GD Library Bar Chart

Published on May 3rd, 2007 by admin

Create a dynamic bar chart with PHP and GD Library.

What you will need

  • A server with php installed and GD Library enabled

The Process

  1. Prepare your php document.
  2. Set up your data.
  3. Create the canvas.
  4. Draw the grid and axis labels.
  5. Draw the bars.
  6. Create the chart labels.
  7. Output the chart.

The Source

Download barchart.php

Part One: Preparing your php document.

Open up your favorite script editor and make a new file. I prefer NotePad++ but any pure text editor will suffice.

Save the file as barchart.php

Part Two: Setting up the data

A bar chart is useless without data so lets make some!

Grab the following code below and paste it into your php file.

//Setting the chart variables
$graphTitle = "Favorite Reptile";
$xLabel 	= "Reptile";
$yLabel 	= "Votes";

$data['Alligator'] = 12;
$data['Crocodile'] = 15;
$data['Iguana']    = 17;
$data['Snake']     = 3;
$data['Turtle']    = 25;
$data['Lizard']    = 3;
$data['Barney']    = 1;

//getting the maximum and minimum values for Y
$newData = $data;
asort($newData);

//minimum
$places = strlen(current($newData));
$mod    = pow(10, $places-1);
$min    = $mod - current($newData);

//maximum
$places = strlen(end($newData));
$mod    = pow(10, $places-1);
$max 	= $mod + end($newData);

$yAxis 	= array("min" => $min, "max" => $max);

The first part is pretty self-explanatory so I will skip that and explain what is going on below that.

Below I’m saving the $data array into a new array because I want to preserve the original values.

Then I sort the array from lowest to highest value.

//getting the maximum and minimum values for Y
$newData = $data;
asort($newData);

Ok, the next part is a little tricky. In a graph it’s always a good idea to have a little space (a buffer) between the top of the graph and the highest value so that the bar doesn’t go directly to the top. Therefore we need to find a maximum value for the Y-Axis that is greater than the highest value of the data.

001

Note the buffer between the bar and the top of the graph.

The same applies for the minimum value, if the lowest value is 2 we would want the graph to start at 0. However, if the minimum value is 200, we may want to start at a higher value.

Take a look below to see my method for finding this buffer

//minimum
$places = strlen(current($newData));	//string length of first element in array. 		  so strlen(1) = 1;
$mod    = pow(10, $places-1); 			//raising that number minus 1 to the power of 10. so pow(10, 0) = 1;
$min    = $mod - current($newData); 	//subtracting that from the minimum. 			  so 1 - 1 = 0; <-your y-axis minimum

//maximum
$places = strlen(end($newData));	    //strlen(25) = 2;
$mod    = pow(10, $places-1);		    //pow(10, 1) = 10;
$max 	= $mod + end($newData); 	 	//10 + 25 = 35; <-- your new y-axis maximum

//storing those min and max values into an array
$yAxis 	= array("min"=>$min, "max"=> $max);

Part Three: Preparing the Canvas.

Ok that wasn’t so bad, now copy the following code and paste it below the previous one.

//------------------------------------------------
// Preparing the Canvas
//------------------------------------------------
//setting the image dimensions
$canvasWidth  = 500;
$canvasHeight = 300;
$perimeter    = 50;

//creating the canvas
$canvas = imagecreatetruecolor($canvasWidth, $canvasHeight);

//allocating the colors
$white     = imagecolorallocate($canvas, 255, 255, 255);
$black     = imagecolorallocate($canvas, 0,0,0);
$yellow    = imagecolorallocate($canvas, 248, 255, 190);
$blue      = imagecolorallocate($canvas, 3,12,94);
$grey      = imagecolorallocate($canvas, 102, 102, 102);
$lightGrey = imagecolorallocate($canvas, 216, 216, 216);

//getting the size of the fonts
$fontwidth  = imagefontwidth(2);
$fontheight = imagefontheight(2);

//filling the canvas with light grey
imagefill($canvas, 0,0, $lightGrey);

Again the code above is pretty self-explanatory.

002
But let me explain what I mean by perimeter.

In a graph you want to have some space to write your labels, therefore it’s necessary to have a perimeter. By setting this value you’re setting how wide you want it to be.

At this point you should have something that looks like this

003

Part Four: Drawing the Grid and Axis Labels

I like to place a grid down on my graphs because it makes building them so much easier. Plus when it comes to testing I have a visual way to tell if the data is being represented accurately.

Copy the following code and paste it below the previous one.

//------------------------------------------------
// Preparing the grid
//------------------------------------------------
//getting the size of the grid
$gridWidth  = $canvasWidth  - ($perimeter*2);
$gridHeight = $canvasHeight - ($perimeter*2);

//getting the grid plane coordinates
$c1 = array("x"=>$perimeter, "y"=>$perimeter);
$c2 = array("x"=>$gridWidth+$perimeter, "y"=>$perimeter);
$c3 = array("x"=>$gridWidth+$perimeter, "y"=>$gridHeight+$perimeter);
$c4 = array("x" => $perimeter, "y" => $gridHeight+$perimeter);

