DBD::Chart 0.51 - Perl DBI Driver abstraction for rendering charts and graphs
Author: By Dean Arnold
Description: DBD::Chart Reference and User Guide.
Keywords: Chart, graph, chart, Perl, perl, DBD, DBI, PNG, GD

## DBD::Chart - Perl DBI Driver interface For Rendering Charts and Graphs

- SYNOPSIS
  - Pie Chart
  - 3-D Bar Chart
  - Point Graph
  - Multirange Linegraph with Logo and Signature
  - Multirange Areagraph
  - Log-Log Linegraph
  - Candlestick Chart
  - Multirange Symbolic Linegraph
  - Box & Whisker Chart with Imagemap
  - Iconic Barchart with Imagemap
  - Lots more examples...
- DESCRIPTION
- VERSION
- CHANGE HISTORY
- DRIVER-SPECIFIC BEHAVIOR
  - DATA-SOURCE NAME
  - DATA TYPES
  - SQL DIALECT
    - CREATE
    - DROP
    - INSERT
    - SELECT
    - UPDATE
    - DELETE
  - IMAGEMAPS
  - ERROR HANDLING
  - DIAGNOSTICS
  - DRIVER-SPECIFIC ATTRIBUTES
  - DRIVER-SPECIFIC FUNCTIONS
- PREREQUISITES AND CONFORMANCE
- KNOWN BUGS
- TO DO List
- ACKNOWLEDGEMENTS
- REFERENCES
- COPYRIGHT

## SYNOPSIS

