Addendum 2: Hellson has provided a php variant of the script discussed below. (Thanks a lot for it!) If, for whatever reason, php suits your needs better, than gawk, you should check out his site 21 Aug 2009

Unfortunately, gnuplot hasn't got a built-in function for producing pie charts. This is a type of figure which is not extremely informative, but is quite popular. (At least, this is what I gather from people's asking for it all over the web.) Today, we will try our hands at making one in gnuplot. In gnuplot 4.3, there is a function with which arcs of circles can be drawn. However, this works only on 2D plots, so if you want to have something that looks like a 3D graph, you have got to work a bit harder. Here is the code that I used to generate the figure below.

reset a1=0.1 a2=0.2 a3=0.15 a4=0.15 a5=0.3 a6=0.1 b=0.4 s=0.2 B=0.5 set view 30, 20 set parametric unset border unset tics unset key set ticslevel 0 unset colorbox set urange [0:1] set vrange [0:1] set xrange [-2:2] set yrange [-2:2] set zrange [0:3] set multiplot # First, we draw the 'box' around the plotting volume set palette model RGB functions 0.9, 0.9,0.95 splot -2+4*u, -2+4*v, 0 w pm3d set palette model RGB functions 0.8, 0.8, 0.85 set urange [a1:1] splot cos(u*2*pi)*v, sin(u*2*pi)*v, 0 w pm3d set urange [0:a1] splot cos(a1*pi)*b+cos(u*2*pi)*v, sin(a1*pi)*b+sin(u*2*pi)*v, 0 w pm3d set palette model RGB functions 1, 0, 0 set urange [0:a1] splot cos(a1*pi)*b+cos(u*2*pi)*v, sin(a1*pi)*b+sin(u*2*pi)*v, s w pm3d set palette model RGB functions 0, 0.5, 0 set urange [a1:a1+a2] splot cos(u*2*pi)*v, sin(u*2*pi)*v, s w pm3d set palette model RGB functions 0, 0, 0.8 set urange [a1+a2:a1+a2+a3] splot cos(u*2*pi)*v, sin(u*2*pi)*v, s w pm3d set palette model RGB functions 0.8, 0, 0.8 set urange [a1+a2+a3:a1+a2+a3+a4] splot cos(u*2*pi)*v, sin(u*2*pi)*v, s w pm3d set palette model RGB functions 0.8, 0.8, 0 set urange [a1+a2+a3+a4:a1+a2+a3+a4+a5] splot cos(u*2*pi)*v, sin(u*2*pi)*v, s w pm3d set palette model RGB functions 0, 0.8, 0.8 set urange [a1+a2+a3+a4+a5:a1+a2+a3+a4+a5+a6] set label 1 '1988' at cos(a1*pi)*B+cos(a1*pi), sin(a1*pi)*B+sin(a1*pi) D = 2*a1+a2 set label 2 '1989' at cos(D*pi)*B+cos(D*pi), sin(D*pi)*B+sin(D*pi) D=D+a2+a3 set label 3 '1990' at cos(D*pi)*B+cos(D*pi), sin(D*pi)*B+sin(D*pi) D=D+a3+a4 set label 4 '1991' at cos(D*pi)*B+cos(D*pi), sin(D*pi)*B+sin(D*pi) D=D+a4+a5 set label 5 '1992' at cos(D*pi)*B+cos(D*pi), sin(D*pi)*B+sin(D*pi) D=D+a5+a6 set label 6 '1993' at cos(D*pi)*B+cos(D*pi), sin(D*pi)*B+sin(D*pi) splot cos(u*2*pi)*v, sin(u*2*pi)*v, s w pm3d unset multiplot

The values in the chart are defined in a1 through a6. (I made sure that they add up to one, so it is easier to work with them.) Then, we set up our figure in the usual way, and first we plot the plane and the shadow of the slices. In order to draw slices, we use a simple parametrisation of an arc of a circle, and shift the boundaries of the 'u' parameter. Note that one of the slices is off set, so it looks as if the pie chart had exploded. The extent to which the single slice is moved out is given by the value of 'b', while 'B' sets the distance of the labels from the centre.

