Friday 7 August 2009

Ribbon charts - without the gawk script

Yesterday, we saw how we can produce a ribbon chart from an arbitrary data file, and with the help of an external script. You can still make it work under windows, although you might have to call the script outside gnuplot. Probably, it would be better to do everything in gnuplot, wouldn't it? So, can we do something to alleviate the situation. But, of course, we can, we just have got to use those little grey cells! If you are patient and read further, I will explain how you can draw this graph completely automatically! (Uhm, this is rather similar to that from yesterday... Never mind, the point is that you haven't got to do any work!)



If you recall, the key to plotting the ribbons was to convert the original data file (see the beginning of my previous post) into something like this:
0 0 0.857354
1 0 0.857354

0 1 0.551386
1 1 0.551386

0 2 0.243002
1 2 0.243002

0 3 -0.24
1 3 -0.24

0 4 -0.422674
1 4 -0.422674
...

i.e., we need two rows of three columns, separated by a linefeed. We will need some data processing for this, but we can manage. First, we will duplicate all columns, simply plotting into a file. By issuing
set table 'rib1.dat'
plot 'ribbon.dat' u 1:1
unset table

we get the following file, 'rib1.dat'
#Curve 0 of 1, 14 points
#x y type
0.857354  0.857354  i
0.551386  0.551386  i
0.243002  0.243002  i
-0.24 -0.24  i
-0.422674 -0.422674  i
-0.513352 -0.513352  i
-0.660823 -0.660823  i
-0.0962106 -0.0962106  i
-0.0152513 -0.0152513  i
0.489453  0.489453  i
0.876023  0.876023  i
0.945061  0.945061  i
0.860648  0.860648  i
0.901743  0.901743  i

This is almost what we want, two columns of the same numbers, namely those from the first column of 'ribbon.dat'. The only difficulty is that it contains a third column, which in this case is just a set of i, but if we were to plot this file as a matrix, at x=2 all values would be equal to zero, so it would be a distorted ribbon. How can we get rid of that letter? Well, we will turn the into a form similar to that at the beginning of this post, simply by
set table 'rib2.dat'
splot 'rib.dat' mat
unset table

where now 'rib2.dat' looks like this
#Surface 0 of 1 surfaces

#IsoCurve 0, 3 points
#x y z type
0  13  0.901743 i
1  13  0.901743 i
2  13  0 i

#IsoCurve 1, 3 points
#x y z type
0  12  0.860648 i
1  12  0.860648 i
2  12  0 i
...

which is very similar to the desired format, for now we can simply call an splot, without the matrix specifier. But we still have an erroneous value in every third line. We will remove that using the 'every' specifier of plot. If you haven't done it yet, you should definitely issue the command
?every

You will learn a lot of interesting things. What we want to do here is to plot only the first end second record in each block. In that case, it does not matter what is in the third record, because it will not be processed by gnuplot. So, we take our 'rib2.dat' file, and plot it as
splot 'rib2.dat' every ::0::1 u 1:2:3 w pm3d

which returns the first (0) and second (1) column in each block. Thus, with these three easy steps, we created a ribbon, which happens to represent the first column in our original data file. All that is left is to walk through the columns in 'ribbon.dat', and do the same thing again and again. Note that we specified the columns that we are going to use as 1:2:3. We will need this later, when we shift the next ribbon to a new position.

Then, let us suppose that we are a bit lazy, and we do not fancy following the prescription above. We can then resort to the recipe outlined a couple of days ago in connection with the pie charts and the bar graphs. If you haven't read those posts, you should now, for I am going to use everything mentioned in them.

Since the three steps above are repetitious, we will put them in a 'for' loop. As I discussed it earlier, the way to do this is to write the instructions in a separate file, and 'reread' them as many times as necessary. I.e., we will have a file, 'ribbon_r.gnu', which contains the following lines
A=A+1
set table 'rib.dat'
plot 'ribbon.dat' u 1:1
unset table

set table 'rib2.dat'
splot 'rib.dat' mat
unset table

r=rand(0); g=rand(0); b=rand(0)
set palette model RGB defined (0 r/cm g/cm b/cm, 1 r g b)
splot 'rib2.dat' every ::0::1 u (A-1+B*$1):2:3 w pm3d
if(A<C) reread

So, this is our 'for' loop, and this is where we call it, 'ribbon.gnu'

reset
filename="ribbon.dat"
mult=1.2; cm=2.5
A=0; B=0.3;
set xlabel 'x axis [a.u.]'; set ylabel 'y axis [a.u.]';
set ticslevel 0
unset key; unset colorbox
set tics out nomirror
set border 1+2+4+8+16+32+64+256+512 back
mini(x)=(x<0 mult:x="" mult="" x="">0?x*mult:x/mult)

set isosample 100, 3
set xrange [0:1]; set yrange [0:1]
set table 'bg.dat'
splot x
unset table; set xrange [*:*]; set yrange [*:*]

splot filename mat
C=GPVAL_DATA_X_MAX+1
ymax = GPVAL_DATA_Y_MAX+1
zmin = mini(GPVAL_DATA_Z_MIN)
zmax = maxi(GPVAL_DATA_Z_MAX)
set xrange [-0.5:C-0.5]
set yrange [0:ymax]
set zrange [zmin:zmax]
set cbrange [0:1]