### Pie Chart

    use DBI;
    my $dbh = DBI->connect('dbi:Chart:');
        or die "Cannot connect\n";
    #
    #    example: create a pie chart
    #
    $dbh->do('CREATE TABLE pie (region CHAR(20), sales FLOAT)');
    $sth = $dbh->prepare('INSERT INTO pie VALUES( ?, ?)');
    $sth->execute('East', 2756.34);
    $sth->execute('Southeast', 3456.78);
    $sth->execute('Midwest', 1234.56);
    $sth->execute('Southwest', 4569.78);
    $sth->execute('Northwest', 33456.78);

    $rsth = $dbh->prepare(
    "SELECT PIECHART FROM pie
     WHERE WIDTH=400 AND HEIGHT=400 AND
     TITLE = \'Sales By Region\' AND
     COLOR=(red, green, blue, lyellow, lpurple) AND
     BACKGROUND=lgray AND
     SIGNATURE=\'Copyright(C) 2001, GOWI Systems, Inc.\'");
    $rsth->execute;
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### 3-D Bar Chart

    #
    # multi-range 3-D bar chart
    #
    $dbh->do('CREATE TABLE bars (quarter SMALLINT, East FLOAT, '.
    'Southeast FLOAT, Midwest FLOAT, Southwest FLOAT, Northwest FLOAT)');
    $sth = $dbh->prepare('INSERT INTO bars VALUES(?, ?, ?, ?, ?, ?)');
    $sth->execute(1, -2756.34, 3456.78, 1234.56, -4569.78, 33456.78);
    $sth->execute(2, 2756.34, 3456.78, 1234.56, 4569.78, 33456.78);
    $sth->execute(3, 2756.34, 3456.78, -1234.56, 4569.78, 33456.78);
    $sth->execute(4, 2756.34, -3456.78, 1234.56, 4569.78, 33456.78);

    $rsth = $dbh->prepare(
    "SELECT BARCHART FROM bars
    WHERE WIDTH=600 AND HEIGHT=400 AND X-AXIS=\'Quarter\' AND
    Y-AXIS=\'Revenue\' AND TITLE = \'Quarterly Revenue By Region\' AND
    3-D=1 AND SHOWVALUES=1 AND COLOR=(red, green, blue, yellow, dbrown)");
    $rsth->execute;
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### Point Graph

    #
    # scatter graph
    #
    $dbh->do('CREATE CHART line (Month SMALLINT, sales FLOAT)');
    $sth = $dbh->prepare('INSERT INTO line VALUES( ?, ?)');
    $sth->execute(1, 2756.34);
    $sth->execute(2, 3456.78);
            ...insert some more rows.....
    $sth->execute(12, 90.57);

    $rsth = $dbh->prepare(
    "SELECT POINTGRAPH FROM line
    WHERE WIDTH=500 AND HEIGHT=300 AND X-AXIS=\'Sales\' AND
    TITLE = \'Sales By Region\' AND COLOR=black AND SHOWGRID=0 AND
    SHAPE=filldiamond AND SHOWVALUES=1");
    $rsth->execute;
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### Multi-range Linegraph, with Logo and Signature

    #
    # multi-range line w/ points, bkground image, and signature
    #
    $dbh->do('DROP CHART line');
    $dbh->do('CREATE CHART line (Month SMALLINT, East FLOAT, ' .
    'Southeast float, Midwest float, Southwest float, Northwest float)');
    $sth = $dbh->prepare('INSERT INTO line VALUES( ?, ?, ?, ?, ?, ?)');
    $sth->execute(1, 2756.34, 3456.90, 1234.99, 1005.34, 2876.34);
    $sth->execute(2, 3456.78, undef, 4321.25, 9001.34, 997.68);
            ...insert some more rows.....
    $sth->execute(12, 90.57,3456.90, 1234.99, undef, 2876.34);

    $rsth = $dbh->prepare(
    "SELECT LINEGRAPH FROM line
    WHERE WIDTH=? AND HEIGHT=? AND X-AXIS=? AND Y-AXIS=? AND
    TITLE = \'Monthly Sales By Region\' AND
    COLOR=(red, green, blue, yellow, lbrown) AND
    SHOWPOINTS=1 AND SHOWGRID=1 AND
    SHAPE=(fillcircle, fillsquare, filldiamond, horizcross, diagcross) AND
    LOGO=\'gowilogo.png\' AND BACKGROUND=lgray AND
    X-ORIENT=\'VERTICAL\' AND
    SIGNATURE=\'Copyright(C) 2001, GOWI Systems, Inc.\'");
    $rsth->execute(400, 400, 'Month', 'Sales');
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### Multi-range Area Graph

    $dbh->do('CREATE CHART line (Month SMALLINT, East FLOAT, ' .
    'Southeast float, Midwest float, Southwest float, Northwest float)');
    $sth = $dbh->prepare('INSERT INTO line VALUES( ?, ?, ?, ?, ?, ?)');

    @month = (1,2,3,4,5,6,7,8,9,10,11,12);
    @east = ( 2756.34, 3456.90, 1234.99, 1005.34, 2876.34, 3456.78, undef,
    	4321.25, 9001.34, 997.68, 1234.56, 7783.20);
    @seast = ( 5321.11, 3333.33, 876.10, 4569.78, 4326.3,  -7895.44, 4444.44,
    	12345.29, 3456.78, 12094.5, 6666.66, 3322.11);
    @midwest = ( 9090.90, 908.57, -2367.4, 3399.55, 5555.55, 887.3, 756.34,
    	1111.11, 2222.22, 8888.88, 9456.3, undef);
    @swest = ( 7783.20, 5321.11, 3333.33, 876.10, 12349.56, 12094.5, 6666.66,
    	3322.11, 9090.90, 4569.78, 3456.99, 4321.25);
    @nwest = ( 9001.34, 997.68, 13456.78, 2367.4, 3399.55, 5555.55, 887.3,
    	90.57, 3456.90, 1234.99, undef, 2876.34);

    $sth->func(1, \@month, chart_bind_param_array);
    $sth->func(2, \@east, chart_bind_param_array);
    $sth->func(3, \@seast, chart_bind_param_array);
    $sth->func(4, \@midwest, chart_bind_param_array);
    $sth->func(5, \@swest, chart_bind_param_array);
    $sth->func(6, \@nwest, chart_bind_param_array);

    %stsary = ();
    $sth->func(\%stsary, chart_bind_param_status);

    $sth->execute;

    $rsth = $dbh->prepare(
    "SELECT AREAGRAPH FROM line
    WHERE WIDTH=400 AND HEIGHT=400 AND X-AXIS=\'Month\' AND
    Y-AXIS=\'Sales\' AND TITLE = \'Monthly Sales By Region\' AND
    COLOR=(red, green, blue, yellow, lbrown) AND
    SHOWPOINTS=1 AND SHOWGRID=1 AND
    SHAPE=(fillcircle, fillsquare, filldiamond, horizcross, diagcross)");
    $rsth->execute;
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### Log-Log Linegraph

    #
    # log-log line graph
    #
    $dbh->do('CREATE CHART line (Month FLOAT, sales FLOAT)');
    $sth = $dbh->prepare('INSERT INTO line VALUES( ?, ?)');
    for ($i = -3; $i < 13; $i++) {
    	$sth->execute(5**$i, exp($i));
    }

    $rsth = $dbh->prepare(
    "SELECT LINEGRAPH FROM line
    WHERE WIDTH=450 AND HEIGHT=450 AND X-AXIS=\'5**X\' AND
    Y-AXIS=\'e**X\' AND Y-LOG=1 AND X-LOG=1 AND
    SHOWVALUES=0 AND TITLE = \'Sample Log-Log Linegraph\' AND
    COLOR=lred AND SHOWGRID=1 AND SHOWPOINTS=1");
    $rsth->execute;
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### Candlestick Chart

    #
    # simple candle graph, directly from another statement handle
    #
    $tddbh = DBI->connect('dbi:Teradata:dbc', 'dbitst', 'dbitst',
        { PrintError => 1, RaiseError => 0, AutoCommit => 1 });
    $tdsth = $tddbh->prepare(
    "SELECT TradeDay(VARCHAR(18)), lowprice, highprice
        FROM candle ORDER BY TradeDay");
    $tdsth->execute;

    $rsth = $dbh->prepare(
    "SELECT CANDLESTICK FROM ?
     WHERE WIDTH=? AND HEIGHT=? AND X-AXIS=? AND Y-AXIS=? AND
     TITLE = \'Daily Price Range\' AND COLOR=red AND SHOWGRID=1 AND
     SHAPE=filldiamond AND SHOWPOINTS=1 AND SHOWVALUES=0");
    $rsth->execute($tdsth, 300,400, 'Date', 'Price');
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### Multirange Symbolic Linegraph

    #
    #	use same data to render linegraph with symbolic domain
    #
    $tdsth->execute;

    $rsth = $dbh->prepare(
    "SELECT LINEGRAPH FROM ?
        WHERE WIDTH=400 AND HEIGHT=400 AND X-AXIS=\'Date\' AND
        Y-AXIS=\'Price\' AND TITLE = \'Daily Price Range\' AND
        COLOR=(red, blue) AND SHOWGRID=1 AND
        SHAPE=(filldiamond, fillsquare) AND SHOWPOINTS=1");

    $rsth->execute($tdsth);
    $rsth->bind_col(1, \$buf);
    $rsth->fetch;

### Multidomain Box & Whisker Chart with Imagemap

    #
    #	simple boxchart with imagemap
    #
    @x = ();
    @y = ();
    $dbh->do('CREATE TABLE samplebox (First integer, Second integer)');
    $sth = $dbh->prepare('INSERT INTO samplebox VALUES(?, ?)');
    foreach (1..100) {
    	$sth->execute($_, int($_/2)+20);
    }
    $sth = $dbh->prepare("SELECT BOXCHART, IMAGEMAP FROM samplebox
    WHERE WIDTH=500 and HEIGHT=300 AND
    	title = 'Sample Box & Whisker Chart' AND
    	signature = 'Copyright(C) 2001, Presicient Corp.' AND
    	MAPNAME = 'boxsample' AND
    	SHOWVALUES = 1 AND
    	COLORS=(red, blue) AND
    	mapURL = 'http://www.presicient.com/samplemap.pl?plotnum=:PLOTNUM&x=:X&y=:Y&z=:Z'"
    	);
    $sth->execute;
    $row = $sth->fetchrow_arrayref;

    open(PIE, '>samplebox.png');
    binmode PIE;
    print PIE $$row[0];
    close PIE;
    print MAP '<h2>Boxchart with Imagemap</h2>', "\n";
    print MAP '<img src=samplebox.png usemap="#boxsample">',
    	$$row[1], "\n";
    $dbh->do('DROP TABLE samplebox');

### Iconic Barchart With Imagemap

    #
    #	iconic barchart
    #
    my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
    my @pumpsales = (123, 100, 78, 45, 50, 70, 30, 36, 67, 234, 201, 194);
    my @turksales = (123, 70, 65, 35, 40, 70, 90, 80, 67, 134, 301, 250);
    $dbh->do('CREATE TABLE iconic (month char(3), pumpkins integer, turkeys integer)');
    my $sth = $dbh->prepare('INSERT INTO iconic VALUES(?, ?, ?)');
    for (my $i = 0; $i <= $#months; $i++) {
    	$sth->execute($months[$i], $pumpsales[$i], $turksales[$i]);
    }
    $sth = $dbh->prepare("SELECT BARCHART, IMAGEMAP FROM iconic
    WHERE WIDTH=820 and HEIGHT=500 AND
    	title = 'Monthly Pumpkin vs. Turkey Sales' AND
    	signature = 'Copyright(C) 2001, Presicient Corp.' AND
    	X-AXIS = 'Month' AND
    	Y-AXIS = 'Sales' AND
    	icons = ('pumpkin.png', 'turkey.png' ) AND
    	keepOrigin = 1 AND
    	SHOWGRID = 1 AND
    	MAPNAME = 'pumpkins' AND
    	MAPURL = 'http://www.presicient.com/samplemap.pl'"	);

    $sth->execute;
    my $row = $sth->fetchrow_arrayref;

    open(BAR, '>iconbar.png');
    binmode BAR;
    print BAR $$row[0];
    close BAR;
    print MAP '<p><h2>Iconic Barchart with Imagemap</h2>', "\n";
    print MAP '<img src=iconbar.png usemap="#pumpkins">',
    	$$row[1], "\n";
    $dbh->do('DROP TABLE iconic');

## DESCRIPTION

DBI driver abstraction for rendering pie charts, bar charts, box & whisker charts, line, point, area, and candlestick graphs. The default output format is PNG; JPEG, or GIF format can be generated by setting the FORMAT property (see below), assuming the appropriate supporting libraries and modules are installed.
BE ADVISED: This is BETA software, and subject to change at the whim of the author(s).

Why DBD::Chart ? Basically, the idea is to make chart rendering easy for us database geeks...and maybe for other folks, as well. Being able to render a chart from a rowset by simply binding output column buffers as input parameter buffers for a simple INSERT, then just SELECT'ing to get the image, seemed like a nice abstraction.

BTW: This driver is 100% pure Perl.

## CURRENT VERSION

Release 0.51

ZIP version
.tar.gz version

## CHANGE HISTORY

Release 0.51:

- 3-D piechart support
- multicolor, single range barcharts

Release 0.50:

- remove dependencies on GD::Graph (ie., added internal piechart, barchart rendering in DBD::Chart::Plot)
- added iconic barcharts and datapoints (ie., use small images instead of solid bars/points)
- 3-D, 3 axis barcharts (X, Y, Z datapoints)
- support for imagemap hotspot generation (i.e., SELECT LINEGRAPH, IMAGEMAP FROM...)
- added box&whisker charts
- moved logo processing from DBD::Chart to DBD::Chart::Plot
- bug fix for symbolic domain areagraphs
- bug fix for escaping single quotes inside a string

Release 0.43:

- fix to support GIF via older GD packages (many thanks to Peter Scott!)
- other cosmetic fixes

Release 0.42:

- fix to support X-ORIENT='HORIZONTAL' on symbolic domains, candlesticks

Release 0.41:

- fix to strip quotes from string literal in INSERT statement
- fix for string literal column index variable in prepare of INSERT
- fix for Y-axis tick alignment when no grid is requested

Release 0.40:

- fix for DECIMAL, INTEGER, etc. last columns in CREATE TABLE
- fix for FORMAT property to properly handle as string value
- added Y-MAX, Y-MIN properties to control Y-axis min/max values for barcharts

Release 0.30:

- strip newlines from SQL for prepare()
- add BACKGROUND property to set background color, incl. transparent background
- add FORMAT property to select PNG or JPEG
- add X-ORIENT property to set X-tick label orientation
- add LOGO property to set a background image
- add SIGNATURE property to set a signature string in image
- add placeholder support in SELECT WHERE clause
- add KEEPORIGIN property to force (0,0) in the graph
- auto-skip symbolic X-axis vertical tick labels when they overlap
- add parameterized chart datasource (i.e., SELECT BARCHART FROM ? WHERE...)

Release 0.20:

- added support for 3-D bar and pie charts (via GD::Graph3d)
- added logarithmic line/point graph support
- added area graphs
- added candlestick charts (e.g., for daily trading range charts)
- added support for non-numeric domain values
- packaged for CPAN

Release 0.10:

- Coded; first alpha release

## DRIVER-SPECIFIC BEHAVIOR

### DATA-SOURCE NAME

The dsn string passed to `DBI->connect()` is simply `'dbi:Chart:'`. No username or password is required.

### DATA TYPES

For purposes of this discussion, data types are assigned to the following classifications:

Type Class | Data Types
--- | ---
| Numeric | INTEGER, SMALLINT, TINYINT, FLOAT, DECIMAL | Symbolic | CHAR, VARCHAR

The various type classes are applied as follows:

- Range (i.e., Y-axis) values must be defined as numbers.
- INTEGER, FLOAT, SMALLINT, TINYINT, and DECIMAL are all acceptable numeric types.
- Domain (i.e., X-axis, Z-axis for barcharts) values may any type class (numeric or symbolic).
- A symbolic domain will result in a uniformly distributed mapping of values to the associated axis.
- For piecharts and barcharts, all domain types are treated as symbolic.
- For line, point, and area graphs:
  - a numeric domain will be mapped using the scaled numeric values.
  - a symbolic domain will result in a uniformly distributed mapping to the associated axis.
- Box & whisker charts require a numeric domain.

Note that literal strings are specified with single quotes. Literal strings containing single quotes can escape the quotes using two consecutive quotes, e.g.

    'Literal strings can''t avoid escapes!'

### Date, Time, Timestamp, and Interval Types

DATE, TIME, and TIMESTAMP types are currently handled as symbolic domain values. Better support for these types is planned for the next release.

Escape clause formatting (i.e., '{d mm/dd/yyy}') will be supported in a future release.

### SQL DIALECT

DBD::Chart uses a small subset of SQL to create, populate, render, and discard chart data:

- `CREATE { TABLE | CHART } chartname ( <domain-definitions> )`

  Creates a chart object that can be populated with datapoints and subsequently rendered. `<domain-definitions>` is a list of column definitions which must follow these rules:

  For pie charts:

  1. no more than 2 columns should be defined; extra columns will be ignored when the chart is rendered.
  2. the 1st column contains the text of label applied to the associated wedge of the pie.
  3. the 2nd column must be numeric and defines the domain values to be plotted.

  For bar charts:

  1. for 2 axis barcharts:
     - at least 2 columns must be defined
     - the 1st column contains the text label printed along the horizontal axis for each bar (if only a single domain column is defined) or group of bars (if more than 1 domain column is defined).
     - the remaining columns must be numeric. When more than 1 domain column is defined, the column values are plotted in groups by the associated label, i.e., all domains for each row are plotted in a group.
  2. for 3 axis barcharts:
     - 3 columns must be defined
     - the 1st column contains the text label printed along the X (i.e., horizontal) axis for each bar.
     - the 2nd column must be numeric and is plotted as a scaled value on the Y (i.e., vertical) axis.
     - the 3rd column contains the text label printed along the Z (i.e., depth) axis for each bar.

  For line, area, or point graphs:

  1. at least 2 columns must be defined.
  2. the 1st column defines the X-axis values for each row to be plotted (i.e., the "domain"), which may be of any type. Note that non-numeric domain types are handled symbolicly, as described above.
  3. each additional column is used as a Y-axis value for a distinct plot line or point-set within the rendered image (i.e., multiple ranges may be plotted against a single domain in a single graph).
  4. Y-axis values may be NULL, in which case the corresponding (X, Y) plot point will be omitted from the associated line or pointset.
  5. numeric domain datasets do not need to be INSERT'ed in order; the charting engine will automatically sort the domain values into ascending order. Non-numeric domains will be plotted in the same order as they are INSERT'd.

  For candlestick graphs:

  1. at least 3 columns must be defined.
  2. the 1st column defines the X-axis values for each candlestick to be plotted, which may be of any type.
  3. the 2nd column must be numeric, and is used as the minimum (bottom) value of the candlestick.
  4. the 3rd column must be numeric, and is used as the maximum (top) value of the candlestick.
  5. multiple sets of candlesticks can be plotted in the same graph by defining additional (minimum, maximum) columns.

  For box & whisker graphs:

  1. each defined column represents a range of values from which the median and quartile values will be computed and plotted. Multiple columns result in multiple box&whiskers within the same graph stacked from bottom to top.
  Column qualifers (e.g., NOT NULL, CASESPECIFIC, etc.) are not supported.

- `DROP { TABLE | CHART }chartname`

  Discards the specified chart context information. Any open statement handles which attempt to manipulate the chart after it has been dropped will return errors.

- `INSERT INTO chartname VALUES ( <? | NULL | literal> [, ...] )`

  Populates the chart with the specified data. A value must be provided for each column defined in the chart (i.e., no defaults are used.).

- `SELECT <chart-type> [, IMAGEMAP ]
  FROM ? | <chartname>
  WHERE <qualifier> = <? | literal | literallist> [AND ...]`

  Renders the image(s) from the specified chart or DBI statement handle, using the <qualifer>s to control how the image is rendered. When IMAGEMAP is included in the column list, text is generated for either

  - an HTML client-side imagemap
  - a Perl compatible array of hashrefs of value and coordinate attributes
  Various <qualifier>s from the WHERE clause provide base URL or scripting tags to be associated with the imagemap. See IMAGEMAPS below for details.

  When any of the various `$sth->fetch()` operations is applied to the SELECT statement:

  - For PNG, JPEG, or GIF formats, images are returned as VARBINARY objects representing the binary image data.
  - Imagemaps are returned as VARCHAR objects containing the HTML imagemap text.

  Valid <chart-type> values are

  - PIECHART - generates a piechart; each wedge is represented as a percentage of the sum of all the domain values. Negative domain values result in an error.
  - BARCHART - generates a barchart; each bar is represented as a percentage of the largest value in the domain. Negative values are supported.
  - BOXCHART - generates a box & whisker chart, plotting a box bounded by the upper and lower quartile values, with a vertical line drawn through the median value, and horizontal lines drawn from the sides of the box to the lower/upper extremes. Extremes are limited to 1.5 interquartiles from each side of the box. Outliers (i.e., values beyond the lower/upper extremes) are plotted as filled diamonds.
  - LINEGRAPH - generates a linegraph
  - AREAGRAPH - generates an areagraph (i.e., the area between plotline and X-axis is filled with the plot color).
  - POINTGRAPH - generates a pointgraph (i.e., scatter-graph)
  - CANDLESTICK - generates a candlestick graph

  The following qualifiers are allowed:

  Qualifier | Description | Default Value | Restrictions
  --- | --- | --- | ---
  WIDTH | sets the image width in pixels | 400 | single value only
  HEIGHT | sets the image height in pixels | 400 | single value only
  SHOWGRID | when set to 1, causes the background grid of all charts/graphs except piecharts and box&whisker charts to be displayed | 0 | single value only, valid values are 0 and 1.
  COLOR (synonym: COLORS) | sets the color of chart elements; may be multivalued, in which case each wedge(piechart), bar(barchart, histogram), box&whisker, line(linegraph), area(areagraph), pointset(scattergraph), or candlestick-set uses the next color in the list. Valid color values are `white, lgray, gray, dgray, black, lblue, blue, dblue, gold, lyellow, yellow, dyellow, lgreen, green. dgreen, lred, red, dred, lpurple, purple, dpurple, lorange, orange, pink, dpink, marine, cyan, lbrown, dbrown.` | black | The colorlist wraps if more range valuesets are defined than colors. Ignored for iconic barcharts/histograms
  ICON (synonym: ICONS) | sets an icon image to be used to render the bars for barcharts, or datapoints for line, point, area, and candlestick graphs. The number of icons per bar is based the ratio of the icon pixel height to the the maximum image pixel height(for barcharts). Icon images may be clipped proportionally to completely fill bars of barcharts. When multiple range values are defined per domain, and a list of icons is provided, each range in a cluster of bars will be rendered with a different icon, selected in order, from the provided list. | None. | String name of a compatible format image file (PNG, JPEG, GIF). Not valid for piecharts. May be multivalued. Icon list wraps if more ranges are defined than icons.
  SHAPE (synonym: SHAPES) | sets the shape of points for line, area, point, or candlestick graphs; may be multivalued. Valid values are `fillsquare, opensquare, horizcross, diagcross, filldiamond, opendiamond, fillcircle, opencircle, icon.` Default none. | fillcircle | An icon shape requires one or more icon files to be specified with the ICON attribute.
  SHOWPOINTS | for line, area, and candlestick graphs, determines whether datapoints are explicitly rendered | 1 if the SHAPE attribute has been specified, otherwise 0 | single value only. Ignored for pie and bar charts, and pointgraphs. Valid values are 0 and 1.
  SHOWVALUES | for barcharts, box&whisker charts, line, area, point, and candlestick graphs, determines whether the datapoint values are displayed. When set to 1, the (X,Y) values are displayed just above the plotted datapoint for line, area, and point graphs; for candlesticks, the minimum and maximum Y values are plotted just above and below each candlestick. For barcharts, the Y axis value of each bar is displayed. FOr box & whisker charts, the median and lower and upper quartile values are displayed. | 0 | single value only, valid values are 0 and 1, ignored for pie charts.
  X-LOG | for line, area, point, and candlestick graphs, causes values along the X-AXIS to be plotted in log10 form; | 0 | All domain values must be > 0 when X-LOG is enabled.
  Y-LOG | for barchart, line, area, point, and candlestick graphs, causes values along the Y-AXIS to be plotted in log10 form; | 0 | All range values must be > 0 when Y-LOG is enabled.
  X-AXIS | sets the label string on the X-AXIS of line, area, point, and candlestick graphs. | 'X-Axis' | Single string value
  Y-AXIS | sets the label string on the Y-AXIS. | 'Y-Axis' | Single string value; ignored for piecharts and box&whisker charts
  Z-AXIS | sets the label string on the Z-AXIS. Also directs plotting engine to render true 3 axis barchart. | 'Z-Axis' | Single string value; valid for barcharts only, ignored for all others
  TITLE | sets the title string of the graph. | None. |
  3-D | sets the 3-D effect on pie and bar charts. | 0 |
  BACKGROUND | sets the background color | white | single value only, from list of legal colors or `transparent`.
  TEXTCOLOR | sets the color of text in the image. | black | Single value from the list of valid colors.
  GRIDCOLOR | sets the color of the grid in the image. | black | Single value from the list of valid colors.
  LOGO | sets a background image; default none, single value only. Accepts a filename (optionally including path info) of an image file of either PNG, JPEG, or GIF format. The image will be centered under the graph image. | None. | If the image size is less than the defined specified WIDTH and/or HEIGHT, the BACKGROUND color will be used to fill to the edges. If the image exceeds the WIDTH and/or HEIGHT, the image will be clipped to fit.
  SIGNATURE | sets a signature string to be printed in tiny font in the lower right hand corner of the image. E.g. "Copyright(C) 2001, GOWI Systems. All rights reserved.". | None. | single value, text string only, default none.
  FORMAT | sets the output image format, either PNG, JPEG, or GIF | PNG | Single value, string, either 'PNG','JPEG', 'GIF' (case insensitive). Some formats require additional support libraries (See PREREQUISITE SOFTWARE below).
  X-ORIENT | sets the display angle of the X-axis tick labels | Horizontal | single value, case-insensitive string, 'horizontal' or 'vertical'
  KEEPORIGIN | forces the origin axes (0,0) in the image. Normally, bar, line, point, area, and candlestick graphs automatically clip away the origin axes if the plot does not cross the origin axis. Set this property to 1 to force the origin axis to be included. | 0 | single value, either 0 or 1. Ignored for piecharts.
  MAPTYPE | set the type of imagemap | HTML | Single string value either 'HTML' or 'Perl'
  MAPNAME | set the name of the map generated for HTML imagemaps | 'plot' | Single string value; only alphanumerics or '_' allowed.
  MAPURL | sets the base URL for HTML IMAGEMAPs. | None | Single string value of standard URL form. E.g., 'http://www.presicient.com/procimg.pl?func=magic&plotnum=:PLOTNUM&X=:X&Y=:Y'. If not given, and IMAGEMAP is requested, the map will be generated with NOHREF tags. The following special variable names will be interpolated with their literal values within the URL string: :PLOTNUM - the ordinal number of the plot within the image, starting from 0. (E.g., a line graph with multiple ranges would have multiple plots). :X - the X-value of the datapoint for line/point/area/candlestick graphs, the domain label for barcharts, or the wedge label for piecharts :Y - the Y-value of the datapoint for line/point/area/candlestick graphs and barcharts, or the value associated with the wedge label for piecharts :Z - not supported for line/point/area/candlestick graphs and 2-axis barcharts; the Z-axis value label for 3-axis barcharts, or the percentage value of the associated wedge for piecharts.
  MAPSCRIPT | set the text of a client-side scripting tag to be included in HTML imagemaps. E.g., 'ONCLICK="alert(\'Got (:X,:Y) for plot :PLOTNUM\')"' | None. | Single string value of a valid scripting tag. Special variable name interpolation is same as for MAPURL.

  General Restrictions:

  - no expressions (e.g., X + Y) or functions (e.g., AVG(X)) are allowed.
  - ordering of wedges and bars in pie and barcharts is determined by the order the rows are INSERTed.
  - Ordering of plot points in line, area, and point graphs with numeric domains is ascending left to right on the X-axis, ascending bottom to top on Y-axis. Graphs with non-numeric domains are plotted in the order they are INSERT'd.
  - When generating area graphs with multiple range valuesets (i.e., more the 1 set of Y values), the order in which the range valuesets are plotted is column 2, column 3,...column N. This order may cause some ranges to be completely obscured by the areagraph of a succeding range. You'll need to experiment with the order of your range valuesets to get the best view.
  - Datasources for the chart may be either
    - a table explicitly CREATEd on the dbi:Chart database handle that has been populated via INSERTs
    - a valid DBI statement handle which has been `execute()`'d. When a parameterized FROM is specified in a SELECT statement, the application must bind a `prepare()`'d and `execute()`'d statement handle from any valid DBI data source, from which DBD::Chart will subsequently `fetch()` the data for populating the chart. In that case, the application does not need to explicitly CREATE and INSERT to a table for the chart. Obviously, the application must still be careful that the column data returned by the bound statement handle is of the proper format (as described above) and does not returned an excessive number of rows - DBD::Chart currently generates an error if more than 1,000 rows is returned by such a bound statement handle.
  - Setting the FORMAT to JPEG on Windows platforms may be problematic. The PPM of the GD package provided by ActiveState does not appear to include the jpeg-6b library, and the Makefile for the jpeg-6b library only builds a static library, rather than a DLL. To render JPEG format graphics requires building the jpeg library and then building the libgd package to include JPEG support.
  - Support for GIF image formats requires a compatible version of the GD modules (pre 1.20).

- `UPDATE chartname
  SET <domain-name> = <? | literal>
  [ WHERE <domain-value> <operator> <? | literal>]`

  Replaces the point with the specified value with a new point value. Valid <operator>s are <, <=, =, >, >=, <>. E.g., this could be used with a bar chart to refresh the bar values in realtime (e.g., monitor User's CPU usage).

- `DELETE FROM chartname
  [ WHERE <domain-name> <operator> <? | literal>]`

  Removes one (or more) data points from the chart. Valid <operator>s are <, <=, =, >, >=, <>. E.g., this could be used to render realtime scrolling linegraphs where old values are rolled off the left of the graph, and new values are appended on the right.
  NOTE:Deleting from a barchart, then inserting new rows, will cause new rows to be displayed at the right end of the chart. Use UPDATE if you want to modified the bar values, but maintain the original display order.

### IMAGEMAPS

Imagemaps can be generated by including the `IMAGEMAP` column as the 2nd field in the SELECTed fieldlist. HTML client-side imagemaps are generated if the `MAPTYPE` qualifier is 'HTML', or if no qualifier is provided. A Perl compatible array of hashrefs of attributes and coordinates is provided if the `MAPTYPE` qualifier is 'PERL'.

The resulting HTML imagemap will have the following behaviors based on the type of chart/graph requested, and the values specified (if any) for the MAPURL and MAPSCRIPT qualifiers:

Graph Type | Hotspot Area | ALT tag | Special Variable Values
--- | --- | --- | ---
Piechart | Polygon starting from center and connecting 10° arcs along the circumference of the wedge. | Wedge value followed by wedge percent in parentheses e.g., "1234(16%)" | :PLOTNUM = 0 :X = <wedge-label> :Y = <assoc. wedge value> :Z = <wedge's percent of total>
2-D Barchart | Complete area of each bar | Range value for the bar | :PLOTNUM = <range number of the bar> :X = <domain label for the bar> :Y = <range value for the bar> :Z = <empty-string>
3-D Barchart (including 3-axis) | Complete area of top face of each bar | Range value for the bar | :PLOTNUM = <range number of the bar> :X = <domain label for the bar> :Y = <range value for the bar> :Z = <Z-axis label value for the bar>
Line, point, area graph | 8-pixel diameter circle centered on each datapoint | (domain, range) values of the datapoint | :PLOTNUM = <range number of the plot> :X = <domain value for the datapoint> :Y = <range value for the datapoint> :Z = <empty-string>
Candlestick | 8-pixel diameter circle centered on each datapoint, both top and bottom of stick | (domain, range) values of the datapoint | :PLOTNUM = <range number of the plot> :X = <domain value for the datapoint> :Y = <range value for the datapoint> :Z = <'top' | 'bottom'> depending on which endpoint of candlestick is focused.
Box & Whisker | the area of the plotted box, and an 8-pixel diameter circle centered on the lower and upper ends of the whicksers | median[lower quartile..upper quartile] values of the box, and the values of the lower and upper extreme datapoint | :PLOTNUM = <range number of the plot> :X = <median value> :Y = <lower quartile value> :Z = <upper quartile value>

A Perl imagemap will have the following behaviors based on the type of chart/graph requested, and the values specified (if any) for the MAPURL and MAPSCRIPT qualifiers:

Graph Type | Attributes & Values
--- | ---
`shape` | `coordinates` | `plotnum` | `X` | `Y` | `Z`
Piechart | POLY | arrayref of (x,y) image pixel coordinates of polygon starting from center and connecting 10° arcs along the circumference of the wedge. | 0 | wedge label | associated wedge value | wedge's percent of total
2-D Barchart | RECT | arrayref of (x,y) image pixel coordinates of rectangle of associated bar | range number of the bar | domain label | range value | undef
3-D Barchart (including 3-axis) | POLY | arrayref of (x,y) image pixel coordinates of top face of associated bar | range number of the bar | domain label for the bar | range value for the bar | Z-axis label value for the bar
Line, point, area graph | CIRCLE | arrayref of (xcenter, ycenter, radius) image pixel coordinates of 8-pixel diameter circle centered on the datapoint | range number of the plot | domain value for the datapoint | range value for the datapoint | undef
Candlestick | CIRCLE | arrayref of (xcenter, ycenter, radius) image pixel coordinates of 8-pixel diameter circle centered on each datapoint, both top and bottom of stick | range number of the plot | domain value for the datapoint | range value for the datapoint | 'top' | 'bottom', depending on which candlestick endpoint is focused.
Box & Whisker | RECT, CIRCLE | arrayref of (x,y of upper left of box, x.y of lower right of box) image pixel coordinates of the box | range number of the plot | median value of the box | lower quartile value of the box | Upper quartile value of the box.

### ERROR HANDLING

Any errors generated from improper SQL usage are flagged with an error value of -1, and appropriate text in the errstr. Errors emanating from DBD::Chart::Plot will be flagged in err and errstr with whatever info is returned.

### DIAGNOSTICS

DBI provides the `trace()` function to enable various levels of trace information. DBD::Chart currently doesn't add any traces to this.

### DRIVER-SPECIFIC ATTRIBUTES

- chart_noverify - when set to 1 during connect(), verification of data values with target columns is bypassed (to provide some performance improvement).

### DRIVER-SPECIFIC FUNCTIONS

The following functions are provided to optimize data movement:
Note:generalized versions of these functions are currently under consideration for addition to the DBI specification.

- `$sth->chart_bind_param_array($paramnum, \@paramary [\%attr | $typespec])`

  binds an array of parameters to the statement; the entire array of parameters will be consumed when the statement is executed.

- `$sth->chart_bind_param_status(\@stsary | \%stshash)`

  binds an array or hash to receive parameter status information when parameter array binding has been used on the statement. If the array version is used, then status for every supplied parameter tuple is returned; if a hash is used, then only the status of unsuccessful parameter tuples is reported, using the ordinal tuple number as the hashkey.

Note: array binding of output values is not supported, since SELECT only returns a single row at a time, namely, the chart image and (optionally) an imagemap.

## PREREQUISITES AND CONFORMANCE

DBD::Chart requires the following (versions are recommended only, cuz they're the version I built with...if you're feeling frisky, you can try older or newer versions.):

- Perl version 5.6.0
- DBI module 1.14.
- GD module 1.32
- GD::Text (aka GDTextUtil) module 0.80

Be advised that these modules require the following (non-Perl) libraries:

- libgd
- libpng
- zlib
- jpeg-6b (for JPEG support)

The following DBI functions are not supported:

    DBI->data_sources()
    $dbh->prepare_cached()
    $sth->table_info()
    $dbh->tables()
    $dbh->type_info_all()
    $dbh->type_info()

## KNOWN BUGS

Bug Number | Report Date | Release Reported in | Description | Status | Fix Release
--- | --- | --- | --- | --- | ---
1 | 2001-Mar-16 | 0.20 | SQL statements with newlines won't prepare() | Fixed | 0.30
2 | 2001-May-09 | 0.30 | INTEGER column definition as last column in CREATE TABLE causes an error | Fixed | 0.40
3 | 2001-May-09 | 0.30 | FORMAT property not properly handled as string property | Fixed | 0.40
4 | 2001-Jun-01 | 0.40 | Y-axis ticks not properly aligned when grid disabled | Fixed | 0.41
5 | 2001-Jun-01 | 0.40 | INSERT of string literal value kept quote mark | Fixed | 0.41
6 | 2001-Jun-01 | 0.40 | INSERT of string literal used bad column index variable | Fixed | 0.41
7 | 2001-Oct-01 | 0.41 | X-ORIENT='HORIZONTAL' didn't work with symbolic domains, candlesticks | Fixed | 0.42

## TO DO List

- temporal datatypes
- SVG support
- XML template support
- Support derived tables to layer graphs in an image
- Gantt charts ?
- surfacemaps ?
- some limited meta-data capability
- Any suggestions?

## ACKNOWLEDGEMENTS

Many thanks to all the authors of the various GD, PNG, JPEG, SVG, and zlib modules. Special thanks to all the initial victims, er, users for their comments, complaints, and suggestions.

Special thanks to Peter Scott for the GIF support and a few other fixes!

## REFERENCES

- Official DBI Site
- CPAN
- Perl.com
- SVG Reference
- Adobe Corp (for SVG viewer)
- ActiveState (for Perl software for Windows)

## AUTHOR

Dean Arnold

## COPYRIGHT

Copyright (c) 2001, Dean Arnold, USA
Affiliations:

- Presicient Corp.,
- MyLines.com,
- Homepage

Permission is granted to use this software according to the terms of the Artistic License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

I'm offering the software AS IS, and ACCEPT NO LIABILITY FOR ANY ERRORS OR OMMISSIONS IN, OR LOSSES INCURRED AS A RESULT OF USING DBD::Chart.

I reserve the right to provide support for this software to individual sites under a separate (possibly fee-based) agreement.

Last updated December 3, 2001