
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
A bar chart is useless without data so lets make some!
//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. |
![]() |
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, it may not be a good idea to start at 0.
Take a look below to see my method to find 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);
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.
![]() |
But let me explain what I mean by perimeter. In a graph you want to have some space to write your labels and such so 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
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 accuratly.
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 && $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)

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);

A grid as you well know is a collection of squares or rectangles. The height and width of those shapes is representational of 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'];

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;

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)

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 && $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);
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; }
![]() |
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. |
Copy the following code and paste it below your previous code.
//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);
Copy the following code and paste it below your previous code.
header("content-type: image/jpg"); imagejpeg($canvas); imagedestroy($canvas);
Tadaa! you have a graph!
I hope this tutorial has been helpful, if you have any questions or suggestions please feel free to contact me.