4.10. Image Maps for Plot Data
Prev | Chapter 4. PHPlot Advanced Topics | Next

## 4.10. Image Maps for Plot Data

This section describes the use of the `data_points` callback to generate an HTML image map (or other similar construct) from plot data. An image map created using this callback will contain links from the data points or shapes on the plot. This feature was first added in PHPlot-5.7.0 as an experimental feature, and was first documented in this Reference Manual with PHPlot-6.0.0.

### Note

Use of callbacks is documented in Section 4.4, “Callbacks”.

The `data_points` callback makes the device coordinates of plotted data available to a script using PHPlot. If a script registers a function as a handler for the `data_points` callback name, the function will be called repeatedly when the plot is being generated. Each call will contain parameters describing the graphics for the corresponding data point. These parameters can be used to create an HTML image map.

This feature is most likely only useful when generating embedded image data with PHPlot. (See EncodeImage for details on embedded image data.) This is because HTML requires the image map be included in the HTML page which contains the reference to the plot image. The browser will first request the HTML page, then make a second request for the image. Normally, the image is generated by a script using PHPlot, but the image map has to be available before this script runs. Using embedded image data allows a single PHP script to produce both the image map and the image data, and return the result as a single page.

Nevertheless, it is also possible to create an image map with a non-embedded image. See Section 4.10.4, “Image Maps with Non-embedded Image Data” for details.

The `data_points` callback works with the following plot types:

- bars and stackedbars (both horizontal and vertical)

- boxes

- bubbles

- ohlc, candlesticks, and candlesticks2

- pie

- points and linepoints (both standard and error bar plots)

No other plot type is supported. This includes lines, squared, thinbarline, area, and stackedarea. (These plot types do not have well-defined areas which could map to data points.)

The rest of this section contains details on the callback, usage with each plot type, and additional information.

### 4.10.1. Image Maps - Usage

To register a callback function to handle `data_points`, use:

    $plot->SetCallback('data_points', 'my_handler', $my_arg);

Where `my_handler` is the name of your function, `$my_arg` is an optional additional argument to pass to your function.

The `data_points` callback function (`my_handler()` above) will be called with 5 fixed-purpose arguments followed by variable arguments. The number and purpose of the variable arguments depends on the plot type. If your handler only needs to work with one specific plot type, you can declare these arguments in your function definition.

If your handler must handle multiple plot types, define your function without arguments and use `func_get_arg()` or `func_get_args()` to access the arguments. You can use the value of the 3rd argument, `$shape`, to determine the number and usage of the variable arguments, since there is one specific function argument set for each value of `$shape`. See Section 4.10.2, “Image Maps - data_points Callback Parameter Summary” for more information.

Here are the fixed arguments to the `data_points` callback function, with this general declaration:

    function my_handler($img, $passthru, $shape, $row, $column, ...)

$img

  The image resource (standard for all callbacks). Not generally used with a `data_points` callback, which cannot safely draw on the image (since PHPlot is in the middle of drawing the plot on the same image).

$passthru

  Pass-through argument, supplied in the SetCallback() call (standard for all callbacks, referred to above as `$my_arg`). You can use this however you want, or ignore it.

$shape

  A word describing the shape of the area being described. This does not necessarily correspond to an HTML image map <area> shape. Each plot type passes a specific shape value, and the shape value defines the usage of the variable arguments.

$row

  The number of the data row being plotted. This typically corresponds to the ordinal of the X axis values (Y for horizontal plots), starting with 0 for the first point, 1 for the second point, etc.

$column

  The column, or data set index, starting with 0 for the first data set. This indicates which Y value for a given X, for example, or which bar within a bar group, or segment within a stacked bar. (For horizontal plots, this would indicate which X for a given Y.) Always 0 for pie charts and OHLC plots, which only have a single data set.

For the variable arguments, refer to the sections below which describe each plot type.

#### 4.10.1.1. Image Maps from Bars and Stackedbars Plots

With plot types bars and stackedbars, an image map can be produced which indicates the area of each bar or stacked bar segment. This works with both vertical and horizontal plots.

For bar and stackedbar plots, the `data_points` callback has this form:

    function my_handler($img, $passthru, $shape, $row, $column, $x1, $y1, $x2, $y2)

The first 2 arguments are standard for all PHPlot callbacks and are not described here. The next 3 arguments are common to all data_points callbacks, and there are 4 additional arguments:

$shape

  Always `rect`, indicating a rectangle shape.

