Trace: » direction » getting_started_guide

Getting Started Guide

Introduction

The main idea behind Image_Graph (former known as GraPHPite) was to create an easy-to-use graph creation tool in PHP.

The initial idea was thought a bit similar to a Lego brick. To create a house, boat, car, aeroplane or whatever, you build the “product” using a number of bricks. But with Lego, you don’t just have cubic bricks to deal with, you also have windows, doors, roof tiles, wheels, etc. In a similar fashion Image_Graph and/or GraPHPite was conceived in the idea of creating a set of building block, which put together in the right fashion comprises exactly the graph the user is looking for.

So starting from the bottom in Lego, you probably build your house on top of some base (a large Lego-”plate”), similar you build your graph on top of a base, the class Image_Graph. On to this base you begin building your Lego-house or Image_Graph-graph.

Installing

Installing Image_Graph is as easy as scratching your nose, if the prerequisites are in place. Image_Graph requires the following:

  • PHP 4 (4.3.0 or later is recommended if not required) or PHP 5
  • PEAR support or at least a working PEAR repository in your include_path
  • Image_Canvas package
  • Image_Color PEAR package
  • Numbers_Words and/or Numbers_Roman are required if using the datapreprocessors for textual numbers or roman numerals

If these requirements are met, the installations is as follows:

pear install Image_Graph-alpha

After installation, simply include Image_Graph in your project using:

include 'Image/Graph.php';

Creating The Building Blocks

As mentioned already you start by creating an Image_Graph object. The way objects are created in the Image_Graph library is using a factory method (as in the well-known design pattern Factory). The main reason a factory method is employed is to allow for a kind of lazy-include of the required files in the library (a complete include of the library would require too many resources and is not desireable).

The factory method can be called statically from the Image_Graph objects. That means that you only have to put one include statement into your graph page (unless you are going to play around with drivers, but we’ll get to that part later) - which is the main Image/Graph.php file.

The only special thing that is done within the factory method is to make a call to include_once on the class file, so there is no requirement on actually using the factory method way, but it’s a lot easier and is also recommended.

Okay, it’s time for some code. The instantiation of the graph object can be done like this:

include 'Image/Graph.php';
$Graph =& Image_Graph::factory('graph', array(600, 400));

If you do not wish to use the factory method, you can also create the object directly:

include 'Image/Graph.php';
$Graph =& new Image_Graph(600, 400);

There is absolutely no difference in the result of the 2 methods. The only difference is that if you consistently use the second way (the ‘new’-way) you will have to explicitly include the files for the necessary class. Once you have created the Image_Graph object, there is also no requirement on having to call the factory method statically. A good reason though is consistency, it is a good idea to do the same thing the same way - always, i.e. always use the static factory or the ‘new’-way.

To join the building blocks, each element has an add() method. This method takes as parameter the object to add on top of the element. To go back to the Lego analogy you add the Lego-bricks to the Lego-plate to build your house. That means that to add a new element to the graph you could do the following:

$newElement =& Image_Graph::factory(
    'some element',
    array($param1, $param2, &$param3)
);
$parentElement->add($newElement);

Or even (worse):

$parentElement->add(
    Image_Graph::factory('some element', array($param1, $param2, &$param3))
);

To overcome this apparent overcomplex API, a combined add/factory method exists: the addNew() method. This method take the same parameters as the factory method as creates an object using these parameters, which it then adds to the ‘parent’ object and finally returns a reference to the newly created object, useful for further modifications. This means that the above examples in the ‘short’ notation becomes:

$parentElement->addNew('some element', array($param1, $param2, &$param3));

A thing that is very important concerning Image_Graph objects is that assignments are all perfomed with the ‘by-reference’ operator (&). This is important for the very simple reason that PHP (PHP4 at least) by default uses ‘copy-of’ assignments, meaning that if $a is an object, then doing $a = $b, does not make $a == $b in the sense you would normally (in other object oriented languages) expect (i.e. that $a and $b is the same object) but in PHP they are equal in the sense that their ‘value’ is identical (i.e. the methods and properties all have the same values!). Which also means that doing something like:

$a = new A();
$a->property = 'this is a test';
 
