...
In this article, the Pentaho ChartBeans 1 project is introduced. Pentaho ChartBeans is a wrapper around existing "chart engines" (such as JFreeChart and Open Flash Chart). Wrapping these chart engines creates a single way of expressing charts.
History
Several designs were considered for Pentaho ChartBeans. The first design was based on JavaBeans and is the source from which the term "beans" derives. The proposal was for two layers of beans--one at the chart component level and one at the chart type level. At the lower level, beans would represent parts of the chart: the plot, axes, series, and titles. The higher level beans would put the pieces together to form chart types of interest to users, such as a BarChartBean
, LineChartBean
, and PieChartBean
.
The second design was based on a Document Object Model (DOM). A chart DOM is an object model that consists of elements which can have attributes and child elements. Elements have an associated namespace. The argument against the use of JavaBeans is that there are no namespaces.
In addition to the JavaBeans vs. DOM decision, it was important that the starting point for a chart be its data. The data are chart type-agnostic.
Finally, it was decided that even the chart type should be a styling issue-Core chart elements, like title and plot would go into the Pentaho ChartBeans namespace. Other, chart engine-specific elements would go into their own namespaces. For example, Open Flash Chart-specific properties would go into a "openflashchart" namespace, while JFreeChart-specific properties would go into a "jfreechart" namespace.
In addition to the JavaBeans vs. DOM decision, it was important that the starting point for a chart be its data. The data are chart type-agnostic.
Finally, it was decided that even the chart type should be a styling issue--not a structural issue. This is because the same series could be used for multiple chart types.
...
Pentaho ChartBeans uses Cascading Style Sheets (CSS) to style charts. Pentaho ChartBeans is not limited to the W3C's style attributes (although it attempts to use them where appropriate, for familiarity). By using CSS, Pentaho ChartBeans allows you to completely separate chart structure and style. You can use external style sheets and inline selectors, as well as class and style attributes. Using an external style sheet would allow an organization to create a consistent look for all of its charts.
Examples
Example from a Java Developer Perspective
Let's use Pentaho ChartBeans to render a standalone PNG image and an HTML page with an embedded Flash chart object.
Chart Data
In this example, we create a ChartTableModel
consisting of 21 rows and 3 columns. In addition, we add some row and column metadata.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
private static ChartTableModel createChartTableModel() { // 21 rows and 3 columns Object[][] dataArray = { { 5.55, 10.11, 20.22 }, { 30.33, 40.44, 50.55 }, { 31.33, 99.44, 150.55 }, { 32.33, 1.44, 30.55 }, { 34.33, 88.44, 77.55 }, { 35.33, 22.44, 54.55 }, { 36.33, 33.44, 52.55 }, { 37.33, 76.44, 54.55 }, { 38.33, 7.44, 59.55 }, { 39.33, 48.44, 56.55 }, { 40.33, 19.44, 57.55 }, { 50.33, 104.44, 36.55 }, { 60.33, 23.44, 74.55 }, { 20.33, 90.44, 80.55 }, { 60.33, 18.44, 27.55 }, { 10.33, 22.44, 97.55 }, { 20.33, 59.44, 55.55 }, { 90.33, 140.44, 22.55 }, { 100.33, 56.44, 76.55 }, { 40.33, 50.44, 50.55 }, { 60.66, 70.77, 80.88 } }; ChartTableModel data = new ChartTableModel(); data.setData(dataArray); // give names to the categories data.setColumnName(0, "budget"); data.setColumnName(1, "sales"); data.setColumnName(2, "forecast"); // give names to the series final String ROW_NAME_KEY = "row-name"; data.setRowMetadata(0, ROW_NAME_KEY, "1"); data.setRowMetadata(1, ROW_NAME_KEY, "2"); // ----- lines omitted ----- data.setRowMetadata(20, ROW_NAME_KEY, "21"); return data; } |
Chart Structure
...
The ChartBeans XML document for this example is below. Its relatively brief because our data and styling is separate from the chart structure. The elements in this document define a stylesheet reference, a chart title, the series, and the chart orientation.
...
<chart xmlns="http://reporting.pentaho.org/namespaces/charting/1.0">
<!-- external style sheet -->
<stylesheet href="theme.css" />
<!-- chart title -->
<title>Bar Chart Using Pentaho ChartBeans</title>
<!-- styling on individual series using style and class attributes -->
<series style="-x-pentaho-chart-series-type: bar; -x-pentaho-chart-bar-style: bar;" class="series1" />
<series class="series2" />
<!-- lines omitted -->
<series class="series18" />
<!-- wrap colors because there are more series than colors in the theme -->
<series class="series1" />
<series class="series2" />
<series class="series3" />
<!-- styling on plot using style attribute -->
<plot style="-x-pentaho-chart-orientation: horizontal"/>
</chart>
Chart Styling
Here is the external style sheet referenced above. Here we're using class selectors. Note the W3C standard color
property as well as a custom Pentaho ChartBeans' -x-pentaho-chart-line-width
property.
...
.series1 {
color: #2D00FF;
-x-pentaho-chart-line-width: 2px;
}
.series2 {
color: #11FFE4;
-x-pentaho-chart-line-width: 2px;
}
/* lines omitted */
.series18 {
color: #B7FFE5;
-x-pentaho-chart-line-width: 2px;
}
Generating Charts
Now let's pull all of the pieces together. First we have a main method that "boots" Pentaho ChartBeans. This reads various configuration files and otherwise readies the system for chart processing requests. Next we render one chart using the JFreeChart plugin for Pentaho ChartBeans and then we render another chart using the Open Flash Chart plugin for Pentaho ChartBeans. Note that both use the same chart document (and referenced stylesheet) as well as the same chart data.
...
public static void main(String[] args) throws Exception {
// "boot" ChartBeans
ChartBoot.getInstance().start();
// render chart using JFreeChart plugin for Pentaho ChartBeans
renderUsingJFreeChartPlugin("chartdocs/Bar.xml", createChartTableModel());
// render same chart using Open Flash Chart plugin for Pentaho ChartBeans
renderUsingOpenFlashChartPlugin("chartdocs/Bar.xml", createChartTableModel());
}
See how we specify the plugin class in the first line?
...
Chart Styling
Generating Charts
Now let's pull all of the pieces together. First we have a main method that "boots" Pentaho ChartBeans. This reads various configuration files and otherwise readies the system for chart processing requests. Next we render one chart using the JFreeChart plugin for Pentaho ChartBeans and then we render another chart using the Open Flash Chart plugin for Pentaho ChartBeans. Note that both use the same chart document (and referenced stylesheet) as well as the same chart data.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
public static void main(String[] args) throws Exception {
// "boot" ChartBeans
ChartBoot.getInstance().start();
// render chart using JFreeChart plugin for Pentaho ChartBeans
renderUsingJFreeChartPlugin("chartdocs/Bar.xml", createChartTableModel());
// render same chart using Open Flash Chart plugin for Pentaho ChartBeans
renderUsingOpenFlashChartPlugin("chartdocs/Bar.xml", createChartTableModel());
}
|
See how we specify the plugin class in the first line?
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
private static void renderUsingJFreeChartPlugin(final String chartDocFilename, final ChartTableModel chartTableModel)
throws Exception {
final IChartPlugin plugin = ChartPluginFactory.getInstance("org.pentaho.chart.plugin.jfreechart.JFreeChartPlugin");
// use the same filename as the chartDocFilename except with a different extension
String chartOutputFilename = "chartoutput/"
+ chartDocFilename.substring(chartDocFilename.indexOf(File.separatorChar), chartDocFilename.indexOf('.'))
+ ".png";
URL chartURL = new File(chartDocFilename).toURL();
ChartDocumentContext cdc = ChartFactory.generateChart(chartURL, chartTableModel);
IOutput output = plugin.renderChartDocument(cdc, chartTableModel);
OutputUtils.persistChart(output, chartOutputFilename, IOutput.OutputTypes.FILE_TYPE_PNG, 400, 400); // 400px x 400px
}
|
The Open Flash Chart example is a little more complicated because we have to embed the chart data in an HTML document. Whereas in the JFreeChart example, the bytes for the PNG image went to the chartOutputFilename, in this example, we write the Pentaho ChartBeans output to a String which contains the JSON that will configure the Open Flash Chart object when rendered by the browser.
Note: This example uses open-flash-chart-full-embedded-font.swf, found at http://www.ofc2dz.com/, which is a patched version of Open Flash Chart 2.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
private static void renderUsingOpenFlashChartPlugin(final String chartDocFilename, final ChartTableModel chartTableModel) throws Exception { final IChartPlugin plugin = ChartPluginFactory .getInstance("org.pentaho.chart.plugin.openflashchart.OpenFlashChartPlugin"); URL chartURL = new File(chartDocFilename).toURL(); ChartDocumentContext cdc = ChartFactory.generateChart(chartURL, chartTableModel); IOutput output = plugin.renderChartDocument(cdc, chartTableModel); ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(); output.persistChart(tmpOut, IOutput.OutputTypes.DATA_TYPE_STREAM, 400, 400); final String ENCODING = "UTF-8"; ByteArrayInputStream in = new ByteArrayInputStream(tmpOut.toByteArray()); IOUtils.closeQuietly(tmpOut); String openFlashChartJson = IOUtils.toString(in, ENCODING); IOUtils.closeQuietly(in); final String HTML_TEMPLATE = "<html>\n" + chartDocFilename.substring(chartDocFilename.indexOf(File.separatorChar), chartDocFilename.indexOf('.')) " <head>\n" + ".png"; <title>Bar URLChart chartURLUsing Open =Flash new File(chartDocFilename).toURL();Chart Plugin</title>\n" ChartDocumentContext cdc = ChartFactory.generateChart(chartURL, chartTableModel); + " IOutput output<script type=\"text/javascript\">window.getChartData = plugin.renderChartDocument(cdc, chartTableModel); OutputUtils.persistChart(output, chartOutputFilename, IOutput.OutputTypes.FILE_TYPE_PNG, 400, 400); // 400px x 400px } |
The Open Flash Chart example is a little more complicated because we have to embed the chart data in an HTML document. Whereas in the JFreeChart example, the bytes for the PNG image went to the chartOutputFilename, in this example, we write the Pentaho ChartBeans output to a String which contains the JSON that will configure the Open Flash Chart object when rendered by the browser.
Note: This example uses open-flash-chart-full-embedded-font.swf, found at http://www.ofc2dz.com/, which is a patched version of Open Flash Chart 2.
Code Block | |
---|---|
java | java |
title | renderUsingOpenFlashChartPlugin method | private static void renderUsingOpenFlashChartPlugin(final String chartDocFilename,function() '{' return ''{0}''; '}'</script>\n" + " </head>\n" + " <body>\n" + " <object id=\"ofco00b1c87708fe11dea97da1e1ba5b86bc\" height=\"100%\" align=\"middle\" width=\"100%\" \n" + " codebase=\"http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0\" \n" final+ ChartTableModel" chartTableModel) throws Exception { classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"> \n" final IChartPlugin plugin = ChartPluginFactory + " <param .getInstance("org.pentaho.chart.plugin.openflashchart.OpenFlashChartPlugin"); URL chartURL = new File(chartDocFilename).toURL();value=\"sameDomain\" name=\"allowScriptAccess\"/><param value=\"opaque\" name=\"wmode\"/> \n" ChartDocumentContext cdc = ChartFactory.generateChart(chartURL, chartTableModel); + " IOutput output = plugin.renderChartDocument(cdc, chartTableModel);<param value=\"open-flash-chart-full-embedded-font.swf?get-data=getChartData\" name=\"movie\"/> \n" ByteArrayOutputStream tmpOut+ =" new ByteArrayOutputStream(); <param value=\"high\" output.persistChart(tmpOut, IOutput.OutputTypes.DATA_TYPE_STREAM, 400, 400);name=\"quality\"/><embed id=\"ofce00b1c87708fe11dea97da1e1ba5b86bc\" \n" final String ENCODING =+ "UTF-8"; height=\"100%\" ByteArrayInputStream in = new ByteArrayInputStream(tmpOut.toByteArray());align=\"middle\" width=\"100%\" \n" IOUtils.closeQuietly(tmpOut); + " String openFlashChartJson = IOUtils.toString(in, ENCODING); pluginspage=\"http://www.macromedia.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" \n" IOUtils.closeQuietly(in); + " final String HTML_TEMPLATE = "<html>\n"allowscriptaccess=\"sameDomain\" bgcolor=\"#FFFFFF\" quality=\"high\" wmode=\"opaque\" \n" + " + " <head>\n" src=\"open-flash-chart-full-embedded-font.swf?get-data=getChartData\"/></object>\n" + " <title>Bar Chart Using Open Flash Chart Plugin</title></body>\n" + "</html>"; String +html " <script type=\"text/javascript\">window.getChartData = function() '{' return ''{0}''; '}'</script>\n" = MessageFormat.format(HTML_TEMPLATE, new String[] { openFlashChartJson }); String chartOutputFilename = "chartoutput/" + " </head>\n" + " <body>\n"chartDocFilename.substring(chartDocFilename.indexOf(File.separatorChar), chartDocFilename.indexOf('.')) + " <object id=\"ofco00b1c87708fe11dea97da1e1ba5b86bc\" height=\"100%\" align=\"middle\" width=\"100%\" \n".html"; + "FileUtils.writeStringToFile(new File(chartOutputFilename), html, "UTF-8"); codebase=\"http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0\" \n" + " classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"> \n" + " <param value=\"sameDomain\" name=\"allowScriptAccess\"/><param value=\"opaque\" name=\"wmode\"/> \n" + " <param value=\"open-flash-chart-full-embedded-font.swf?get-data=getChartData\" name=\"movie\"/> \n" + " <param value=\"high\" name=\"quality\"/><embed id=\"ofce00b1c87708fe11dea97da1e1ba5b86bc\" \n" + " height=\"100%\" align=\"middle\" width=\"100%\" \n" + " pluginspage=\"http://www.macromedia.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" \n" + " allowscriptaccess=\"sameDomain\" bgcolor=\"#FFFFFF\" quality=\"high\" wmode=\"opaque\" \n" + " src=\"open-flash-chart-full-embedded-font.swf?get-data=getChartData\"/></object>\n" + " </body>\n" + "</html>"; String html = MessageFormat.format(HTML_TEMPLATE, new String[] { openFlashChartJson }); String chartOutputFilename = "chartoutput/" + chartDocFilename.substring(chartDocFilename.indexOf(File.separatorChar), chartDocFilename.indexOf('.')) + ".html"; FileUtils.writeStringToFile(new File(chartOutputFilename), html, "UTF-8"); } } |
Example from an End User Perspective
Chart Data
Chart Structure
The ChartBeans XML document for this example is below. Its relatively brief because our data and styling is separate from the chart structure. The elements in this document define a stylesheet reference, a chart title, the series, and the chart orientation.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<chart xmlns="http://reporting.pentaho.org/namespaces/charting/1.0">
<!-- external style sheet -->
<stylesheet href="theme.css" />
<!-- chart title -->
<title>Bar Chart Using Pentaho ChartBeans</title>
<!-- styling on individual series using style and class attributes -->
<series style="-x-pentaho-chart-series-type: bar; -x-pentaho-chart-bar-style: bar;" class="series1" />
<series class="series2" />
<!-- lines omitted -->
<series class="series18" />
<!-- wrap colors because there are more series than colors in the theme -->
<series class="series1" />
<series class="series2" />
<series class="series3" />
<!-- styling on plot using style attribute -->
<plot style="-x-pentaho-chart-orientation: horizontal"/>
</chart>
|
Chart Styling
Here is the external style sheet referenced above. Here we're using class selectors. Note the W3C standard color
property as well as a custom Pentaho ChartBeans' -x-pentaho-chart-line-width
property.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
.series1 {
color: #2D00FF;
-x-pentaho-chart-line-width: 2px;
}
.series2 {
color: #11FFE4;
-x-pentaho-chart-line-width: 2px;
}
/* lines omitted */
.series18 {
color: #B7FFE5;
-x-pentaho-chart-line-width: 2px;
}
|
Generating Charts
Here is the result using the JFreeChart plugin for Pentaho ChartBeans:
...
- Pentaho ChartBeans Developer Documentation
- JFreeChart
- Open Flash Chart
- Pentaho ChartBeans Subversion repository: svn://source.pentaho.org/svnroot/pentaho-commons/pentaho-chartbeans/trunk
- Pentaho ChartBeans ChartComponent Subversion repository: svn://source.pentaho.org/svnroot/bi-platform-v2/trunk/bi-platform-plugin-actions
1 Pentaho ChartBeans name is subject to change.