4.4. Callbacks

This section documents the callback feature in PHPlot.

Callbacks allow a programmer using PHPlot to insert their own functions into the graph drawing process. Callbacks are currently also used for development and testing of PHPlot.

Warning

All PHPlot class variables, and all methods/functions which are not documented in the "Reference" section of the PHPlot Reference Manual, are considered to be for internal use and are subject to be changed or removed at any time. If you call internal functions, or access internal class variables, you greatly increase the risk of breaking your application with future PHPlot releases.

4.4.1. Callbacks Application Interface

Refer to these entries in the Function Reference:

Either a function name or an object and method can be registered as a callback with SetCallback. For more information about using callbacks with objects and methods, see the PHP manual under Types, Pseudo Types, Callback and the documentation for the PHP call_user_func function. Also refer to Section 4.4.4, “Object Methods as Callbacks” later in this manual. Whether calling a function or an object method as a callback, the same calling sequence is used.

function_name($img, $passthrough_arg, [other_args...])

$img

The GD image resource for the plot image.

$passthrough_arg

The third argument supplied to SetCallback ($arg) when the callback is established. This allows the programmer to pass information to the callback without using global variables. This can be any PHP type including array. To pass a reference, you should put it into an array and pass the array.

other_args...

Zero or more additional arguments supplied by PHPlot to callbacks of this type. Refer to Section 4.4.3, “Available Callbacks” to see what callback reasons supply extra arguments.

For example, given this callback setup:

$plot->SetCallback('draw_graph', 'my_drawing_callback', $myvar);

Then PHPlot will call:

my_drawing_callback($img, $myvar_value, $plot_area);

Where $myvar_value is the value of $myvar at the time SetCallback was called. (The plot_area parameter is only supplied for the draw_graph callback in PHPlot-5.1.0 and later.)

Some callbacks are expected to return a value. This is documented in Section 4.4.3, “Available Callbacks”. In all other cases, the return value from a callback function is ignored. (Callbacks which return a value were implemented in PHPlot-5.1.3.)

Note

Instead of using the name of a function in SetCallback, you can use a PHP anonymous function. See the example in Section 4.5.2, “Custom Data Color Selection”.

4.4.2. Callback Function Access

By default, the callback function has access only to the GD image resource as the $img argument, the pass-through argument provided when the callback function was registered, and additional arguments (if any) provided by PHPlot for the callback. It does not have access to the PHPlot class object instance, nor any of its contents.

If you need access to the internals of the PHPlot class instance from your callback, you have three options.

  1. You can declare your PHPlot class instance variable as global.

  2. You can pass the instance variable as the $arg when registering the callback. With PHP5 and above, this will pass a reference to the object, which allows reading and changing variables.

  3. You can use a class method which extends PHPlot. This is described in Section 4.4.4, “Object Methods as Callbacks”.

As stated in the warning at the top of this section, any access to the class internals is risky and subject to break with any new update to PHPlot.

4.4.3. Available Callbacks

This section defines the currently available callback names. A callback name is also called a reason.

Note

At most one callback can be active for any given callback name, for each PHPlot object. Setting a second callback on the same name will result in the new callback replacing the old one.

Most of the callbacks currently available are drawing callbacks, activated during the graph drawing process started by DrawGraph. By convention, a drawing callback occurs right after the event which it names. For example, the draw_titles callback will be called after drawing the plot titles.

Debug callbacks are for use when developing and debugging PHPlot itself. Needless to say, their use for other purposes is discouraged.

The following table lists the available callback reasons.

Callback Name:Calling Point:Extra Parameters:Notes:
data_colorEvery time a color is needed for a data element.$row, $col, $extraThe callback is expected to return an integer color index into the data colors array. This is for custom color selection. For more information, see Section 4.5, “Custom Data Color Selection”.
data_pointsEvery time a data point is plotted, for supported plot types.$shape, $row, $col, ...This callback is primarily used to create image maps. For more information, see Section 4.10, “Image Maps for Plot Data”. This was added in PHPlot-5.7.0.
draw_setupAfter all setup, before drawing anything.(None)Anything drawn here will be covered by the background.
draw_image_backgroundAfter drawing the image backgrounds and border.(None) 
draw_plotarea_backgroundAfter drawing the plot area background.plot_areaplot_area parameter was added in PHPlot-5.1.0
draw_titlesAfter drawing the plot title, X and Y titles.(None)Called even if no titles were set.
draw_axesAfter drawing the X and Y axis and grid lines.(None)Not called for pie charts.
draw_graphAfter drawing the body of the graph.plot_areaplot_area parameter was added in PHPlot-5.1.0
draw_borderAfter drawing the plot area border.(None)Not called for pie charts before PHPlot-5.6.0
draw_legendAfter drawing the legend, if legend is enabled.(None)Not called if no legend was set.
draw_allAfter all drawing is complete.plot_areaAdded in PHPlot-5.1.0
debug_textboxJust before drawing any text.$px, $py, $bbox_width, $bbox_heightProvides access to the orthogonal bounding box position and size for the text string.
debug_scaleCalled at end of many scale calculation functions.Function name, then an array of variable name => valueFor displaying intermediate values in margin and scale calculations.

