Monday 25 May 2009

Graphs on a background with gradient

Sometimes one would like to have a graph whose background is not so monotonic. This is especially useful in presentations. There is a relatively easy way to come up with a solution for this. Again, we will use multiplot, and plot the background on plots different to the main plot. First, here is the figure, that we have




and here is the code that produced it
reset
f(x) = exp(-x/10.0)*sin(x)
g(x) = exp(-x/10.0)
h(x) = -exp(-x/10.0)
set sample 30
set table 'test.dat'
plot [0:20] f(x)+(rand(0)-0.5)*0.2
unset table

set sample 100

set multiplot
set palette model RGB functions 0.4+gray/1.667, 0.75+gray/4.0, 0.4+gray/1.667
set pm3d map
set isosample 100,100
set yrange [-1:1]
unset colorbox
unset border
unset xtics
unset ytics
set size 1.5,1.6
set origin -.25,-.3
splot y t ''

set palette model RGB functions 0.9+gray/10.0, 0.5+gray/2.0, 0.5+gray/2.0
set size 1.208, 1.295
set origin -0.065,-0.125
splot [0:20] y  t ''

set size 1,1
set origin 0,0
set xtics
set ytics
set xlabel 'Time [s]'
set ylabel 'Position [m]'
set border 1+2+4+8
set key reverse box

plot [0:20] f(x) w l lt 3 lw 2 t 'y=sin(x)*exp(-x/10) ', \
g(x) w l lt rgb "#008800" t '', h(x) w l lt rgb "#008800" t '', \
'test.dat' u 1:2:($2-rand(0)*0.1-0.05):($2+rand(0)*0.1+0.05) w errorb pt 13 lt 1 t 'Data set 2 '

unset multiplot


Now, let us see what is happening here. The first couple of lines are there just to produce some data (in this case, a damped oscillation with some random noise). The interesting part begins with 'set multiplot': we define a palette, which will run between some shade of green and white. This will be our background for the whole image. It will have a gradient, because we plot the function 'y', so as we go towards the top, the colour becomes whiter and whiter. In order to cover the whole canvas, we have to play with the size a bit, but this should be more or less straightforward.


In the second plot, the only thing that really is different is the colour palette, which, this time, is from some shade of red to white. Again, you might have to set the size of the plot by hand, and this might also depend on the actual terminal that you are using.

In the last part, we set the labels and the border (if you cast a glance at the code, you'll notice that these were switched off at the beginning), and plot our functions and data. Since I wanted to show errorbars, I generated artificial errors with the rand(0) function. If you have a real data set that you want to plot, this should be much simpler. You can skip the first 7 lines, and just use the columns in your data file to show the errors.


There, you have it!

2 comments:

  1. Hi gnuplotter, great blog!
    I am playing with this one right now and used it for a double logarithmic plot. I have to add the logscales at the beginning and change the xrange and yrange early on to make it work (maybe put set xrange + yrange near the top).

    There's quite a bit of fiddling to get the areas to line up, and I can't get rid of thin white borders on the lower right of the plot, where the green does not reach.

    I do not understand the concepts of set size and set origin well enough to make it work. Is there a way to make it exact, and is there a way to coerce the margins set automatically out of gnuplot?

    Or, failing that, set margins (rmargin, lmargin, tmargin, bmargin) manually till a pleasing result is achieved, then store them in variables to make all of this fit into formulas?

    Then this would be a really powerful way to produce lots of nice plots. I'd love to do this, just lack the understanding of how gnuplot fills the canvas.

    Thank you for your generous contribution to the public domain!

    ReplyDelete
  2. Hi Zoltán,

    I just realized I gave my own answer there - the margins are the key to the solution. Here is my version of your script for the public domain - no more fiddling with numbers, all fully automated!
    The trick is to switch things on and off at the right time, so that the graph fills the whole screen for the screen background or only the graph area for the graph background (with overdraw of the labels). The last two plot statements may be rolled into one but I feel it's cleaner to keep them separate.
    PS: All my contributions free to use in your blog and web page!
    ___

    reset
    f(x) = exp(-x/10.0)*sin(x)
    g(x) = exp(-x/10.0)
    h(x) = -exp(-x/10.0)

    xl=0; xh=20; yl=-1; yh=1;
    set xrange [xl:xh]
    set yrange [yl:yh]

    set sample 30
    set table 'test.dat'
    plot f(x)+(rand(0)-0.5)*0.2
    unset table

    set sample 128
    set isosamples 2,128

    set table 'background.dat'
    splot (y-yl)/(yh-yl)
    unset table

    set multiplot

    set rmargin 0
    set lmargin 0
    set tmargin 0
    set bmargin 0

    unset colorbox
    unset border
    unset xtics
    unset ytics

    set palette defined (0 "#68c068", 1 "#ffffff")
    plot 'background.dat' w ima

    set rmargin
    set lmargin
    set tmargin
    set bmargin

    set xtics
    set ytics
    set xlabel 'Time [s]'
    set ylabel 'Position [m]'
    set border 1+2+4+8

    set palette defined (0 "#e68080", 1 "#ffffff")
    plot 'background.dat' w ima

    set key reverse box

    plot f(x) w l lt 3 lw 2 t 'y=sin(x)*exp(-x/10) ', \
    g(x) w l lt rgb "#008800" t '', h(x) w l lt rgb "#008800" t '', \
    'test.dat' u 1:2:($2-rand(0)*0.1-0.05):($2+rand(0)*0.1+0.05) w errorb pt 13 lt 1 t 'Data set 2 '

    unset multiplot

    !/bin/rm -f test.dat background.dat

    ReplyDelete