$row

  This is the bar group index. The left-most bar group (for vertical bar charts) is row 0.

$column

  This is the bar index within a group. For vertical plot type 'bars', index 0 is the left-most in the group. For vertical plot type 'stackedbars', index 0 is the bar segment closest to the X axis.

$x1, $y1

  Device coordinates of the upper left corner of a bar or segment.

$x2, $y2

  Device coordinates of the lower right corner of a bar or segment.

Generating an image map for bar and stackedbar plots is straight-forward. The provided `$shape` and coordinates are compatible with HTML <area> markup. You must provide the URL, alternate text, and optionally a title (tooltip text).

This example appends the image map line to a string. sprintf() is used to convert the coordinates to integers for cleaner HTML.

    $coords = sprintf("%d,%d,%d,%d", $x1, $y1, $x2, $y2);
    $image_map .= "  <area shape=\"rect\" coords=\"$coords\""
              .. " title=\"$title_text\" alt=\"$alt_text\" href=\"$url\">\n";

The `$url`, `$title_text`, and `$alt_text` would typically depend on the passed `$row` and `$column`.

Refer to Section 5.44, “Example - Image Map from Bar Chart” for a complete example of an image map for a bar chart.

#### 4.10.1.2. Image Maps from Box Plots

With plot type boxes, an image map can be produced which indicates the area of each data point. This area is the bounding box which includes the box and both whiskers. The bounding box does not include any outliers.

For box plots, the `data_points` callback has this form:

    function my_handler($img, $passthru, $shape, $row, $column, $x1, $y1, $x2, $y2)

The first 2 arguments are standard for all PHPlot callbacks and are not described here. The next 3 arguments are common to all data_points callbacks, and there are 4 additional arguments:

$shape

  Always `rect`, indicating a rectangle shape.

$row

  The index of the data row, starting with 0 for the first X value.

$column

  This is unused, and always 0.

$x1, $y1

  Device coordinates of the upper left corner.

$x2, $y2

  Device coordinates of the lower right corner.

The upper left and lower right coordinates above refer to the bounding box as described above.

Generating an image map for box plots is straight-forward. The provided `$shape` and coordinates are compatible with HTML <area> markup. You must provide the URL, alternate text, and optionally a title (tooltip text).

This example appends the image map line to a string. sprintf() is used to convert the coordinates to integers for cleaner HTML.

    $coords = sprintf("%d,%d,%d,%d", $x1, $y1, $x2, $y2);
    $image_map .= "  <area shape=\"rect\" coords=\"$coords\""
              .. " title=\"$title_text\" alt=\"$alt_text\" href=\"$url\">\n";

The `$url`, `$title_text`, and `$alt_text` would typically depend on the passed `$row`.

Section 5.44, “Example - Image Map from Bar Chart” contains a complete example of an image map for a bar chart, and the parameters and usage for box plots are the same except that the $col (column) parameter is always 0, since there is only one data set.

#### 4.10.1.3. Image Maps from Bubbles Plots

With plot type bubbles, an image map can be produced which indicates the area of each bubble.

For bubbles plots, the `data_points` callback has this form:

    function my_handler($img, $passthru, $shape, $row, $column, $x, $y, $diam)

The first 2 arguments are standard for all PHPlot callbacks and are not described here. The next 3 arguments are common to all data_points callbacks, and there are 3 additional arguments:

$shape

  Always `circle`, indicating a disk shape.

$row

  The row is the index for the independent variable X. The first X value has index 0.

$column

  The column is the index for the dependent variable Y. For the first (or only) dataset for each X, the column index is 0.

$x, $y

  Device coordinates of the center of the bubble.

$diam

  Diameter of the bubble, in pixels.

Generating an image map for bubble plots is straight-forward. PHPlot provides parameters that are compatible with HTML image map markup, except that PHPlot provides a diameter, and HTML requires the radius.

Here is an example of generating one area in an image map from a bubbles plot. You must provide the URL, alternate text, and optionally a title (tooltip text). This appends the image map line to a string. sprintf() is used to convert the coordinates to integers for cleaner HTML.

    $coords = sprintf("%d,%d,%d", $x, $y, $diam / 2);
    $image_map .= "  <area shape=\"circle\" coords=\"$coords\""
                . " title=\"$title_text\" alt=\"$alt_text\" href=\"$url\">\n";

The `$url`, `$title_text`, and `$alt_text` would typically depend on the passed `$row` and `$column`.