set multiplot
set palette model RGB defined (0 0.3 0.3 0.85, 1 0.9 0.9 0.95)
splot 'bg.dat' u ($1*C-0.5):($2*ymax):(zmin):3 w pm3d, \
'' u ($1*C-0.5):(ymax):(1.9999*$2*(zmax-zmin)+zmin):3 w pm3d, \
'' u (-0.5):($1*ymax):(1.9999*$2*(zmax-zmin)+zmin):(0) w pm3d
set cbrange [zmin:zmax]

unset border; unset tics; unset xlabel; unset ylabel; unset zlabel
l 'ribbon_r.gnu'
unset multiplot

This looks formidable at first, but we can easily decipher all. First, in our 'for' loop, in 'ribbon_r.gnu', we simply wrote down the three steps required to created one ribbon, we re-set the colour palette, and call the loop as many times as many columns there are (C).

In the main script, in 'ribbon.gnu', we first set up the main properties of the figure, and we define the width (B) of the ribbons, the multiplier (mult), which determines by how much the figure is bigger, than the minimum and maximum of the data points in 'ribbon.dat', and we also define 'cm', which will determine how "deep" the colour modulation of the ribbons is. By setting this to a number close to 1, we get a more or less homogeneous colour, while setting it to something large, we get a wildly modulated colour palette for the ribbons. Note the two helper function, 'mini' and 'maxi', which are used to set the zrange, and which make use of the value of 'mult'. The next couple of lines produces the background, which you can skip, if you do not want a very fancy graph. Then we make a dummy plot, just to determine the various ranges. You can read about this in my last but one post. Immediately after the multiplot, we plot 'bg.dat', i.e., the background of the figure. After this we call 'ribbon_r.gnu', and finally, escape from the multiplot.

A couple of notes: in the 'for' loop, we generated the colours by picking three random numbers. This means that your plot will have different colours after successive calls of 'ribbon.gnu'. You can change this, if you want to have some definite colouring scheme.

As I have already pointed out, the colour modulation of the ribbons is given by the variable 'cm', at the beginning of 'ribbon.gnu', while the size of the figure with respect to the range of the values in 'ribbon.dat' is given by 'mult'. If you set it to something smaller, than 1, be prepared for some clipping of the data!

Finally, these two scripts will produce the graphs automatically for you, the only thing you have to set is the name of the file, and, of course, you have to have the data in the format given at the very beginning of my previous post, i.e., the data points must be arranged in a matrix.

Tomorrow (or whenever I have time), I will show what else this script can be used for, with some small modification. So long!

7 comments:

  1. My ultimate goal is a wall chart, but when attempting the ribbon first, I get the following errors using CentOS gnuplot-4.0.0-14.el5:

    gnuplot> set tics out nomirror
    ^
    ';' expected
    gnuplot> set border 1+2+4+8+16+32+64+256+512 back ^
    ';' expected
    gnuplot> set table 'bg.dat'
    ^
    valid set options: [] = choose one, {} means optional
    'angles', 'arrow', 'autoscale', 'bars', 'border', 'boxwidth',

    ....
    ... and so on...
    Is my version of gnuplot not compatable with your methods?

    ReplyDelete
  2. Ok, I compiled/installed 4.2 on CentOS and completed the ribbon graph posted on 6th August using the shell script. Now as I attempt the 7th August plot, I'm running into what looks like a typo on your part. In the post, you state:

    ---
    set table 'rib1.dat'
    plot 'ribbon.dat' u 1:1
    unset table

    we get the following file, 'rib.dat'
    ---
    No. We get the file rib1.dat. Not a big deal right? I correct the naming of the file in the next step, but get the following error...
    --
    set table 'rib2.dat'
    splot 'rib1.dat' mat
    ...... Bad number in matrix
    ---
    So... I am stuck. Making the filename corrections in your provided gnu loop doesn't help, as I realize the naming of the file is irrelavant. Just doesn't seem like I can splot a file with i's in it.

    ReplyDelete
  3. Looks like replacing all i's with 0's in rib.dat got me through all steps upto:
    ----
    where now 'rib2.dat' looks like this
    ----
    So that I can proceed all the way to:
    ----
    splot 'rib2.dat' every ::0::1 u 1:2:3 w pm3d
    ----
    So I'm happy except that it looks like I'll have to stick with a method outside of gnuplot to loop through my ribbons. Also, I'm going to have to proceed with the next wall lesson without a loop and see if I can decipher how to do the "two line" adjustment without your gnuplot loop.

    ReplyDelete
  4. Dear Gnuploter,

    I would like to ask you something about pm3d and map.
    I have the file test.dat which contains data in the form:

    0 0 0
    0 1 0
    0 0 0

    Do you maybe know if i can define the size for a box for each element, in order to have a representation of the matrix. The problem is that the unit in my matrix overlaped by zeros.

    thanks in advance
    Nikos

    ReplyDelete
  5. Hi Michael,

    Sorry, I was away for a few days. What you describe might be a problem with the version of gnuplot that you have. Mine is 4.2.4, and I am running it on Linux/Fedora. Perhaps, if you posted a segment of the faulting data file, we could try to work something out.
    Cheers,
    Zoltán

    ReplyDelete
  6. Hi Nikos,

    I am not sure that I have understood your question. Is the problem that you want to plot only the 1, but not the zeroes, or something else? Is this test.dat is generated by one of the scripts that I described here, or is it your own data file?
    Cheers,
    Zoltán

    ReplyDelete
  7. consider that a have a file with data in the matrix form below:

    0 1 2
    3 4 5
    6 7 8

    when i write:

    set pm3d map
    splot "test.dat" matrix

    i take a snapshot with 4 colors.

    In fact what i want is to put a different color for each different number.
    Can you maybe help me?

    ReplyDelete