Sunday, 7 June 2009

Wall charts with gnuplot

Today we will discuss how to make a wall chart with gnuplot. There is a simpler version of this, the so-called fence plot, that you can find on gnuplot's surface demo page, and we will build on this. By the end of our adventure, we will have produced this graph:



So, let us see what is to be done. First, I will just give the gnu script, and then discuss segments of it.
reset

A = 4
B = 3
C = 1
unset key
unset colorbox
f(x,y) = abs(sin(x*x+y*y)/(x*x+y*y)) # We plot this function
set isosample 2, 30
set parametric
set urange [-B:B]
set vrange [0:1]
set xrange [-A:A]
set yrange [-B:B]
set zrange [0:C]
set ticslevel 0 # We need this, in order to shift the 0 of the z axis

dx = 0.3 # Thickness of the walls

set multiplot
set border 1+2+4+8+16+32+64+256+512
# Plot the "background" first
set palette model RGB functions 0.9, 0.9,0.95
splot -A+2*A*v, B*u,0 w pm3d

unset border; unset xtics; unset ytics; unset ztics
set palette model RGB functions 1, 254.0/255.0, 189.0/255.0
splot -A, B*u, C*v w pm3d, A*u, B, C*v w pm3d

x0 = -A+1
y0 = 0.0
set palette model RGB functions 0, gray/2+0.5, 0.0
splot x0-dx, u, f(u,y0) w l lt -1 lw 0.2, \
x0-dx*v, u, f(u,y0) w pm3d,\
x0, u, f(u,y0)*v with pm3d, \
x0, u, f(u,y0) w l lt -1 lw 0.2

x0 = x0+1
y0 = y0+0.5
set palette model RGB functions gray/2+0.5, 0.0, 0.0
splot x0-dx, u, f(u,y0) w l lt -1 lw 0.2, \
x0-dx*v, u, f(u,y0) w pm3d,\
x0, u, f(u,y0)*v with pm3d, \
x0, u, f(u,y0) w l lt -1 lw 0.2

x0 = x0+1
y0 = y0+0.5
set palette model RGB functions 0, 0, gray/2+0.5
splot x0-dx, u, f(u,y0) w l lt -1 lw 0.2, \
x0-dx*v, u, f(u,y0) w pm3d,\
x0, u, f(u,y0)*v with pm3d, \
x0, u, f(u,y0) w l lt -1 lw 0.2

x0 = x0+1
y0 = y0+0.5
set palette model RGB functions gray/2+0.5, gray/2+0.5, 0
splot x0-dx, u, f(u,y0) w l lt -1 lw 0.2, \
x0-dx*v, u, f(u,y0) w pm3d,\
x0, u, f(u,y0)*v with pm3d, \
x0, u, f(u,y0) w l lt -1 lw 0.2

x0 = x0+1
y0 = y0+0.5
set palette model RGB functions gray/2+0.5, 0, gray/2+0.5
splot x0-dx, u, f(u,y0) w l lt -1 lw 0.2, \
x0-dx*v, u, f(u,y0) w pm3d,\
x0, u, f(u,y0)*v with pm3d, \
x0, u, f(u,y0) w l lt -1 lw 0.2

x0 = x0+1
y0 = y0+0.5
set palette model RGB functions 0, gray/2+0.5, gray/2+0.5
splot x0-dx, u, f(u,y0) w l lt -1 lw 0.2, \
x0-dx*v, u, f(u,y0) w pm3d,\
x0, u, f(u,y0)*v with pm3d, \
x0, u, f(u,y0) w l lt -1 lw 0.2

x0 = x0+1
y0 = y0+0.5
set palette model RGB functions gray/3+0.3, 0, 0
splot x0-dx, u, f(u,y0) w l lt -1 lw 0.2, \
x0-dx*v, u, f(u,y0) w pm3d,\
x0, u, f(u,y0)*v with pm3d, \
x0, u, f(u,y0) w l lt -1 lw 0.2
unset multiplot


In the first part, we set up the plotting ranges and the function that we want to plot. Note that in order to shift the 0 of the z axis, we have explicitly got to call 'set ticslevel 0'. We can also notice that in the graph above, the top surface is invariant under translations along the x axis, therefore, we can reduce the sampling frequency in that direction. This shouldn't matter, if you make a bitmap file, but it is going to save you a lot of space, if you produce a vector output, e.g., eps or svg.

Having finished the set-up, we plot the background, i.e., we will just plot three planes, the x-y (this one in gray), the y-z, and the x-z. These latter ones are in yellow. We set the colours in the colour scheme of the appropriate plots, by calling 'set palette model RGB functions 0.9, 0.9,0.95', which produces a shade of gray with a bluish tinge. Also note that we unset the border, and the tics immediately after the first plot. The reason for this is that in this way, we can avoid having gnuplot plot the axes and the tics more than once. By the way, before the first plot, we set the border as 'set border 1+2+4+8+16+32+64+256+512', which draws the frame along all, but the three front edges. You can learn how to set the border by reading the output of the command
?border


After having plotted the 'background' of the graph, we plot the first wall. In order to give it some 3D lookout, we have got to plot actually 4 different things: the vertical wall facing us, the top of the body, and the two relevant edges. The first two plots are surfaces, while the latter two are lines, so we call appropriate modifiers to splot, namely, 'with pm3d' and 'with lines'. We have also got to specify the colour of the walls, which we did by issuing 'set palette model RGB functions 0, gray/2+0.5, 0.0' before the first plot. The rest of the script is nothing but the repetition of these seven lines. Letting x0 = x0 + 1, we move the walls along the x axis, while letting y0 = y0 + 0.5, we plot a new function each time. Since we want each wall to have a different colour, we also need to change the palette in each step.

There are two remarks that we can make. The first is that the order of plotting the wall, the top and the two edges depends on the view, so don't be surprised, if you rotate the figure and all of a sudden, it looks messy! The second comment is that you can easily 'close' the graphs, by adding one parametric plot to each of the walls, which would be something like this:
x0-dx*v, -B, f(x0,-B)*(B+u)/(2*B) w pm3d


This is it for today!

2 comments:

  1. Gnuplotter:

    Thanks for the post on "wall charts." I'm trying to use gnuplot to do a very similar thing but with data from a file instead of the parametric formula data. I'm fairly experienced with gnuplot, but can't seem to make it work. I can do an splot with
    hidden3d set, but gnuplot connects all the points in a grid, so you don't get the waterfall effect.

    Any tips on doing your wall-chart style with a data-file input?

    Thanks,

    Chad

    ReplyDelete
  2. Greetings Chad,

    Many thanks for visiting! I have discussed at great length what you want to do here
    This method doesn't actually require any external scripts, so you should be able to run it on any operating system. I hope this helps.
    Cheers,
    Gnuplotter

    ReplyDelete