//------------------------------------------------
//creating the grid plane
//------------------------------------------------
imagefilledrectangle($canvas, $c1['x'], $c1['y'], $c3['x'], $c3['y'], $white);

//finding the size of the grid squares
$sqW = $gridWidth/count($data);
$sqH = $gridHeight/$yAxis['max'];

//------------------------------------------------
//drawing the vertical lines and axis values
//------------------------------------------------
$verticalPadding = $sqW/2;
foreach($data as $assoc=>$value)
{
//drawing the line
imageline($canvas, $verticalPadding+$c4['x']+$increment, $c4['y'], $verticalPadding+$c1['x']+$increment, $c1['y'], $black);

//axis values
$wordWidth = strlen($assoc)*$fontwidth;
$xPos = $c4['x']+$increment+$verticalPadding-($wordWidth/2);
ImageString($canvas, 2, $xPos, $c4['y'], $assoc, $black);

$increment += $sqW;
}

//------------------------------------------------
//drawing the horizontel lines and axis labels
//------------------------------------------------
//resetting the increment back to 0
$increment = 0;

for($i=$yAxis['min']; $i<$yAxis['max']; $i++)
{

//main lines

//often the y-values can be in the thousands, if this is the case then we don't want to draw every single
//line so we need to make sure that a line is only drawn every 50 or 100 units.

if($i%$mod==0){
//drawing the line
imageline($canvas, $c4['x'], $c4['y']+$increment, $c3['x'], $c3['y']+$increment, $black);

//axis values
$xPos = $c1['x']-($fontwidth*strlen($i))-5;
ImageString($canvas, 2, $xPos, $c4['y']+$increment-($fontheight/2), $i, $black);

}
//tics
//these are the smaller lines between the longer, main lines.
elseif(($mod/5)>1 &amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp; $i%($mod/5)==0)
{
imageline($canvas, $c4['x'], $c4['y']+$increment, $c4['x']+10, $c4['y']+$increment, $grey);
}
//because these lines begin at the bottom we want to subtract
$increment-=$sqH;
}

Below I’m setting the width and height of the grid, remember that we want the grid to go inside the perimeter.

//getting the size of the grid
$gridWidth  = $canvasWidth  - ($perimeter*2);
$gridHeight = $canvasHeight - ($perimeter*2);

The next part is the most important of the whole project!

I like to assign coordinates to my graph so that I don’t have to constantly remember that the first point lies 30 pixels to the left of the canvas. It just makes graph construction and manipulation much easier.

//getting the grid plane coordinates
$c1 = array("x"=>$perimeter, "y"=>$perimeter);
$c2 = array("x"=>$gridWidth+$perimeter, "y"=>$perimeter);
$c3 = array("x"=>$gridWidth+$perimeter, "y"=>$gridHeight+$perimeter);
$c4 = array("x"=>$perimeter, "y"=>$gridHeight+$perimeter)

004

The imagefilledrectangle() function as you might suspect draws a filled rectangle on the canvas. Take a look at the illustration below to see how it works

imagefilledrectangle($canvas, $c1['x'], $c1['y'], $c3['x'], $c3['y'], $white);

005

A grid as you well know is a collection of squares or rectangles. The height and width of those shapes represents a unit, therefore we have to find the unit for our graph.

	//finding the size of the grid squares
$sqW = $gridWidth/count($data);
$sqH = $gridHeight/$yAxis['max'];

006

Now it’s time to draw the vertical lines and axis labels on our graph!

//------------------------------------------------
//drawing the vertical lines and axis labels
//------------------------------------------------
$verticalPadding = $sqW/2;
foreach($data as $assoc=>$value)
{
//drawing the line
imageline($canvas, $verticalPadding+$c4['x']+$increment, $c4['y'], $verticalPadding+$c1['x']+$increment, $c1['y'], $black);

//axis labels
$wordWidth = strlen($assoc)*$fontwidth;
$xPos = $c4['x']+$increment+$verticalPadding-($wordWidth/2);
ImageString($canvas, 2, $xPos, $c4['y'], $assoc, $black);

$increment += $sqW;
}

It is good technique to have a buffer between the y-axis and the first vertical line or else it would be hard to read. Look below, notice that the one on the right looks much better and will give us nice evenly spaced bars.

$verticalPadding = $sqW/2;

007

I’m going to assume that you have an understanding of loops

The imageline() function looks very complex but just work it out slowly you’ll see that it makes a lot of sense.

//drawing the line
imageline($canvas, $verticalPadding+$c4['x']+$increment, $c4['y'], $verticalPadding+$c1['x']+$increment, $c1['y'], $black)

008

Next we’re going to add the labels for the x-axis.

The labels are going to go on graph from left to right and will be below the grid plane.

	//axis labels