Other than the above code, a script to generate an image map for a bubbles plot would be similar to Section 5.44, “Example - Image Map from Bar Chart”, which produces a bar chart.

#### 4.10.1.4. Image Maps from Financial OHLC Plots

With plot types ohlc, candlesticks, and candlesticks2 (collectively called OHLC - open, high, low, close plots), an image map can be produced which indicates the area of each data point. For candlesticks and candlesticks2 plots, this area is the bounding box containing the candlestick and its wicks. For ohlc plots, this area is the bounding box formed by the vertical line and horizontal ticks.

For OHLC plots, the `data_points` callback has this form:

    function my_handler($img, $passthru, $shape, $row, $column, $x1, $y1, $x2, $y2)

The first 2 arguments are standard for all PHPlot callbacks and are not described here. The next 3 arguments are common to all data_points callbacks, and there are 4 additional arguments:

$shape

  Always `rect`, indicating a rectangle shape.

$row

  The index of the data row, starting with 0 for the first X value.

$column

  This is unused, and always 0.

$x1, $y1

  Device coordinates of the upper left corner.

$x2, $y2

  Device coordinates of the lower right corner.

The upper left and lower right coordinates above refer to the bounding box as described above.

Generating an image map for OHLC plots is straight-forward. The provided `$shape` and coordinates are compatible with HTML <area> markup. You must provide the URL, alternate text, and optionally a title (tooltip text).

This example appends the image map line to a string. sprintf() is used to convert the coordinates to integers for cleaner HTML.

    $coords = sprintf("%d,%d,%d,%d", $x1, $y1, $x2, $y2);
    $image_map .= "  <area shape=\"rect\" coords=\"$coords\""
              .. " title=\"$title_text\" alt=\"$alt_text\" href=\"$url\">\n";

The `$url`, `$title_text`, and `$alt_text` would typically depend on the passed `$row`.

Section 5.44, “Example - Image Map from Bar Chart” contains a complete example of an image map for a bar chart, and the parameters and usage for OHLC plots are the same except that the $col (column) parameter is always 0, since there is only one data set.

#### 4.10.1.5. Image Maps from Pie Plots

With plot type pie, an image map can be produced which indicates the area of each pie segment. However, PHPlot only supplies the values which identify the outline of the pie segment, and HTML maps do not support areas of this shape. Therefore, the callback handler function needs to generate one or more polygons which approximate the pie segment area.

### Note

PHPlot does not attempt to draw pie segments that are too small (due to the implementation of the PHP/GD drawing function). If a segment's calculated start angle and end angle are equal (after converting to integers), the segment will not be drawn, and the data_points callback will not be called for that segment.

For pie charts, the `data_points` callback has this form:

    function my_handler($img, $passthru, $shape, $row, $column, $x, $y,
                        $pie_width, $pie_height, $start_angle, $end_angle)

The first 2 arguments are standard for all PHPlot callbacks and are not described here. The next 3 arguments are common to all data_points callbacks, and there are 6 additional arguments:

$shape

  Always `pie`, indicating a pie segment of an ellipse.

$row

  The pie segment index, starting at 0 for the first segment. (By default, segments are drawn counter-clockwise from 0 degrees, but this can be changed.)

$column

  This is unused, and always 0.

$x, $y

  Device coordinates of the center of the pie.

$pie_width

  Horizontal diameter of the pie, in pixels.

$pie_height

  Vertical diameter of the pie, in pixels.

$start_angle

  Starting angle for the segment, in clockwise degrees (see note).

$end_angle

  Ending angle for the segment, in clockwise degrees.

### Note

clockwise degrees means (360 - A), where A is an angle measured in the conventional sense: counter-clockwise from the X axis. For example, a pie segment that starts at the top of the pie ('North') and ends at the bottom point ('South') would have start_angle=270 and end_angle=90. The start_angle is always greater than the end angle.

Generating an image map for pie charts is more involved than with other plot types. Each pie segment is defined by the ellipse center point, the two diameter values, and the start and end angles. Due to the PHP/GD implementation, PHPlot uses clockwise angles (360-A), so the start_angle is greater than the end_angle, and the segment is drawn clockwise from the end_angle to the start_angle.

HTML image maps do not support ellipse section shapes directly. Therefore, the callback function has to approximate the area using one or more polygons.

The method shown in the example linked below approximates the pie segment area using a polygon with one point at the pie center, one point at each end of the arc, and zero or more points along the arc , such that the maximum separation of points along the circumference is no more than 20 degrees. This has been found to produce a good fit for image maps. More details on the method can be found in the example.