Notes:

Several of the drawing callbacks include plot_area as an extra parameter. This is an array of 4 values that define the plot area within the image, in GD pixel coordinates, as left_x, top_y, right_x, and bottom_y. For more information, see Chapter 7, PHPlot Plot Layout.

See Section 4.4.5, “Using Callbacks to Annotate Plots” for information on using the drawing callbacks to annotate your plot.

4.4.4. Object Methods as Callbacks

The callback function argument to SetCallback can be an array of two elements: a class variable and a method. This can be used with any class, but here we are interested in using an extension of the PHPlot class. Consider the following setup:

class my_PHPlot extends PHPlot
{
  function __construct($width=600, $height=400, $outfile=NULL, $infile=NULL)
  {
    parent::__construct($width, $height, $outfile, $infile);
  }

  function callback($img, $arg)
  {
    fwrite(STDERR, "callback in object\n");
    fwrite(STDERR, "Plot area: ({$this->plot_area[0]}, {$this->plot_area[1]}) :");
    fwrite(STDERR, " ({$this->plot_area[2]}, {$this->plot_area[2]})\n");
  }
}

We define a class which extends PHPlot, and a method 'callback' which displays the plot area using the internal PHPlot class variable plot_area.

Note

PHPlot version 6.1.0 and earlier used the class name as the constructor method name, as required in PHP4. This was deprecated in PHP7. Earlier versions of this reference manual used $this->PHPlot(...) to call the parent constructor. This will not work with PHPlot after version 6.1.0 when the constructor name was changed for PHP7.

Using __construct() in the extended class as shown above - for both the extended class constructor and when calling the base class constructor - will work in PHP5 and PHP7, and with PHPlot versions before and after the constructor name change.

We will then create an instance of the extended class, and set a callback.

$plot = new my_PHPlot(400,300);
$plot->SetCallback('draw_titles', array($plot, 'callback'));

When the draw_titles callback is triggered, it will call the 'callback' method inside our extended class. Because this is an extension of the PHPlot class, it has access to all the member variables via $this.

4.4.5. Using Callbacks to Annotate Plots

This section contains information about using PHPlot callbacks to annotate a plot with text and graphics. This is an advanced topic, and requires some knowledge of both PHPlot and the PHP GD extension.

Warning

The information in this section uses features which are recent additions to PHPlot, and in some cases uses PHPlot internal variables and functions. As a result, these methods are less likely to work with older releases, and more at risk to change or break in future releases.

This section will first provide general information and advice about annotating plots using callbacks. After, portions of the script from Section 5.22, “Example - Annotating a Plot Using a Callback” will be explained in more detail.

The emphasis here is on using callbacks, but annotation is also possible without callbacks. You can use SetPrintImage(False) to disable automatic output of your image. Then, when DrawGraph returns, you can annotate your plot using GD functions on the img member variable of your PHPlot object. Use of callbacks is preferred, however, because it makes your script somewhat less dependent on PHPlot internals (such as the img variable).

4.4.5.1. Setting the callback

Use SetCallback to establish a drawing callback. You can find a list of callbacks in Section 4.4.3, “Available Callbacks”. The various callbacks with names starting 'draw_' are called at different points in the drawing process. Drawn objects will cover items drawn at an earlier stage. For example, if you draw a line from a 'draw_titles' callback (which is called after the plot titles are drawn, but before the graph is drawn), the line would be 'behind' and possibly covered by the plotted data.

Note that PHPlot does very little except save parameter values until you call DrawGraph. For that reason, you should use GD functions for annotation only from a drawing callback (that is, a callback with a name starting with 'draw_'). The drawing callbacks are called after PHPlot calculations and image resource setup, at which point everything is ready for drawing. In addition, you should not use PHPlot functions which control plot appearance from your drawing callback. These would either have no affect, because it is too late, or produce unexpected results.

4.4.5.2. Coordinates

When drawing with GD, you will use the Device Coordinate system. The coordinates in this system are pixels, with the origin in the upper left corner of your image. Y advances down and X advances to the right.