Once we are done with this, we can set out to draw the actual slices. In order to colour them with a different colour, we change the palette as we proceed, and change the parameter range of 'u'. Before the last slice, we put out the labels as well, so that they will be displayed when the last piece is drawn.

Now, this seems to be a bit convoluted, and more importantly, it's quite inconvenient to put all values in by hand. So, what about a simple script to produce the gnu script? One possible implementation in gawk is given here.

#!/bin/bash gawk 'BEGIN {i=0} { if($0!~/#/) { label[i] = $1 v[i] = $2 D+= $2 i++ } } END { print "reset" print "b=0.4; a=0.2; B=0.5" print "set view 30, 20; set parametric" print "unset border; unset tics; unset key; unset colorbox" print "set ticslevel 0" print "set urange [0:1]; set vrange [0:1]" print "set xrange [-2:2]; set yrange [-2:2]; set zrange [0:3]" print "set multiplot" print "set palette model RGB functions 0.9, 0.9,0.95" print "splot -2+4*u, -2+4*v, 0 w pm3d" print "set palette model RGB functions 0.8, 0.8, 0.85" printf "set urange [%f:1]\n", v[0]/D print "splot cos(u*2*pi)*v, sin(u*2*pi)*v, 0 w pm3d" printf "set urange [0:%f]\n", v[0]/D printf "splot cos(%f*pi)*b+cos(u*2*pi)*v, sin(%f*pi)*b+sin(u*2*pi)*v, 0 w pm3d\n", v[0]/D, v[0]/D print "set palette model RGB functions 1, 0, 0" printf "set urange [0:%f]\n", v[0]/D printf "splot cos(%f*pi)*b+cos(u*2*pi)*v, sin(%f*pi)*b+sin(u*2*pi)*v, a w pm3d\n", v[0]/D, v[0]/D d=v[0]/D for(j=0;j<i-1;j++) { printf "set palette model RGB functions %f, %f, %f\n", (j%3+1)/3, (j%6+1)/6, (j%9+1)/9 printf "set urange [%f:%f]\n", d, d+v[j]/D print "splot cos(u*2*pi)*v, sin(u*2*pi)*v, a w pm3d" d+=v[j]/D } d=v[0]/D for(j=0;j<i-1;j++) { printf "set label %d \"%s\" at cos(%f*pi)*B+cos(%f*pi), sin(%f*pi)*B+sin(%f*pi)\n", j+1, label[j], d, d, d, d d=d+v[j]/D+v[j+1]/D } printf "set label %d \"%s\" at cos(%f*pi)*B+cos(%f*pi), sin(%f*pi)*B+sin(%f*pi)\n", i, label[i-1], d, d, d, d printf "set palette model RGB functions %f, %f, %f\n", (i%3+1)/3, (i%6+1)/6, (i%9+1)/9 printf "set urange [%f:1]\n", 1.0-v[i-1]/D print "splot cos(u*2*pi)*v, sin(u*2*pi)*v, a w pm3d" print "unset multiplot" }' $1

This is really nothing but the mechanical implementation of our gnuplot script. The only difference with respect to that is that we had to set the colour palette mechanically, which I did by giving the values (j%3+1)/3, (j%6+1)/6, (j%9+1)/9. If you are not satisfied with the colouring of your output, you can easily tamper with this, and get something that you like more.

Now, if you make this executable and call it, pie.sh, say, and have a file with two columns, the first one being the label for a particular value, then you can simple call this script from gnuplot as

gnuplot> load "< ./pie.sh pie.dat"

Given the input file, pie.dat,

# This is a simple data file to test our script # Note that the second column doesn't add up to 1. # But this is not a problem, for the script normalises that:) 1989 0.1 1990 0.2 1991 0.2 1992 0.05 1992 0.15 1993 0.3 1994 0.1

I get this figure, which is quite OK, as far as the colouring is concerned.

## No comments:

## Post a Comment