$wordWidth = strlen($assoc)*$fontwidth; 					 //getting the width of the word
$xPos = $c4['x']+$increment+$verticalPadding-($wordWidth/2); //dividing that by 2 to center the word
ImageString($canvas, 2, $xPos, $c4['y'], $assoc, $black);	 //outputting the word on canvas

The lines for y-axis follow a similar method.

//------------------------------------------------
//drawing the horizontal lines and axis labels
//------------------------------------------------
//resetting the increment back to 0
$increment = 0;

for($i=$yAxis['min']; $i<$yAxis['max']; $i++)
{

//main lines

//often the y-values can be in the thousands, if this is the case then we don't want to draw every single
//line so we need to make sure that a line is only drawn every 50 or 100 units.

if($i%$mod==0){
//drawing the line
imageline($canvas, $c4['x'], $c4['y']+$increment, $c3['x'], $c3['y']+$increment, $black);

//axis values
$xPos = $c1['x']-($fontwidth*strlen($i))-5;
ImageString($canvas, 2, $xPos, $c4['y']+$increment-($fontheight/2), $i, $black);

}
//tics
//these are the smaller lines between the longer, main lines.
elseif(($mod/5)>1 &amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp; $i%($mod/5)==0)
{
imageline($canvas, $c4['x'], $c4['y']+$increment, $c4['x']+10, $c4['y']+$increment, $grey);
}
//because these lines begin at the bottom we want to subtract
$increment-=$sqH;
}

Copy the following code and paste it below your previous code. This creates a vertical black line on the left hand side of the graph.

	imageline($canvas, $c1['x'], $c1['y'], $c4['x'], $c4['y'], $black);

Part Five: Drawing the bars

Copy the following code and paste it below your previous code.

	//------------------------------------------------
// Making the vertical bars
//------------------------------------------------
$increment = 0; 		//resetting the increment value
$barWidth = $sqW*.2; 	//setting a width size for the bars, play with this number
foreach($data as $assoc=>$value)
{
$yPos = $c4['y']-($value*$sqH);
$xPos = $c4['x']+$increment+$verticalPadding-($barWidth/2);
imagefilledrectangle($canvas, $xPos, $c4['y'], $xPos+$barWidth, $yPos, $blue);
$increment += $sqW;
}

009
The part that we need to pay attention to here is $yPos, we want the bar to start at the bottom of the graph and then go up the appropriate y-value to make the right height.

Part Six: Making the Graph Labels

Copy and paste :)

//Graph Title
ImageString($canvas, 2, ($canvasWidth/2)-(strlen($graphTitle)*$fontwidth)/2, $c1['y']-($perimeter/2), $graphTitle, $green);

//X-Axis
ImageString($canvas, 2, ($canvasWidth/2)-(strlen($xLabel)*$fontwidth)/2, $c4['y']+($perimeter/2), $xLabel, $green);

//Y-Axis
ImageStringUp($canvas, 2, $c1['x']-$fontheight*3, $canvasHeight/2+(strlen($yLabel)*$fontwidth)/2, $yLabel, $green);

Part Seven: Final Output

Copy. . you know the drill 😉

header("content-type: image/jpg");
imagejpeg($canvas);
imagedestroy($canvas);

Tadaa! A graph!

010

Conclusion

I hope this tutorial has been helpful, if you have any questions or suggestions please feel free to contact me.

Leave a Reply




Comments

  • Post by Luca on July 23, 2007

    Hi there,very good tutorial, thank you for sharing.Though, I have no idea why but I had to correct this line of the code:imagefilledrectangle($canvas, $xPos, $c4['y'], $xPos $barWidth, $yPos, $blue);with this one:imagefilledrectangle($canvas, $xPos, $yPos, $xPos $barWidth, $c4['y'], $blue);in order to make the whole tutorial run.Thanks alot again,Luca

  • Post by sean on December 12, 2007

    Very good tutorial but i had to remove the following code to display this table correctly: $xPos = $c4['x'] $increment $verticalPadding-($wordWidth/2); ImageString($canvas, 2, $xPos, $c4['y'], $assoc, $black); $increment = $sqW;*/

  • Post by Scott Cronk on April 9, 2009

    I have data sets with negative values and positive values and your tutorial code only seems to work for positive values.. negatives are drawn below and outside the canvas. I am planning to decipher your code to develop a fix ... but perhaps you have a quick and easy fix I could use???

  • Post by Anthony on August 12, 2010

    Do you have a tutorial on how to graph data from a database?

  • Post by fsaravia on October 7, 2011

    got some errors! solved by adding: // line 64 $green = imagecolorallocate($canvas, 255, 102, 102); // line 101 $increment = 0;

  • Post by akshay on April 4, 2013

    is there any code available to create the same kind of graph dynamically with values from a database ?

  • Post by Pat on January 18, 2015

    I'd also like to know if you have a tutorial on how to graph data from a database?

Popular Posts

Posts By Category

Supported by