If you want to make annotations relative to specific values in your plot data, you need to translate those values from World Coordinates to device coordinates. Use the PHPlot function GetDeviceXY to perform this translation. You will need access to your PHPlot object from inside your callback function in order to use this (or any other PHPlot method function). You can make it global, or designate it as the passthrough argument to SetCallback.

Note

This does not apply to pie charts, which have do not use world coordinates.

If your annotations will fall outside the plot area (for example, in an area you reserved for annotation using SetPlotAreaPixels or SetMarginsPixels, then you need not be concerned with coordinate translation. Of course, you can also add annotations at fixed pixel coordinates inside the plot area, however these may overlay (if done from a draw_graph or later callback) or underlay (if done before the draw_graph callback) the plotted data.

4.4.5.3. Colors

Every GD drawing function you use will require a color value argument. You are recommended to allocate your own colors in your callback using the GD function imagecolorresolve(). This function will always return a color index, by either re-using an existing color in the image's color map, or by allocating a new color. Using imagecolorresolve() rather than trying to access the PHPlot internal variables for color indexes will protect your script from breaking if the way PHPlot manages its internal colors ever changes.

4.4.5.4. Text

Text can be added to your plot using GD functions which include imagestring, for build-in simple fonts, and imagettftext for TrueType font text. To use these functions, you need device coordinates, as described above.

You can also add text to your plot using the PHPlot function DrawText. This is documented only for internal use by PHPlot, so there is a risk of future incompatibility. But this function provides support for controlling the text justification, and works better with multi-line text.

4.4.5.5. Example

This example creates a bar chart and adds annotation. The goal is to draw an ellipse and add text to the highest and lowest bars in a bar chart. Refer to Section 5.22, “Example - Annotating a Plot Using a Callback” for the complete script and output from this example.

The script starts with the usual PHPlot object creation and setup.

$plot = new PHPlot(800, 600);
$plot->SetTitle('Monthly Widget Sales');
...

(For the complete script, see the example referenced above.)

Before calling DrawGraph, establish the drawing callback. This uses the draw_all callback, which gets called when all drawing is complete in DrawGraph. (Note: If using PHPlot-5.0.7 or earlier, use 'draw_graph' instead, as 'draw_all' was not yet available.) The name of our callback function is annotate_plot, and we are passing the PHPlot object ($plot) as a pass-through parameter. You can use a global or class callback instead - see Section 4.4.1, “Callbacks Application Interface” for more on these options.

$plot->SetCallback('draw_all', 'annotate_plot', $plot);

Here is the declaration of our callback function. The $img parameter is provided by PHPlot itself, and is the GD resource for our image. The $plot parameter is the pass-through argument we provided above when establishing the callback. Some callbacks make other parameters available. In fact, 'draw_all' provides the plot area coordinates as an additional parameter, but we don't need that here so we do not have to include that in the function declaration.

function annotate_plot($img, $plot)
{

As stated above, you should allocate your own colors, rather than trying to get into PHPlot's internals for color values. Here we allocate two colors and assign the color indexes to local variables:

$red = imagecolorresolve($img, 255, 0, 0);
$green = imagecolorresolve($img, 0, 216, 0);

Next, we want to draw graphics centered on two points in our data. The points were calculated as best_index (X), best_sales (Y), worst_index (X), and worst_sales (Y). In order to draw at these locations, we need to translate the values from World Coordinates to Device Coordinates. This is done using the PHPlot function GetDeviceXY.

list($best_x, $best_y) = $plot->GetDeviceXY($best_index, $best_sales);
list($worst_x, $worst_y) = $plot->GetDeviceXY($worst_index, $worst_sales);

Now we are ready to draw some ellipses, centered on our two data points. The values 50 and 20 are the width and height, in pixels.

imageellipse($img, $best_x, $best_y, 50, 20, $green);
imageellipse($img, $worst_x, $worst_y, 50, 20, $red);

As stated above, we have two options for text, and the example uses each method. We can draw text using the GD functions, but we have to do a little more work to position the text. Here the text is approximately centered horizontally and above the data point. (Note ImageString by default uses the upper left corner of the text string for positioning.)

$font = '3';
$fh = imagefontheight($font);
$fw = imagefontwidth($font);
imagestring($img, $font, $best_x-$fw*4, $best_y-$fh-10, 'Good Job!', $green);

Or, we can use the PHPlot internal function DrawText. With a PHPlot version 5.1.0 and later, we omit the font specification and it will default to the generic font, which can be set with SetFont('generic', ...)

$plot->DrawText('', 0, $worst_x, $worst_y-10, $red, 'Bad News!', 'center', 'bottom');

SourceForge.net Logo

This version of the manual was produced for the PHPlot Sourceforge project web service site, which requires the logo on each page.

To download a logo-free copy of the manual, see the PHPlot project downloads area.