Image Output - Pie

A nice way to introduce complex programming and algorithms into your work is by drawing graphs and charts from data provided by the user or stored in files/databases on the server.

This example looks at producing a pie chart from a set of values.

header("Content-Type: image/png");
$im = @imagecreate(600, 400);
// data, labels and colours
$dataitems = array(37, 100, 82, 93);
$datalabels = array('Cheese', 'Hamster', 'Geography', 'Life');
// define black for outlining and text
$black = imagecolorallocate($im, 0, 0, 0);
// white for background
$white = imagecolorallocate($im, 255,255,255);
// make an array of usable colours
$grey = imagecolorallocate($im, 0xC0, 0xC0, 0xC0);
$navy = imagecolorallocate($im, 0x00, 0x00, 0x80);
$red = imagecolorallocate($im, 0xFF, 0x00, 0x00);
$green = imagecolorallocate($im, 0x00, 0xFF, 0x00);
$usablecols = array($grey, $navy, $red, $green);


// work out angles for each segment and add % to data labels
$total = array_sum($dataitems);
$angles = array();
for ($i=0;$i<$numitems;$i++)
   $angles[$i] = $dataitems[$i]/$total*360;
   $pcent = round($dataitems[$i]/$total*100,1);
   $datalabels[$i] = $datalabels[$i]." ".$pcent."%";

// fill image white
imagefilledrectangle($im, 0,0,599, 399, $white);
$lastangle = 0;

//draw segments
for ($i=0;$i<$numitems;$i++)
   imagefilledarc($im,199,199,390,390, $lastangle,$lastangle+ $angles[$i], $usablecols[$i], IMG_ARC_PIE);
   $lastangle = $lastangle+ $angles[$i];

// circle outline in black
imageellipse($im,199,199, 390,390, $black);

// create key
for ($i=0;$i<$numitems;$i++)
   imagefilledrectangle($im, 420, 10 + ($i*30), 435,25 + ($i*30), $usablecols[$i]);
   imagerectangle($im, 420, 10 + ($i*30), 435,25 + ($i*30), $black);
   imagestring($im, 5,450,10 + ($i*30),$datalabels[$i], $black);


Although our pie chart script works fine as is, there are a couple of things to think about carefully.

  • The data items, their labels and the colours to be used with them are all hard-coded into the script. It would be much better to have the script take the information from another source (eg user input or a file/database on the server).
  • To make this script a little simpler, the colour array has been made quite clumsily. Either there is a need for a better method of passing a list (of unspecified length) of colours to the script or you should predefine enough colours to cover most scenarios. A pie chart with say, 8 items, is always going to be crowded - that seems like a sensible cut-off point.
  • I allowed a small amount of extra width for the key. The smallest drawing font is being used and my current labels fit the space. More work is likely to be needed if data labels are too much longer than the current ones.

Other considerations about graphs in general.

  • There are some graphing and charting libraries that can be used. There is one that is compatible with the GD library. It's relatively easy to add these items to your own W/LAMP server installation - not so easy if you are using an environment over which you have no control. It's also not as useful to A level projects as when you do all of the work yourself.
  • Pie charts show how each data item relates to the whole. The information they show is all about proportion. With lots of data items (eg 12 months of rainfall data), you may find that a chart showing totals is better. Bar/Column graphs and line graphs are pretty good for this.
  • When the number of items to be displayed in a column graph is not known at design time (because the user or other modules in the program can cause it to vary), you may need to consider scaling. This is not as hard as it sounds. To get the width of a column, divide the available width by the number of items you want to display. For the height, you need the range of values (or if negative values or not possible), the maximum value. The available height divided by the range gives you the information you need to scale the heights.
  • Some graphs need axes with major/minor ticks as well as some labels. This means drawing some straight lines at fixed points and then drawing lots of small horizontal/vertical lines across the axes. Loops are your friend here.