/*
* RapidMiner
*
* Copyright (C) 2001-2008 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.plotter.charts;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.DeviationRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.YIntervalSeries;
import org.jfree.data.xy.YIntervalSeriesCollection;
import org.jfree.ui.HorizontalAlignment;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import com.rapidminer.datatable.DataTable;
import com.rapidminer.datatable.DataTableRow;
import com.rapidminer.gui.MainFrame;
import com.rapidminer.gui.plotter.PlotterAdapter;
import com.rapidminer.tools.LogService;
/**
* This is the deviation chart plotter.
*
* @author Ingo Mierswa
* @version $Id: SeriesChartPlotter.java,v 1.5 2008/05/25 12:08:44 ingomierswa Exp $
*/
public class SeriesChartPlotter extends PlotterAdapter {
private static final long serialVersionUID = -8763693366081949249L;
/** The currently used data table object. */
private transient DataTable dataTable;
/** The data set used for the plotter. */
private YIntervalSeriesCollection dataset = null;
/** The column which is used for the values. */
private boolean[] columns;
/** The axis values for the upper and lower bounds. */
private int[] axis = new int[] { -1, -1 };
/** Indicates if bounds are plotted. */
private boolean plotBounds = false;
private List<Integer> plotIndexToColumnIndexMap = new ArrayList<Integer>();
public SeriesChartPlotter() {
super();
setBackground(Color.white);
}
public SeriesChartPlotter(DataTable dataTable) {
this();
setDataTable(dataTable);
}
private JFreeChart createChart(XYDataset dataset, boolean createLegend) {
// create the chart...
JFreeChart chart = ChartFactory.createXYLineChart(
null, // chart title
null, // x axis label
null, // y axis label
dataset, // data
PlotOrientation.VERTICAL,
createLegend, // include legend
true, // tooltips
false // urls
);
chart.setBackgroundPaint(Color.white);
// get a reference to the plot for further customization...
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(Color.WHITE);
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
DeviationRenderer renderer = new DeviationRenderer(true, false);
if (plotBounds) {
for (int i = 0; i < dataset.getSeriesCount() - 1; i++) {
LineStyle style = PlotterAdapter.LINE_STYLES[this.plotIndexToColumnIndexMap.get(i) % PlotterAdapter.LINE_STYLES.length];
renderer.setSeriesStroke(i, style.getStroke());
renderer.setSeriesPaint(i, style.getColor());
renderer.setSeriesFillPaint(i, style.getColor());
}
float[] dashArray = new float[] { 7, 14 };
renderer.setSeriesStroke(dataset.getSeriesCount() - 1, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, dashArray, 0));
renderer.setSeriesPaint(dataset.getSeriesCount() - 1, Color.GRAY.brighter());
renderer.setSeriesFillPaint(dataset.getSeriesCount() - 1, Color.GRAY);
} else {
for (int i = 0; i < dataset.getSeriesCount(); i++) {
LineStyle style = PlotterAdapter.LINE_STYLES[this.plotIndexToColumnIndexMap.get(i) % PlotterAdapter.LINE_STYLES.length];
renderer.setSeriesStroke(i, style.getStroke());
renderer.setSeriesPaint(i, style.getColor());
renderer.setSeriesFillPaint(i, style.getColor());
}
}
renderer.setAlpha(0.25f);
plot.setRenderer(renderer);
NumberAxis xAxis = (NumberAxis) plot.getDomainAxis();
xAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
xAxis.setAutoRange(true);
xAxis.setAutoRangeStickyZero(false);
xAxis.setAutoRangeIncludesZero(false);
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
yAxis.setAutoRange(true);
yAxis.setAutoRangeStickyZero(false);
yAxis.setAutoRangeIncludesZero(false);
return chart;
}
public void setDataTable(DataTable dataTable) {
super.setDataTable(dataTable);
this.dataTable = dataTable;
columns = new boolean[dataTable.getNumberOfColumns()];
repaint();
}
public int getValuePlotSelectionType() {
return MULTIPLE_SELECTION;
}
public void setPlotColumn(int index, boolean plot) {
if ((index >= 0) && (index < columns.length))
this.columns[index] = plot;
repaint();
}
public boolean getPlotColumn(int index) {
return this.columns[index];
}
public String getPlotName() { return "Plot Series"; }
public int getNumberOfAxes() {
return 2;
}
public String getAxisName(int index) {
switch (index) {
case 0:
return "Lower Bound";
case 1:
return "Upper Bound";
default:
return "none";
}
}
public int getAxis(int index) {
return axis[index];
}
public void setAxis(int index, int dimension) {
if (axis[index] != dimension) {
axis[index] = dimension;
repaint();
}
}
private int prepareData() {
synchronized (dataTable) {
this.dataset = new YIntervalSeriesCollection();
this.plotBounds = false;
this.plotIndexToColumnIndexMap.clear();
int columnCount = 0;
for (int c = 0; c < dataTable.getNumberOfColumns(); c++) {
if (getPlotColumn(c)) {
if (dataTable.isNumerical(c)) {
YIntervalSeries series = new YIntervalSeries(this.dataTable.getColumnName(c));
Iterator<DataTableRow> i = dataTable.iterator();
int index = 1;
while (i.hasNext()) {
DataTableRow row = i.next();
double value = row.getValue(c);
series.add(index++, value, value, value);
}
dataset.addSeries(series);
plotIndexToColumnIndexMap.add(c);
columnCount++;
}
}
}
if ((getAxis(0) > -1) && (getAxis(1) > -1)) {
if ((dataTable.isNumerical(getAxis(0))) && (dataTable.isNumerical(getAxis(1)))) {
YIntervalSeries series = new YIntervalSeries("Bounds");
Iterator<DataTableRow> i = dataTable.iterator();
int index = 1;
while (i.hasNext()) {
DataTableRow row = i.next();
double lowerValue = row.getValue(getAxis(0));
double upperValue = row.getValue(getAxis(1));
if (lowerValue > upperValue) {
double dummy = lowerValue;
lowerValue = upperValue;
upperValue = dummy;
}
double mean = (upperValue - lowerValue) / 2.0d + lowerValue;
series.add(index++, mean, lowerValue, upperValue);
}
dataset.addSeries(series);
columnCount++;
this.plotBounds = true;
}
}
return columnCount;
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
paintSeriesChart(g);
}
public void paintSeriesChart(Graphics graphics) {
int categoryCount = prepareData();
String maxClassesProperty = System.getProperty(MainFrame.PROPERTY_RAPIDMINER_GUI_PLOTTER_COLORS_CLASSLIMIT);
int maxClasses = 20;
try {
if (maxClassesProperty != null)
maxClasses = Integer.parseInt(maxClassesProperty);
} catch (NumberFormatException e) {
LogService.getGlobal().log("Deviation plotter: cannot parse property 'rapidminer.gui.plotter.colors.classlimit', using maximal 20 different classes.", LogService.WARNING);
}
boolean createLegend = categoryCount > 0 && categoryCount < maxClasses;
JFreeChart chart = createChart(this.dataset, createLegend);
// set the background color for the chart...
chart.setBackgroundPaint(Color.white);
// legend settings
LegendTitle legend = chart.getLegend();
if (legend != null) {
legend.setPosition(RectangleEdge.TOP);
legend.setFrame(BlockBorder.NONE);
legend.setHorizontalAlignment(HorizontalAlignment.LEFT);
}
Rectangle2D drawRect = new Rectangle2D.Double(0, 0, getWidth(), getHeight());
chart.draw((Graphics2D)graphics, drawRect);
}
}