$b = $a;
$a->property = 'changing the property';
 
print $b->property;

Will output ‘this is a test’ where you normally would expect it to output ‘changing the property’, due to the fact that $b = $a would assign the object $a to $b and not a copy hereof. This is relevant to Image_Graph due to the fact that we are adding objects constantly and thereby assigning them. Consider the following example:

$Plot = $Graph->addNew('line', &$Dataset);
/* notice the missing & */
$Plot->setLineColor('red');

In this example the $Plot would/could be a copy of the actual object created with the factory method (not this works as expected with PHP5), and therefor the setLineColor() call would be called on a copy of the object created with the factory method. Causing the plot not to show with a red line.

Building The Graph

Having instantiated your Image_Graph object, you can begin to construct your graph. To build a graph a number of building blocks are required:

  • The graph
  • An area to create the plots on
  • The plot
  • A set of data to plot

The above was all named in singular, but there is not limitation (except maybe the graph) to how many areas, plots or datasets you can create/add. With this in mind, let’s look at some actual code for a very, very simple graph and the break it into parts afterwards. The following code:

<?php
include 'Image/Graph.php';     
$Graph =& Image_Graph::factory('graph', array(400, 300)); 
$Plotarea =& $Graph->addNew('plotarea'); 
$Dataset =& Image_Graph::factory('dataset'); 
$Dataset->addPoint('Denmark', 10); 
$Dataset->addPoint('Norway', 3); 
$Dataset->addPoint('Sweden', 8); 
$Dataset->addPoint('Finland', 5); 
$Plot =& $Plotarea->addNew('bar', &$Dataset); 
$Graph->done(); 
?>

Will produce this result:

Creating The Graph

This section deals with:

include 'Image/Graph.php';     
$Graph =& Image_Graph::factory('graph', array(400, 300));

We have touched this previously so this section will be short. The graph object, which is an instance of Image_Graph is the main ‘keeper’ of the entire graph. The graph object can be created using the methods described in the section Creating The Building Blocks.

The Plotarea

This section deals with:

$Plotarea =& $Graph->addNew('plotarea');

The plotarea can be thought of as a coordinate-system. A plot area hold two axis and it is to the plotarea, the plots are added (and displayed). It is possible to have several plotareas within one graph. To decide how these plotareas are layed out on the graph, the concept of layout are introduced in the section Setting Up The Layout. By default the plotares (as mentioned) creates 2 axis - a x-axis and an y-axis (oddly enough). The y-axis is a normal linear value axis, i.e. from a valye y0 to a value y1, where y0 < y1, with a linear distribution of values [y0; y1]. The x-axis however is a category axis, meaning that x-values are used ‘as they are’. Fx. the x-values:

‘Dog’, 1, ‘Cat’, 0.5, ‘Boeing 747’

Are displayed on the axis as exactly these values, no linear distribution of the values are attempted. It is possible, when constructing the plotarea, to specify what type of axis are to be used. This is done by specifying as parameters the class of the axis to create (via the factory method, see Creating The Building Blocks). Fx.:

$Plotarea =& $Graph->addNew('plotarea', array('axis', 'axis_log'));

Which will create a plotarea consisting of a normal linear x-axis and a logarithmic y-axis. The following axis types exist currently

  • ‘axis’ or Image_Graph_Axis (normal linear axis)
  • ‘axis_log’ or Image_Graph_Axis_Logarithmic (logarithmic axis)
  • Image_Graph_Axis_Category (category / non-linear axis)
  • Image_Graph_Axis_Radar (x-axis used in radar charts, should not be used explicitly)

Adding a Plot

This section deals with:

$Plot =& $Plotarea->addNew('bar', &$Dataset);

Having created the foundation for your Lego house, you would definitely need a roof, or in our case, you would need a plot to display the data. This is (as previously mentioned) done by adding the plots to the plotarea. To create a new plot simply create the plot using the factory methods as specified in the code-snippet above. Pass the dataset to the constructor as well, making the plot use the data in the dataset. Remember to use the & in front of the dataset to force the plot to use the ‘same’ dataset object, not a copy thereof.

