Saturday, 13 June 2009

3D bargraphs in gnuplot, one more time

Some time ago, on 25th May, we discussed how we can draw bargraphs based on cylinders. What was good about them is that we gave the graph a 3D look by adding phong to the surface. The downside is that cylinders are not the conventional shapes to draw something like this. (As a matter of fact, there is one exception: when one wants to draw a bargraph in 2D, but give it a phong on the 2D surface, which gives the impression that what we are looking at is the projection of a cylinder. I will come to this point on a later date.) Instead, people plot a rectangular cuboid. Today we will try our hands at that. At the end of the day, we will have the following graph:

First, let us see how we create the figure above. The gnu script for drawing one cuboid is as follows:
set multiplot
set palette defined (0 1 0.5 0.5, 1 1 0.5 0.5)
splot u, v, B w pm3d

set palette defined (0 1 0.3 0.3, 1 1 0.3 0.3)
splot A+u, 0, v w pm3d

set palette defined (0 0.8 0 0, 1 0.8 0 0)
splot A+A, u, B*v w pm3d

unset multiplot

First, we define our palette. This should have only one colour per face, because we do not want to add any gradient, phong etc. (If you insist, you can add that very easily.) Then we plot the top of the cuboid, at a z-level of B, and shifted horizontally by A. In the next step, we re-define our palette, which will now have a slightly darker shade of red, and plot the front surface. In the final step, we move to the third visible face, make it darker, and plot it. In this way, we have drawn one cuboid. The rest is nothing but the repetition of these three steps, and the general set-up of the graph. Obviously, by changing the order of the palette definitions, one can change the direction of the lighting.

Instead of copying the complete gnu script here, I will just give the gawk script, which processes a file of 2 columns, the first being the label of the bars, and the second containing the actual values. As usual, you can call the script from gnuplot without writing the file to disc as
load "< my_data_file.dat"

So, this is what we have:

gawk  'BEGIN {i=0; max=0}
  if($0!~/#/) {
   label[i] = $1
   v[i] = $2
   if(max<v[i]) max=v[i];
 END {
  print "reset"
  print "set view 60, 20; set parametric; set isosample 2, 2"
  print "unset key; unset colorbox"
  print "set ticslevel 0"
  print "set urange [0:0.5]; set vrange [0:1]"
  printf "set xrange [0:%d]; set yrange [-%f:%f]; set zrange [0:%f]\n", i, i/2, i/2, max
  print "set multiplot"
  print "set border 1+2+4+8+16+32+64+256+512; unset ytics; unset xtics"
  print "set palette model RGB functions 0.9, 0.9,0.95"
  printf "splot %d*u, -%f+%d*v, 0 w pm3d\n", 2*i, i/2, i
  print "unset border; unset xtics; unset ytics; unset ztics"
  print "set palette model RGB functions 1, 254.0/255.0, 189.0/255.0"
  printf "splot 0, -%f+%d*v, %f*u w pm3d, %d*u, %f, %f*v w pm3d\n", i/2, i, 2*max, 2*i, i/2, max

  print "set palette defined (0 1 0.5 0.5, 1 1 0.5 0.5)"
  printf "splot "
  for(j=0;j<i-1;j++) {
   printf "%d+u, v, %f w pm3d,\\\n", j, v[j]
  if(i>1) printf "%d+u, v, %f w pm3d\n", i-1, v[i-1]
  print "set palette defined (0 1 0.3 0.3, 1 1 0.3 0.3)"
  printf "splot "
  for(j=0;j<i-1;j++) {
   printf "%d+0.5, 2*u, v*%f w pm3d,\\\n", j, v[j]
  if(i>1) printf "%d+0.5, 2*u, v*%f w pm3d\n", i-1, v[i-1]
  print "set palette defined (0 0.8 0 0, 1 0.8 0 0)"
  for(j=0;j<i;j++) {
   printf "set label %d \"%s\" at %f, %f rotate by 40\n", j+1, label[j], j+0.3, -i/2+1
  printf "splot "
  for(j=0;j<i-1;j++) {
   printf "%d+u, 0, v*%f w pm3d,\\\n", j, v[j]
  if(i>1) printf "%d+u, 0, v*%f w pm3d\n", i-1, v[i-1]
  print "unset multiplot"
 }' $1

The generalisation to more than 1 data column should be trivial: you have only got to choose your colours, and re-size the bars in the x-y directions accordingly.

No comments:

Post a Comment