Dynamic Graphs with PHP is a tutorial that will
show you how to use the data recorded on a site, and transform some of
it into some eye pleasing graphs. Great if you need to show them off to
more then yourself.
Introduction
Dynamic Graphs with PHP, MySQL and GD
Ok. Your site has recorded the data you want, now you want to display
it in an easy to read format. The first method that comes to mind is
simply to put the data in an HTML table. Although this is probably the
easiest way out, there is a much better way of displaying your
information: a graph. This was originally only possible by using sneaky
tables with 's
of different lengths. But now, thanks to the GD library and PHP, you
can actually have a PNG or JPG image generated dynamically from data in
a MySQL database. This article will help you start out in dynamic image
generation.
Requirements
The technical requirements for this article are listed below:
- PHP Scripting language (obviously): Without this language, this
article is absolutely useless. If you don't have it, stop reading and
get it now!
- MySQL Server: For data storage. Any other SQL (Oracle, MSQL, etc.)
would be fine, this is just my personal preference. The queries in this
article were written for MySQL, however, and to use another SQL would
mean you would have to translate them.
- GDLib: An extension to PHP that offers image manipulation capabilities. It can be found at http://www.boutel.com/gd. Installation of this extension is unique to each environment that it is being set up in, and will not be covered.
- Any paint program: To draw the base image for the graph (there is not artistic talent required, don't worry).
Once you have all of these set up and running, you are ready to start coding.
Basic Image Dynamics
Before we jump into content driven graphs, lets try some simple image
manipulation. Create a new php file and name it image.php. You can
check on your progress at anytime by entering the php file as a URL in
your browser (ex: http://127.0.0.1/image.php) This file is going to be
the image. I can already hear people saying "But its just text! How can
it be a picture?" Its all in the first line of code:
header ("Content-type: image/png");
This tells the browser that this file is, in fact, an image (as
compared to a "text/html" document). This line has to be present in
every image generated by PHP/GD, and it should be as is, although the
"image/png" can be changed to "image/jpeg" if you want (I encourage
using PNG's, however, as their quality is superior to JPEG's). Now the
next line:
$im = imagecreate (300, 300);
?>
imagecreate is a new function that is only
available with GDLib. It creates a blank image with the specified
dimensions. Now, we need to allocate some colors that were going to use
in the image. To do this we use the imagecolorallocate function:
$blue = imagecolorallocate ($im,0,0,255);
$im was used as reference to which image
the color will be allocated to (you can work with more than one image
at a time). Most image functions require you to specify which image you
are operating on. The three integers that follow are the color code in
RGB (NOT hexadecimal). Interestingly enough, and this is something I
haven't read anywhere, the first color you allocate becomes the
background. If no colors are allocated, then the image takes on a black
background. So far, our 300x300 image has a blue background. Put
another imagecolorallocate function
before it allocating white (255,255,255) so that you get a nice subtle
white background. Lets take a look at our code so far.
header ("Content-type: image/png");
$im = imagecreate (300, 300);
$white = imagecolorallocate ($im,255,255,255);
$blue = imagecolorallocate ($im,0,0,255);
?>
Now you have a blank white image that is 300x300 pixels in size. Lets
do something with it. Lets tell the world how much we love GDLib. Enter
this under what you already have:
imagestring ($im, 5, 0, 0, "I Love GDLib!!!", $blue);
?>
Now take a look at your image. If all went
well, you should have the text "I Love GDLib!!!" written in blue in
your previously empty image. Lets examine why this happened. The first
argument, $im,
refers to which image the text should be written to. The second refers
to which of the five built in fonts to use. Each is mono space, with
the width of the characters matching the font number (ie. Font 3 will
have a character width of 3 pixels). The third and fourth arguments are
the x and y coordinates of the upper left hand corner of the string (a
string put at 0,0 will show, but a string put at 0, 300 would go
completely off the image). The fifth argument is the actual string, and
the last is the color. The color must be one of the colors allocated
from before. Now for some geometry. Were going to draw a rectangle
using the same blue color as the text. The function to draw rectangles
is imagerectangle (complex, eh?). Enter this line into your script and
we'll analyze:
imagerectangle ($im,50,50,100,100,$blue);
?>
Take a look at the image, and, if all went
well, you'll see the outline of a rectangle drawn in blue. The first
argument, $im,
refers to which image the rectangle is to be drawn on (like the
imageallocate and the imagestring function). The last argument
specifies which color it is to be drawn in. Only an allocated color can
be used. The 2nd to 5th arguments are the x1,y1, x2 and y2 coordinates
of the rectangle. x1,y1 is the upper left hand corner, and x2, y2 is
the lower right hand corner. As you can see, most image functions have
similar arguments. They all must identify which image they are to be
drawn to as their first argument, and most require the color they
should be in as their last argument. Imagerectangle and image string
are two of the many drawing functions that come with GDLib. Others
include imagedrawcircle, imagedrawpolygon, imageline,
and many, many others. This article will only scratch the surface of
this powerful extension, and the only way to learn how to use all the
drawing functions is to open up the PHP manual and experiment. Now try
the same coding again, only this time write imagefilledrectangle
instead of imagerectangle. If done properly, you should have, as the
name implies, a filled rectangle in blue. Now allocate the color black
to a variable, and use it in an imagerectangle after the
imagefilledrectangle to get a nice outline. To finish it all off, add
imagepng($im); to draw the image. The final code is below:
header ("Content-type: image/png");
$im = imagecreate (300, 300);
$white = imagecolorallocate ($im,255,255,255);
$blue = imagecolorallocate ($im,0,0,255);
$black = imagecolorallocate ($im,0,0,0);
imagestring ($im, 5, 0, 0, "I Love GDLib!!!", $blue);
imagefilledrectangle ($im,50,50,100,100,$blue);
imagerectangle ($im,50,50,100,100,$black);
imagepng($im);
?>
Now that you know the basics of image dynamics, we'll move on to a real world application: dynamic graphs.
Dynamic Graphs
To demonstrate some of the power of GDLib, we will use a voting poll in
which a bar graph of the results is generated as an example. To see a
graph like this in action, check out http://www.tamocomics.com,
my web comic (shameless advert), and click on "View Results" on the
homepage. The first step of making a voting poll is, obviously, to set
up the database. I made two tables in MySQL to handle the voting; one
that held the names and HTML values of the different voting options,
and another that kept track of the actual votes. There are millions of
ways one could set up a voting poll; this is not the only way and
definitely not the best. The "HTML values" in the first table are
simply shorter versions of the actual names that were used in the HTML
forms (ex: "Yes" would be "y"). This was made to take into account vote
options with spaces (ex: "I like the site a lot"). To avoid any later
trouble, I used the "name" only for display, and all the calculations
took place on the "HTML value." In the second table, all that is really
necessary is a column for the HTML value of the user's vote. IP
addresses and id numbers can be added as well depending on the site's
needs. A sample "options" table would be as follows:
+----+-----------+-------+
| id | name | value |
+----+-----------+-------+
| 1 | Hat | hat |
| 2 | Tee shirt | shirt |
| 3 | Pants | pants |
| 4 | Mug | mug |
+----+-----------+-------+
And a "poll" table (where the actual votes are recorded; the second of the above mentioned tables) might look like this:
+----+-----------+-------+
| id | ip | vote |
+----+-----------+-------+
| 1 | 127.0.0.1 | hat |
| 2 | 127.0.0.1 | shirt |
| 3 | 127.0.0.1 | hat |
| 4 | 127.0.0.1 | mug |
| 5 | 127.0.0.1 | pants |
| 6 | 127.0.0.1 | shirt |
| 7 | 127.0.0.1 | mug |
| 8 | 127.0.0.1 | hat |
| 9 | 127.0.0.1 | pants |
| 10 | 127.0.0.1 | shirt |
| 11 | 127.0.0.1 | mug |
| 12 | 127.0.0.1 | pants |
| 13 | 127.0.0.1 | pants |
| 14 | 127.0.0.1 | shirt |
| 15 | 127.0.0.1 | hat |
| 16 | 127.0.0.1 | shirt |
| 17 | 127.0.0.1 | hat |
| 18 | 127.0.0.1 | mug |
+----+-----------+-------+
Instead of imagecreate, imagecreatefrompng
was used. This stores the base image, "graphtemp.png", resource into
$im, rather than just white. Here are the dimensions etc. for the
picture, incase you decide to make one to follow along: it is 400x220,
the y-axis is 25 pixels away from the left hand of the image and the
x-axis is 200 pixels away from the top of the image, the y-axis is 184
pixels in height and the y-axis is 360 pixels in length. Keep these
numbers in mind, as they will be used later in the calculations. Next,
we allocate the colors to be used. Using black for the outline gives a
good effect, and the inside color is you choice. I will use red in this
example. So
= imagecolorallocate ($im, 255, 0, 0);
$black = imagecolorallocate ($im, 0, 0, 0);
?>
Nothing new. Now, a graph is quite empty without data, so the next step is to get the data that will fill this graph up.
We connect to the MySQL database:
("localhost", "user", "password");
mysql_query("USE database");
?>
Remember, of course, to change the host, user, password and database to match your servers set up
(so that's why it wouldn't work! :)). Now that we have the connection, we can begin to call data.
The first and most important number, yes even more important than knowing how many votes have been
cast, is the number of vote options you are working with. Without this piece pf data, there would
be no way to ensure that the right number of bars has been drawn. Call this magic variable as such:
= mysql_query("SELECT * FROM voteoptions");
$numoptions = mysql_num_rows($optionsquery);
?>
Using simple MySQL functions, we now know the number of vote options
were working with, and that number is stored in the variable $numoptions.
Even though just be looking at the MySQL table we can tell that there
are four options, this may change. Having this number loaded
dynamically allows the coder to have a truly dynamic graph system. Now,
we need to know how many people have voted. This is a number that can't
be checked manually, not with any ease for that matter.
(For more details read part2)
|