Once you have your points (converted to integers, in an array `$points` with X and Y values alternating), you can generate a line in the image map as follows. This example appends the image map line to a string.

    $coords = implode(',', $points);
    $image_map .= "  <area shape=\"poly\" coords=\"$coords\""
               .  " title=\"$title_text\" alt=\"$alt_text\" href=\"$url\">\n";

The `$url`, `$title_text`, and `$alt_text` would typically depend on the passed `$row`.

Refer to Section 5.45, “Example - Image Map from Pie Chart” for a complete example of an image map for a pie chart.

#### 4.10.1.6. Image Maps from Points and Linepoints Plots

With plot types points and linepoints, an image map can be produced which indicates the area around each point. The lines in a linepoints plot are not part of the image map areas. This also works with error plots that use these plot types, however the error bars are not part of the image map areas.

For points and linepoints plots, the `data_points` callback has this form:

    function my_handler($img, $passthru, $shape, $row, $column, $x, $y)

The first 2 arguments are standard for all PHPlot callbacks and are not described here. The next 3 arguments are common to all data_points callbacks, and there are 2 additional arguments:

$shape

  Always `dot`, indicating a single point.

$row

  The row is the index for the independent variable X. The first X value has index 0.

$column

  The column is the index for the dependent variable Y. For the first (or only) dataset for each X, the column index is 0.

$x, $y

  Device coordinates of the center of the point marker.

Generating an image map for points and linepoints plots is straight-forward. PHPlot provides only the center coordinates for each point marker. It does not indicate the shape or size of the marker, nor the coordinates of any line segments or error bars. To generate an image map, you should use a fixed radius size and define the image map areas as circles with that radius centered around each data point. You need to choose a radius. A larger radius provides a larger clickable area, but the area of adjacent points may overlap.

Here is an example of generating one area in an image map from a points or linepoints plot. You must provide the URL, alternate text, and optionally a title (tooltip text). This appends the image map line to a string. sprintf() is used to convert the coordinates to integers for cleaner HTML. This example uses a 20 pixel radius for the areas around each data point.

    define('MAP_RADIUS', 20); // Capture area circle radii
    $coords = sprintf("%d,%d,%d", $x, $y, MAP_RADIUS);
    $image_map .= "  <area shape=\"circle\" coords=\"$coords\""
               . " title=\"$title_text\" alt=\"$alt_text\" href=\"$url\">\n";

The `$url`, `$title_text`, and `$alt_text` would typically depend on the passed `$row` and `$column`.

Other than the above code, a script to generate an image map for a points or linepoints plot would be similar to Section 5.44, “Example - Image Map from Bar Chart”, which produces a bar chart.

### 4.10.2. Image Maps - data_points Callback Parameter Summary

The following table contains a summary of the `data_points` callback parameters for each supported plot type.

Plot Type(s) | Callback Parameters / Notes
--- | ---
bars, stackedbars | $img, $passthru, $shape='rect', $row, $column, $x1, $y1, $x2, $y2
Image map area does not include shading.
boxes | $img, $passthru, $shape='rect', $row, 0, $x1, $y1, $x2, $y2
Rectangle shape includes box and whiskers. It does not include any outliers.
bubbles | $img, $passthru, $shape='circle', $row, $column, $x, $y, $diam
x,y is center. Use diam/2 for radius in image map circle area.
candlesticks, candlesticks, ohlc | $img, $passthru, $shape='rect', $row, 0, $x1, $y1, $x2, $y2
Rectangle shape includes body, wicks, ticks of each candlestick or OHLC marker.
pie | $img, $passthru, $shape='pie', $row, 0, $x, $y, $width, $height, $start_angle, $end_angle
Callback needs to fit a polygon to the ellipse segment.
points, linepoints | $img, $passthru, $shape='dot', $row, $column, $x, $y
x,y is center. Supply a radius for image map circle areas. Image map area will cover the points only, not lines.

### 4.10.3. Image Maps - Implementation Notes and Limitations

Since most PHPlot scripts will not produce image maps, the burden of converting data points into a format for HTML image maps was left to the implementation in the callback function. This is why PHPlot passes the diameter values it already calculated (instead of radius values), and why pie chart segments must be interpolated by the callback function.

You can generate image maps for error plots (data types data-data-error and data-data-yx-error) with points and linepoints plot types, but the image map areas will not include the error bars. For these plot types, the only the coordinates of the data points are provided.