Image_Graph supports the following plot types:

  • ‘line’ or Image_Graph_Plot_Line
  • ‘area’ or Image_Graph_Plot_Area
  • ‘bar’ or Image_Graph_Plot_Bar
  • ‘smooth_line’ or Image_Graph_Plot_Smoothed_Line
  • ‘smooth_area’ or Image_Graph_Plot_Smoothed_Area
  • ‘pie’ or Image_Graph_Plot_Pie
  • ‘step’ or Image_Graph_Plot_Step
  • ‘impulse’ or Image_Graph_Plot_Impulse
  • ‘dot’ or ‘scatter’ or Image_Graph_Plot_Dot
  • ‘radar’ or Image_Graph_Plot_Radar (this is a special case which requires some further explanation)
  • Image_Graph_Plot_CandleStick
  • Image_Graph_Plot_Band

Below here is a visual example of the different plot types (in the order above starting from top left to bottom right):

The last 4 plots are subtypes of the ‘bar’, ‘area’ and ‘step’ plots. Image_Graphs supports multiple datasets within each plot. A multiple dataset plot can be displayed in 3 ways:

  • ‘normal’
  • ‘stacked’
  • ‘stacked100pct’

Normal means that data is displayed as they are, no summarization is done through the datasets. For a line chart this simply displays a normal line chart for each dataset, for a bar chart the bars are displayed next to one another as in the first example on the last row above. The ‘normal’ type is not supported for multiple datasets when using a step, impulse or area chart. And the ‘normal’ type is the only supported one for smoothed charts.

Stacked means that the datasets are added onto each other, meaning that the first dataset will start out from y1(x) = 0, the second from y2(x) = y1(x), making the plots be ... well stacked. This is demonstrated in the two examples in the middle of the last row above.

The last way is the ‘stacked100pct’, which means that similar to stacked charts the datasets are plotted on top of each other, but instead of a normal sum of the y-values, they actual y-value displayed is a percentage of the total sum, meaning that the plot will always summarize to 100% for every dataset value. An example could be the following datasets:

Dataset1: (a, 2), (b, 4), (c, 1)
Dataset2: (a, 1), (b, 0), (c, 3)

Will display actual y-values as:

Actual Dataset1: (a, 66.6%), (b, 100%), (c, 25%)
Actual Dataset2: (a, 33.3%), (b, 0%), (c, 75%)

Multiple plots can be added to the same plotarea, simply by adding them sequentially. Remember the last one added will be the one appearing on top! Fx.

$Plot1 =& $Plotarea->addNew('area', &$Dataset1); 
$Plot2 =& $Plotarea->addNew('line', &$Dataset2);

Entering Data

This section deals with:

$Dataset =& Image_Graph::factory('dataset'); 
$Dataset->addPoint('Denmark', 10); 
$Dataset->addPoint('Norway', 3); 
$Dataset->addPoint('Sweden', 8); 
$Dataset->addPoint('Finland', 5);

The plots of course need some data to display on the chart. This is done using datasets, there are 2 main types of datasets, first of all the ‘trivial’ dataset, which is the one most often used. The trivial dataset can be thought of as an array of datapoints (which is what the internal datastructure is), points are added to the dataset one by one using the method addPoint() as show above. The full class name for a trivial dataset is Image_Graph_Dataset_Trivial, but the short hand ‘dataset’ can be used for the factory methods. An example of usage is show above.

The other dataset type is the function based (as in mathematical function), there is a second version of the function based dataset which deals with vector functions. To use this dataset simply create it using the factory method, specify the starting and ending x-value [x0; $x1], the function-name to use as callback for the actual function call and finally the number of points to calculate. An example of usage could be:

function foo($bar) { 
    return 2 * $bar + 10; 
} 
     
$Dataset =& Image_Graph::factory('function', array(-3, 10, 'foo', 100));

This would cause a plot to display the function ‘foo’ with values starting from x = -3 to x = 10 calculating 100 points in between (that is intervals of 0.13). Using a function based dataset also means that the defaultt x-axis is not an optimal solution. The default/category x-axis will as mentioned previously display all the x-values, meaning that in this case the (default) x-axis will comprise of the values {-3, -2.87, -2.74, ..., 9.74, 9.87, 10}. To overcome this simply specify the linear axis for the x-axis in the constructor of the plotarea, i.e:

$Plotarea =& Image_Graph::factory('plotarea', 'axis');

As mentioned the sub-type of the function based dataset is the vector-function dataset, which is a dataset based on two functions one for the x-values and one for the y-values. To use this simply specify both the x- and y-function in the constructor, i.e:

function foo($t) { 
    return $t * cos($t); 
} 
     
function bar($t) { 
    return $t * sin($t); 
} 
     
$Dataset =& Image_Graph::factory('vector', 
    array(0, 10, 'foo', 'bar', 100) 
);

Output

This section deals with:

$Graph->done();

This is very simple! Simply call the done() method of the Image_Graph object to render the output. To make the plot output to a file, pass a parameter array as parameter to the done() method:

$Graph->done( 
    array('filename' => './output.png') 
);

Configuring Appearance

The default appearance (as show in the first example) is not very inviting or even ‘readable’. Therefor it is possible to set attributes on the elements, specifying their appearance. The following attributes can be set:

  • line color
  • fill color/style
  • border color
  • background color/style

The last 2 you probably wont use very often. Color handling in Image_Graph is done using the PEAR package Image_Color with some slight modifications/extensions resulting in the class Image_Graph_Color. This means that colors can be specified in the standard formats, including named colors (fx ‘red’, ‘green’, ‘magenta’, etc.) and RGB formats (fx. #00ff00 and 75%,20%,19%) and as a RGB array (fx. array(0, 255, 0)). It is also possible to specify the alpha channel (or opacity) within the color. When using the string formats, simply append an ‘@’ and the opacity as fraction, i.e. 0 = transparent, 1 = opague (fx. ‘red@0.2’, ‘#00ff00@0.9’) or as an array, pass the fraction as the fourth value, i.e. array(0, 255, 0, 0.2). Also check the PEAR manual for Image_Color

To set a color on an element, simply use the following methods:

$element->setLineColor('red'); 
$element->setFillColor('#0000ff@0.1'); 
$element->setBackgroundColor('green@0.1'); 
$element->setBorderColor(array(0, 0, 0));

Any one of the colors, can be of any of the formats specified above. It is also possible to specify more ‘fancy’ fill styles that colors. Supported fills are gradient filling and fill using an image. To do this, you need to create fill style objects using the factort methods. Fx.

$fill =& Image_Graph::factory( 
    'Image_Graph_Fill_Image', 
    'image_fill.png' 
); 
$element->setFillStyle($fill);

Or for a gradient:

$fill =& Image_Graph::factory('gradient', 
    array(IMAGE_GRAPH_VERTICAL, 'white', 'red') 
); 
$element->setFillStyle($fill);

The supported directions for the gradients are:

  • IMAGE_GRAPH_VERTICAL
  • IMAGE_GRAPH_HORIZONTAL
  • IMAGE_GRAPH_VERTICAL_MIRRORED
  • IMAGE_GRAPH_HORIZONTAL_MIRRORED
  • IMAGE_GRAPH_GRAD_DIAGONALLY_TL_BR
  • IMAGE_GRAPH_GRAD_DIAGONALLY_BL_TR
  • IMAGE_GRAPH_GRAD_RADIAL

More complex fillings can be achieved by using the Image_Graph_Fill_Array class, which makes the same element use different fillings, for example with a bar chart it is possible to make the first bar chart have one filling, the second another, and so forth. Which filling is used by which ‘box’ or filled element can be chosen in 2 ways: either as a round-robin or by giving each point an ID tag. For example:

$fill =& Image_Graph::factory('Image_Graph_Fill_Array'); 
$fill->addColor('red@0.2'); 
$fill->addColor('#00ff00'); 
$fill->addNew('gradient', 
    array( 
        IMAGE_GRAPH_GRAD_VERTICAL, 
        'white', 
        'blue' 
    ) 
); 
$Plot->setFillStyle($fill);

Assuming that $Plot for example is a bar chart this would cause the first bar to be displayed in ‘red@0.2’, the next with #00ff00 (green), the third with a gradient, the fourth in ‘red@0.2’, the fifth with #00ff00, and so on. The other way was to use ID tags. When creating the dataset, as a third parameter to the addPoint() method, an ID tag can be specified. For example:

$Dataset->addPoint('Denmark', 10, 'DK'); 
$Dataset->addPoint('Norway', 3, 'NO'); 
$Dataset->addPoint('Sweden', 8, 'SE'); 
$Dataset->addPoint('Finland', 5, 'FI');

And when adding the fill styles/colors to the array, specify the ID tag on the add method, fx:

$fill =& Image_Graph::factory('Image_Graph_Fill_Array'); 
$fill->addColor('red', 'DK'); 
$fill->addColor('lightblue', 'FI'); 
$fill->addColor('yellow', 'SE'); 
$fill->addColor('blue', 'NO'); 
$Plot->setFillStyle($fill);

Then the fill style is chosen, based upon the ID tag of the datapoint and the ID tag in the fill array, i.e. Denmark will use ‘red’ fill style, Sweden ‘yellow’, Norway ‘blue’ and Finland ‘lightblue’. Similarly you can use Image_Graph_Fill_Array to make multiple-dataset plots use different fill styles for each dataset, for example in a stacked area chart. Consider the fill style created above and assume we are creating a stacked area chart for the scandinavian countries, then the fillstyle can be chose accordingly:

$Datasets = array( 
    'DK' => &$DatasetDK, 
    'NO' => &$DatasetNO, 
    'SE' => &$DatasetSE, 
    'FI' => &$DatasetFI 
); 
$Plot =& $Plotarea->addNew('area', array($Datasets, 'stacked')); 
$Plot->setFillStyle($fill);

That is in this case the ID tags are the keys within the dataset array.

Setting Up The Layout

As shown in the example above displaying the possible plot types, it is possible to have several plot areas within the same graph. By having several plotareas, also comes the need to be able to decide how these plotareas are placed within the graph canvas. To solve this the concept of layout’s are introduced.

A layout is a simple class, which decides how it’s sub-elements are located on the graph. Image_Graph employs a simple method for this, by taking 2 elements and arranging them either vertically (on top of each other) or horizontally (next to each other). These layouts can be nested so that it is possible to divide the entire graph area into boxes with a defined perimiter. For example consider the wish to layout the graph with the following layout:

FIXME

+---------+---------------+
|         |               |
|    1    |       2       |
+---------+               |
|         +---------------+
|    3    |       4       |
|         |               |
+---------+---------------|

To do this we first create a horizontal layout, splitting (1+3) from (2+4), that is divide the area by the vertical line going down the middle (at 40% from the left edge in this case). We now have 2 area, the one (A) consisting of 1+3 and the other (B) consisting of 2+4. Now we wish to split A into 1 and 3 (which in this case is done at 43% (3/7 th) off the top edged), and then split B into 2 and 4 at 71% (5/7 th).

With this in mind let’s see how Image_Graph does it. To create the horizontal and vertical layout’s Image_Graph uses the two factory methods horizontal() and vertical() which can be called statically on the Image_Graph class. So to create a horizontal layout/arrangement of 2 elements af 40% off the left edge, the following can be done:

$Graph->add( 
    Image_Graph::horizontal( 
        $A, 
        $B, 
        40 
    ) 
);

To continue the example above, then $A will be the are A = (1+3) and $B = B = (2+4), so that we could do the following, prior to the above call:

$A =& Image_Graph::vertical( 
    $part1, 
    $part3, 
    43 
); 
     
$B =& Image_Graph::vertical( 
    $part2, 
    $part4, 
    71 
);

Or this could (simply) be performed in one call:

$Graph->add( 
    Image_Graph::horizontal( 
        Image_Graph::vertical( 
            $part1 = Image_Graph::factory('plotarea'), 
            $part3 = Image_Graph::factory('plotarea'), 
            43 
        ), 
        Image_Graph::vertical( 
            $part2 = Image_Graph::factory('plotarea'), 
            $part4 = Image_Graph::factory('plotarea'), 
            71 
        ), 
        40 
    ) 
);

Notice that we also did the creation of the plotareas inline with the $partx = Image_Graph::factory(’plotarea’) call. Also notice that here the & was deliberately left out! For some obscure reason it does not work if you include the &. If you need to create a set of equally sized plotareas, for example in a 3 by 2 grid (or 4 by 3 as above) you can use the Image_Graph_Layout_Matrix class to do this. Lets assume that in the above examples 1, 2, 3 and 4 are all going to be the same size, then we could do the following:

$Matrix =& $Graph->addNew('Image_Graph_Layout_Matrix', array(2, 2)); 
$part1 =& $Matrix->getEntry(0, 0); 
$part2 =& $Matrix->getEntry(0, 1); 
$part3 =& $Matrix->getEntry(1, 0); 
$part4 =& $Matrix->getEntry(1, 1);

Notice the coordinate system uses matrix coordinates (row, column). Using a matrix layout in this way will always create the rows*column new plotareas all with the same size. It is also possible to just create the ‘slots’ and the fill in the blacks later on. To do this simply pass ‘false’ as parameter 3 to the constructor and the use the setEntry() method of the matrix object to occupy a slot by a specified element:

$Matrix =& $Graph->addNew('Image_Graph_Layout_Matrix', array(2, 2, false)); 
$part1 =& Image_Graph::factory('plotarea'); 
$Matrix->setEntry(0, 0, $part1);

A More Comprehensive Example

This example is more comprehensize and deals with some features that was not convered in this guide. Have a look at it, it should be possible to get the ideas from the inline comments.

require 'Image/Graph.php';    
 
// create the graph
$Graph =& Image_Graph::factory('graph', array(400, 300));
// add a TrueType font
$Font =& $Graph->addNew('ttf_font', 'Gothic');
// set the font size to 11 pixels
$Font->setSize(8);
 
$Graph->setFont($Font);
 
// create the plotarea layout
$Graph->add(
    Image_Graph::vertical(
        Image_Graph::factory('title', array('Primary & Secondary Axis', 11)),
        Image_Graph::vertical(
            $Plotarea = Image_Graph::factory('plotarea'),
            $Legend = Image_Graph::factory('legend'),
            90
        ),
        5
    )
);         
 
// make the legend use the plotarea (or implicitly it's plots)
$Legend->setPlotarea($Plotarea);   
 
// create a grid and assign it to the secondary Y axis
$GridY2 =& $Plotarea->addNew('bar_grid', IMAGE_GRAPH_AXIS_Y_SECONDARY);  
$GridY2->setFillStyle(
    Image_Graph::factory(
        'gradient', 
        array(IMAGE_GRAPH_GRAD_VERTICAL, 'white', 'lightgrey')
    )
);    
 
// create a line plot using a random dataset
$Dataset1 =& Image_Graph::factory('random', array(8, 10, 100, true)); 
$Plot1 =& $Plotarea->addNew('line', &$Dataset1);
$Plot1->setLineColor('red');
 
// create an area plot using a random dataset
$Dataset2 =& Image_Graph::factory('random', array(8, 1, 10, true)); 
$Plot2 =& $Plotarea->addNew(
    'Image_Graph_Plot_Area', 
    $Dataset2, 
    IMAGE_GRAPH_AXIS_Y_SECONDARY
);
 
$Plot2->setLineColor('gray');
$Plot2->setFillColor('blue@0.2');
 
// set the titles for the plots
$Plot1->setTitle('Primary Axis');
$Plot2->setTitle('Secondary Axis');
 
$AxisX =& $Plotarea->getAxis(IMAGE_GRAPH_AXIS_X);
$AxisX->setTitle('Oranges');
$AxisY =& $Plotarea->getAxis(IMAGE_GRAPH_AXIS_Y);
$AxisY->setTitle('Apples', 'vertical'); 
$AxisYsecondary =& $Plotarea->getAxis(IMAGE_GRAPH_AXIS_Y_SECONDARY);
$AxisYsecondary->setTitle('Pears', 'vertical2'); 
 
// output the Graph
$Graph->done();

The result of this code is:

 
image_graph/getting_started_guide.txt · Last modified: 2006/02/22 18:19