Tuesday, 26 May 2009

Simple pie chart with Gnuplot

Addendum: I have noticed (just by looking at the backtracks of people who come to my blog) that for some reason, google won't tell you that there are recent developments on the pie chart. So, if you are interested, you should look at my post on the 1st Aug, 2009 (where I show how to make the pie chart entirely in gnuplot, without any external scripts), and also 31st May, 2009 (which is the 3D version of the present post.) 19 Aug 2009


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