PHPlot does not provide the data values from the data array that go with the points. If you need these values, for example in tooltips, your callback function needs to get them from the data array, using the $row and $column index values. This may be complex for pie charts (for example, if you want tooltip text to show the percentage value of the pie segment). Section 5.45, “Example - Image Map from Pie Chart” shows access to data values for a pie chart in the simple case of data type `text-data-single`. Section 5.46, “Example - Image Map and Non-embedded Plot Image” shows access to data values for a bar chart.

For OHLC plots (candlesticks, candlesticks2, and ohlc plot types), and for box plots, PHPlot does not provide the callback with the coordinates of individual features (such as the candlestick body rather than the high point wick). PHPlot only provides the bounding box rectangle for the overall data point graphic.

The image map must be located in the same HTML file as the image reference. Although the HTML definition of the `usemap` attribute of the `<img>` tag seems to indicate that a URL to an external file containing the map may be used, this does not in fact work.

### 4.10.4. Image Maps with Non-embedded Image Data

It is also possible to generate an image map when the PHPlot script produces an image in the normal way (not embedded) and returns it to the browser as image data. But the script will need to run twice: once to generate the PHPlot image, and once to generate the containing HTML page with the image map. (You can use two separate scripts instead, but this is not recommended, since both operations must create identical plots so the image map areas correspond to the plot areas.)

In the following example, the script normally generates an HTML page. The page contains an image map, generated with PHPlot, and also a `<img>` image tag which points back to the same script to have it generate the plot image. When requesting the image, the script adds a parameter 'mode=plot' to the URL. This tells the second execution of the script to generate the image data instead of the HTML page.

The obvious drawback to this method is that you are processing a complete plot twice each time a plot is needed. The first time, only the image map is needed, and the plot itself is discarded. This is inefficient, especially if the plotting script needs to query a database or perform extensive calculations.

Another concern is if the script queries a database, the data could change between the two uses of the script, resulting in an image map and plot which do not correlate.

The rest of this section contains selected, annotated code from Section 5.46, “Example - Image Map and Non-embedded Plot Image”.

Start by checking for the mode parameter:

    # Produce an image if the URL has mode=plot, and an HTML page otherwise:
    $do_html = empty($_GET['mode']) || $_GET['mode'] != 'plot';

The callback handler is the same as the other imagemap examples, in that it appends to the global string $image_map one line from the image map.

    # Callback for 'data_points' : Generate 1 line in the image map.
    function store_map($im, $data, $shape, $row, $col, $x1, $y1, $x2, $y2)
    { ... }

The `generate_html()` function creates the containing HTML page. Only parts of the code are shown.

    function generate_html()
    {
        global $image_map;

Create a self-referencing URL with mode=plot parameter for the `<img>` tag:

        # If the URL already has parameters, use & separator, else ?.
        $sep = empty($_SERVER['QUERY_STRING']) ? '?' : '&';
        $url = htmlspecialchars($_SERVER['REQUEST_URI'] . $sep .  'mode=plot');

Now generate the HTML page. Include the image map using the global string `$image_map`, which our callback function has built line-by-line as PHPlot produced the plot. Also include the reference to the plot image. This will result in the browser making a second request to the script, this time with the mode=plot parameter.

        echo <<<END
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
         "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    ...
    <map name="map1">
    $image_map
    </map>
    ...
    <img src="$url" alt="Plot image" usemap="#map1">
    ...
    </html>

    END;
    }

This ends the `generate_html()` function.

In the main body of the script, create a PHPlot object and configure the plot as usual. Set the `data_points` callback. (You need only do this in the case of generating HTML, not the image case.) There are two other places where the operation differs for the HTML or image generation, based on the `$do_html` flag: disabling automatic output with SetPrintImage, and calling the `generate_html()` function at the end.

    $plot = new PHPlot(800, 600);
    if ($do_html) {
        // Do not output the image in this mode:
        $plot->SetPrintImage(False);
        // Set the callback for image map generation:
        $plot->SetCallback('data_points', 'store_map');
    }
    ... // Set up the plot, data values, plot type, etc.
    // Output the image (in plot mode), or build the image map (in html mode):
    $plot->DrawGraph();
    if ($do_html) generate_html();

That's all. If `$do_html` is true, no image will be produced (due to `SetPrintImage(False)`), and `generate_html()` will be called. If `$do_html` is false, `DrawGraph()` will output the plot image, and the map data will be not be produced or output.

Prev | Up | Next
4.9. Streaming Plots | Home | Chapter 5. PHPlot Examples