/* ================================================================
* Cewolf : Chart enabling Web Objects Framework
* ================================================================
*
* Project Info: http://cewolf.sourceforge.net
* Project Lead: Guido Laures (guido@laures.de);
*
* (C) Copyright 2002, by Guido Laures
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library 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.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
package de.laures.cewolf.taglib;
import java.awt.Font;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.labels.XYToolTipGenerator;
import org.jfree.chart.plot.*;
import org.jfree.chart.plot.dial.DialPlot;
import org.jfree.chart.plot.dial.DialPointer;
import org.jfree.chart.plot.dial.StandardDialScale;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.urls.StandardXYURLGenerator;
import org.jfree.chart.urls.StandardCategoryURLGenerator;
import org.jfree.chart.urls.XYURLGenerator;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.PieDataset;
import org.jfree.data.general.ValueDataset;
import org.jfree.data.time.*;
import org.jfree.data.xy.*;
import de.laures.cewolf.jfree.ThermometerPlot;
import de.laures.cewolf.jfree.XYSplineRenderer;
import de.laures.cewolf.jfree.XYConditionRenderer;
import de.laures.cewolf.ChartValidationException;
import de.laures.cewolf.DatasetProduceException;
/**
* Chart factory creates Jfreechart instances. To add a new factory use the
* <code>CewolfChartFactory.registerFactory(new CewolfChartFactory() {...});</code> method.
*
* @author Guido Laures
*/
public abstract class CewolfChartFactory implements ChartConstants, AxisConstants, LayoutConstants {
// chart type string
protected String chartType;
// map contains registered factories, (String) chartType->CewolfChartFactory mappings
private static Map factories = new HashMap();
/** Creates a new instance of ChartFactory */
protected CewolfChartFactory(String chartType) {
this.chartType = chartType;
}
/**
* Callback when the chart instance to be created.
* @param title The title of chart
* @param xAxisLabel label on x axis
* @param yAxisLabel label on y axis
* @param data The dataset to create chart for
* @return The newly created JFreeChart instance
*
* @throws IncompatibleDatasetException If the incoming data is not compatible with this factory
*/
public abstract JFreeChart getChartInstance (String title, String xAxisLabel, String yAxisLabel, Dataset data)
throws IncompatibleDatasetException;
//////////////// static part ///////////////////////
/**
* Register a new chart factory instance.
* @param factory The factory to register
*/
public static void registerFactory (CewolfChartFactory factory) {
factories.put(factory.chartType, factory);
}
private static final int getChartTypeConstant (String type) {
final int res = ChartTypes.typeList.indexOf(type.toLowerCase());
if (res < 0) {
throw new RuntimeException("unsupported chart type " + type);
}
return res;
}
private static final int getLayoutConstant (String layout) {
return LayoutTypes.typeList.indexOf(layout.toLowerCase());
}
public static JFreeChart getChartInstance (String chartType, String title,
String xAxisLabel, String yAxisLabel, Dataset data, boolean showLegend)
throws ChartValidationException {
// first check the dynamically registered chart types
CewolfChartFactory factory = (CewolfChartFactory) factories.get(chartType);
if (factory != null) {
// custom factory found, use it
return factory.getChartInstance(title, xAxisLabel, yAxisLabel, data);
}
JFreeChart chart;
switch (getChartTypeConstant(chartType)) {
case XY :
check(data, XYDataset.class, chartType);
chart = createXYLineChart(title, xAxisLabel, yAxisLabel,
(XYDataset) data, PlotOrientation.VERTICAL, showLegend, true, true);
return chart;
case PIE :
check(data, PieDataset.class, chartType);
chart = ChartFactory.createPieChart(title, (PieDataset) data, showLegend, true, true);
return chart;
case AREA_XY :
check(data, XYDataset.class, chartType);
chart = ChartFactory.createXYAreaChart(title, xAxisLabel, yAxisLabel,
(XYDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case SCATTER :
check(data, XYDataset.class, chartType);
chart = createScatterPlot(title, xAxisLabel, yAxisLabel,
(XYDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case AREA :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createAreaChart(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case HORIZONTAL_BAR :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createBarChart(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.HORIZONTAL, showLegend, false, false);
return chart;
case HORIZONTAL_BAR_3D :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createBarChart3D(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.HORIZONTAL, showLegend, false, false);
return chart;
case LINE :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createLineChart(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case STACKED_HORIZONTAL_BAR :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createStackedBarChart(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.HORIZONTAL, showLegend, false, false);
return chart;
case STACKED_HORIZONTAL_BAR_3D :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createStackedBarChart3D(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.HORIZONTAL, showLegend, false, false);
return chart;
case STACKED_VERTICAL_BAR :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createStackedBarChart(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case STACKED_VERTICAL_BAR_3D :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createStackedBarChart3D(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case VERTICAL_BAR :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createBarChart(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case VERTICAL_BAR_3D :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createBarChart3D(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case TIME_SERIES :
check(data, XYDataset.class, chartType);
chart = ChartFactory.createTimeSeriesChart(title, xAxisLabel, yAxisLabel,
(XYDataset) data, showLegend, false, false);
return chart;
case CANDLE_STICK :
check(data, OHLCDataset.class, chartType);
chart = ChartFactory.createCandlestickChart(title, xAxisLabel, yAxisLabel, (OHLCDataset) data, true);
return chart;
case HIGH_LOW :
check(data, OHLCDataset.class, chartType);
chart = ChartFactory.createHighLowChart(title, xAxisLabel, yAxisLabel, (OHLCDataset) data, true);
return chart;
case GANTT :
check(data, IntervalCategoryDataset.class, chartType);
chart = ChartFactory.createGanttChart(title, xAxisLabel, yAxisLabel,
(IntervalCategoryDataset) data, showLegend, false, false);
return chart;
case WIND :
check(data, WindDataset.class, chartType);
chart = ChartFactory.createWindPlot(title, xAxisLabel, yAxisLabel,
(WindDataset) data, showLegend, false, false);
return chart;
case VERTICAL_XY_BAR :
check(data, IntervalXYDataset.class, chartType);
boolean dateAxis = data instanceof DynamicTimeSeriesCollection || data instanceof TimePeriodValuesCollection
|| data instanceof TimeSeriesCollection || data instanceof TimeTableXYDataset;
chart = ChartFactory.createXYBarChart(title, xAxisLabel, dateAxis, yAxisLabel,
(IntervalXYDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case PIE_3D :
check(data, PieDataset.class, chartType);
chart = ChartFactory.createPieChart3D(title, (PieDataset) data, showLegend, false, false);
return chart;
case METER :
check(data, ValueDataset.class, chartType);
MeterPlot plot = new MeterPlot((ValueDataset) data);
chart = new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), plot, showLegend);
ChartFactory.getChartTheme().apply(chart);
return chart;
case DIAL :
check(data, ValueDataset.class, chartType);
DialPlot dplot = new DialPlot((ValueDataset) data);
dplot.addPointer(new DialPointer.Pin());
StandardDialScale scale = new StandardDialScale();
scale.setTickLabelFont(new Font("Dialog", Font.BOLD, 10));
dplot.addScale(0, scale);
chart = new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), dplot, showLegend);
ChartFactory.getChartTheme().apply(chart);
return chart;
case THERMOMETER :
check(data, ValueDataset.class, chartType);
ThermometerPlot tplot = new ThermometerPlot((ValueDataset) data);
chart = new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), tplot, showLegend);
ChartFactory.getChartTheme().apply(chart);
return chart;
case COMPASS :
check(data, ValueDataset.class, chartType);
CompassPlot cplot = new CompassPlot((ValueDataset) data);
chart = new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), cplot, showLegend);
ChartFactory.getChartTheme().apply(chart);
return chart;
case STACKED_AREA :
check(data, CategoryDataset.class, chartType);
chart = ChartFactory.createStackedAreaChart(title, xAxisLabel, yAxisLabel,
(CategoryDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case BUBBLE :
check(data, XYZDataset.class, chartType);
chart = ChartFactory.createBubbleChart(title, xAxisLabel, yAxisLabel,
(XYZDataset) data, PlotOrientation.VERTICAL, showLegend, false, false);
return chart;
case SPLINE :
check(data, XYDataset.class, chartType);
chart = createSplineChart(title, xAxisLabel, yAxisLabel,
(XYDataset) data, PlotOrientation.VERTICAL, showLegend, true, true);
return chart;
case HISTOGRAM :
check(data, IntervalXYDataset.class, chartType);
chart = ChartFactory.createHistogram(title, xAxisLabel, yAxisLabel,
(IntervalXYDataset) data, PlotOrientation.VERTICAL, true, false, false);
return chart;
case SPIDERWEB :
check(data, CategoryDataset.class, chartType);
SpiderWebPlot swplot = new SpiderWebPlot((CategoryDataset) data);
chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, swplot, showLegend);
ChartFactory.getChartTheme().apply(chart);
return chart;
default :
throw new UnsupportedChartTypeException(chartType + " is not supported.");
}
}
/**
* Creates a spline chart (based on an {@link XYDataset}) with default settings.
*
* @param title the chart title (<code>null</code> permitted).
* @param xAxisLabel a label for the X-axis (<code>null</code> permitted).
* @param yAxisLabel a label for the Y-axis (<code>null</code> permitted).
* @param dataset the dataset for the chart (<code>null</code> permitted).
* @param orientation the plot orientation (horizontal or vertical) (<code>null</code> NOT permitted).
* @param showLegend a flag specifying whether or not a legend is required.
* @param tooltips configure chart to generate tool tips?
* @param urls configure chart to generate URLs?
*
* @return The chart.
*/
public static JFreeChart createSplineChart (String title, String xAxisLabel,
String yAxisLabel, XYDataset dataset, PlotOrientation orientation,
boolean showLegend, boolean tooltips, boolean urls) {
if (orientation == null) {
throw new IllegalArgumentException("Null 'orientation' argument.");
}
NumberAxis xAxis = new NumberAxis(xAxisLabel);
xAxis.setAutoRangeIncludesZero(false);
NumberAxis yAxis = new NumberAxis(yAxisLabel);
XYItemRenderer renderer = new XYSplineRenderer(10);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setOrientation(orientation);
if (tooltips) {
renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
}
if (urls) {
renderer.setURLGenerator(new StandardXYURLGenerator());
}
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, showLegend);
ChartFactory.getChartTheme().apply(chart);
return chart;
}
/**
* Creates a scatter plot with default settings. The chart object
* returned by this method uses an {@link XYPlot} instance as the plot,
* with a {@link NumberAxis} for the domain axis, a {@link NumberAxis}
* as the range axis, and an {@link XYConditionRenderer} as the renderer.
*
* @param title the chart title (<code>null</code> permitted).
* @param xAxisLabel a label for the X-axis (<code>null</code> permitted).
* @param yAxisLabel a label for the Y-axis (<code>null</code> permitted).
* @param dataset the dataset for the chart (<code>null</code> permitted).
* @param orientation the plot orientation (horizontal or vertical) (<code>null</code> NOT permitted).
* @param legend a flag specifying whether or not a legend is required.
* @param tooltips configure chart to generate tool tips?
* @param urls configure chart to generate URLs?
*
* @return A scatter plot.
*/
public static JFreeChart createScatterPlot (String title, String xAxisLabel,
String yAxisLabel, XYDataset dataset, PlotOrientation orientation,
boolean legend, boolean tooltips, boolean urls) {
if (orientation == null) {
throw new IllegalArgumentException("Null 'orientation' argument.");
}
NumberAxis xAxis = new NumberAxis(xAxisLabel);
xAxis.setAutoRangeIncludesZero(false);
NumberAxis yAxis = new NumberAxis(yAxisLabel);
yAxis.setAutoRangeIncludesZero(false);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, null);
XYToolTipGenerator toolTipGenerator = null;
if (tooltips) {
toolTipGenerator = new StandardXYToolTipGenerator();
}
XYURLGenerator urlGenerator = null;
if (urls) {
urlGenerator = new StandardXYURLGenerator();
}
XYItemRenderer renderer = new XYConditionRenderer(false, true);
renderer.setBaseToolTipGenerator(toolTipGenerator);
renderer.setURLGenerator(urlGenerator);
plot.setRenderer(renderer);
plot.setOrientation(orientation);
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, legend);
ChartFactory.getChartTheme().apply(chart);
return chart;
}
/**
* Creates a line chart (based on an {@link XYDataset}) with default settings.
*
* @param title the chart title (<code>null</code> permitted).
* @param xAxisLabel a label for the X-axis (<code>null</code> permitted).
* @param yAxisLabel a label for the Y-axis (<code>null</code> permitted).
* @param dataset the dataset for the chart (<code>null</code> permitted).
* @param orientation the plot orientation (horizontal or vertical) (<code>null</code> NOT permitted).
* @param legend a flag specifying whether or not a legend is required.
* @param tooltips configure chart to generate tool tips?
* @param urls configure chart to generate URLs?
*
* @return The chart.
*/
public static JFreeChart createXYLineChart (String title, String xAxisLabel,
String yAxisLabel, XYDataset dataset, PlotOrientation orientation,
boolean legend, boolean tooltips, boolean urls) {
if (orientation == null) {
throw new IllegalArgumentException("Null 'orientation' argument.");
}
NumberAxis xAxis = new NumberAxis(xAxisLabel);
xAxis.setAutoRangeIncludesZero(false);
NumberAxis yAxis = new NumberAxis(yAxisLabel);
XYItemRenderer renderer = new XYConditionRenderer(true, false);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
plot.setOrientation(orientation);
if (tooltips) {
renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator());
}
if (urls) {
renderer.setURLGenerator(new StandardXYURLGenerator());
}
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, legend);
ChartFactory.getChartTheme().apply(chart);
return chart;
}
public static JFreeChart getOverlaidChartInstance (String chartType, String title, String xAxisLabel,
String yAxisLabel, int xAxisType, int yAxisType, List plotDefinitions, boolean showLegend)
throws ChartValidationException, DatasetProduceException {
final int chartTypeConst = getChartTypeConstant(chartType);
final AxisFactory axisFactory = AxisFactory.getInstance();
switch (chartTypeConst) {
case OVERLAY_XY :
ValueAxis domainAxis = (ValueAxis) axisFactory.createAxis(ORIENTATION_HORIZONTAL, xAxisType, xAxisLabel);
// get main plot
PlotDefinition mainPlotDef = (PlotDefinition) plotDefinitions.get(0);
if (domainAxis instanceof NumberAxis && mainPlotDef.isXaxisinteger()) {
((NumberAxis) domainAxis).setStandardTickUnits(NumberAxis.createIntegerTickUnits());
}
check(mainPlotDef.getDataset(), XYDataset.class, chartType);
XYPlot plot = (XYPlot) mainPlotDef.getPlot(chartTypeConst);
plot.setDomainAxis(domainAxis);
ValueAxis rangeAxis = (ValueAxis) axisFactory.createAxis(ORIENTATION_VERTICAL, yAxisType, yAxisLabel);
if (rangeAxis instanceof NumberAxis && mainPlotDef.isYaxisinteger()) {
((NumberAxis) rangeAxis).setStandardTickUnits(NumberAxis.createIntegerTickUnits());
}
plot.setRangeAxis(rangeAxis);
//plot.setRenderer(new StandardXYItemRenderer());
// add second and later datasets to main plot
for (int plotidx = 1;plotidx<plotDefinitions.size();plotidx++) {
PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions.get(plotidx);
check(subPlotDef.getDataset(), XYDataset.class, chartType);
plot.setDataset(plotidx, (XYDataset)subPlotDef.getDataset());
int rendererIndex = PlotTypes.getRendererIndex(subPlotDef.getType());
XYItemRenderer rend = (XYItemRenderer) PlotTypes.getRenderer(rendererIndex);
plot.setRenderer(plotidx, rend);
}
return new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), plot, showLegend);
case OVERLAY_CATEGORY ://added by lrh 2005-07-11
CategoryAxis domainAxis2 = (CategoryAxis)axisFactory.createAxis(ORIENTATION_HORIZONTAL, xAxisType, xAxisLabel);
// get main plot
mainPlotDef = (PlotDefinition) plotDefinitions.get(0);
check(mainPlotDef.getDataset(), CategoryDataset.class, chartType);
CategoryPlot plot2 = (CategoryPlot) mainPlotDef.getPlot(chartTypeConst);
plot2.setDomainAxis(domainAxis2);
ValueAxis va = (ValueAxis) axisFactory.createAxis(ORIENTATION_VERTICAL, yAxisType, yAxisLabel);
if (va instanceof NumberAxis && mainPlotDef.isYaxisinteger()) {
((NumberAxis) va).setStandardTickUnits(NumberAxis.createIntegerTickUnits());
}
plot2.setRangeAxis(va);
//plot.setRenderer(new StandardXYItemRenderer());
// add second and later datasets to main plot
for (int plotidx = 1;plotidx<plotDefinitions.size();plotidx++) {
PlotDefinition subPlotDef = (PlotDefinition) plotDefinitions.get(plotidx);
check(subPlotDef.getDataset(), CategoryDataset.class, chartType);
plot2.setDataset(plotidx, (CategoryDataset)subPlotDef.getDataset());
int rendererIndex = PlotTypes.getRendererIndex(subPlotDef.getType());
CategoryItemRenderer rend2 = (CategoryItemRenderer) PlotTypes.getRenderer(rendererIndex);
plot2.setRenderer(plotidx, rend2);
}
return new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), plot2, showLegend);
default :
throw new UnsupportedChartTypeException(chartType + " is not supported.");
}
}
public static JFreeChart getCombinedChartInstance (String chartType, String title, String xAxisLabel,
String yAxisLabel, List plotDefinitions, String layout, boolean showLegend)
throws ChartValidationException, DatasetProduceException {
final int chartTypeConst = getChartTypeConstant(chartType);
switch (chartTypeConst) {
case COMBINED_XY :
final int layoutConst = getLayoutConstant(layout);
Plot plot = null;
switch (layoutConst) {
case DOMAIN :
ValueAxis domainAxis = new DateAxis(xAxisLabel);
plot = new CombinedDomainXYPlot(domainAxis);
for (int i = 0; i < plotDefinitions.size(); i++) {
PlotDefinition pd = (PlotDefinition) plotDefinitions.get(i);
check(pd.getDataset(), XYDataset.class, chartType);
XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
NumberAxis na = new NumberAxis(pd.getYaxislabel());
if (pd.isYaxisinteger())
na.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
temp.setRangeAxis(na);
((CombinedDomainXYPlot) plot).add(temp);
}
return new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), plot, showLegend);
case RANGE :
ValueAxis rangeAxis = new NumberAxis(yAxisLabel);
plot = new CombinedRangeXYPlot(rangeAxis);
boolean allInteger = true;
for (int i = 0; i < plotDefinitions.size(); i++) {
PlotDefinition pd = (PlotDefinition) plotDefinitions.get(i);
if (! pd.isYaxisinteger())
allInteger = false;
check(pd.getDataset(), XYDataset.class, chartType);
XYPlot temp = (XYPlot) pd.getPlot(chartTypeConst);
temp.setDomainAxis(new DateAxis(pd.getXaxislabel()));
((CombinedRangeXYPlot) plot).add(temp);
}
if (allInteger)
((NumberAxis) rangeAxis).setStandardTickUnits(NumberAxis.createIntegerTickUnits());
return new JFreeChart(title, new Font("SansSerif", Font.BOLD, 18), plot, showLegend);
default :
throw new AttributeValidationException(layout, " any value");
}
default :
throw new UnsupportedChartTypeException(chartType);
}
}
/**
* Helper to check if the given dataset is the expected type.
* @param data The dataset
* @param clazz Expected type (class)
* @param chartType The chart type string
* @throws IncompatibleDatasetException If not the expected class
*/
public static void check(Dataset data, Class clazz, String chartType) throws IncompatibleDatasetException {
if (!clazz.isInstance(data)) {
throw new IncompatibleDatasetException("Charts of type " + chartType + " " + "need datasets of type " + clazz.getName());
}
}
}