4.4. Callbacks
Prev | Chapter 4. PHPlot Advanced Topics | Next

## 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:

- SetCallback - Register a callback function

- GetCallback - Return a currently registered callback function

- RemoveCallback - Unregister a callback function

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

### 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, this will pass a reference to the object, which allows reading and changing variables. (PHP4 would pass a copy of the object at the time the callback function is being set up, which would probably not be useful. There are work-arounds, but PHP4 is no longer supported.)

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_color | Every time a color is needed for a data element. | $row, $col, $extra | The 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_points | Every 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_setup | After all setup, before drawing anything. | (None) | Anything drawn here will be covered by the background.
draw_image_background | After drawing the image backgrounds and border. | (None) |
draw_plotarea_background | After drawing the plot area background. | plot_area | plot_area parameter was added in PHPlot-5.1.0
draw_titles | After drawing the plot title, X and Y titles. | (None) | Called even if no titles were set.
draw_axes | After drawing the X and Y axis and grid lines. | (None) | Not called for pie charts.
draw_graph | After drawing the body of the graph. | plot_area | plot_area parameter was added in PHPlot-5.1.0
draw_border | After drawing the plot area border. | (None) | Not called for pie charts before PHPlot-5.6.0
draw_legend | After drawing the legend, if legend is enabled. | (None) | Not called if no legend was set.
draw_all | After all drawing is complete. | plot_area | Added in PHPlot-5.1.0
debug_textbox | Just before drawing any text. | $px, $py, $bbox_width, $bbox_height | Provides access to the orthogonal bounding box position and size for the text string.
debug_scale | Called at end of many scale calculation functions. | Function name, then an array of variable name => value | For 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 my_PHPlot($width=600, $height=400, $outfile=NULL, $infile=NULL)
      {
        $this->PHPlot($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 we are using a PHP4-style constructor, which also works with PHP5. You can use the PHP5 constructor method instead.)

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

This is for PHP5. For PHP4, you need to use a reference to the $plot instance. Note that PHP4 is no longer supported.

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

Prev | Up | Next
4.3. Truecolor Images | Home | 4.5. Custom Data Color Selection