/*
* RapidMiner
*
* Copyright (C) 2001-2011 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.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import javax.swing.Icon;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleInsets;
import com.rapidminer.datatable.DataTable;
import com.rapidminer.datatable.DataTableRow;
import com.rapidminer.gui.plotter.PlotterConfigurationModel;
import com.rapidminer.gui.plotter.RangeablePlotterAdapter;
import com.rapidminer.tools.Tools;
/**
* This is the multiple series chart plotter.
*
* @author Ingo Mierswa
*/
public class MultipleSeriesChartPlotter extends RangeablePlotterAdapter {
private static final long serialVersionUID = -8763693366081949249L;
private static final String SERIESINDEX_LABEL = "index";
/** The currently used data table object. */
private transient DataTable dataTable;
private int indexAxis = -1;
/** The column which is used for the values. */
private boolean[] columns;
public MultipleSeriesChartPlotter(PlotterConfigurationModel settings) {
super(settings);
setBackground(Color.white);
}
public MultipleSeriesChartPlotter(PlotterConfigurationModel settings, DataTable dataTable) {
this(settings);
setDataTable(dataTable);
}
private JFreeChart createChart() {
// create the chart...
JFreeChart chart = ChartFactory.createXYLineChart(
null, // chart title
null, // x axis label
null, // y axis label
null, // data
PlotOrientation.VERTICAL,
false, // 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);
// domain axis
if ((indexAxis >= 0) && (!dataTable.isNominal(indexAxis))) {
if ((dataTable.isDate(indexAxis)) || (dataTable.isDateTime(indexAxis))) {
DateAxis domainAxis = new DateAxis(dataTable.getColumnName(indexAxis));
domainAxis.setTimeZone(Tools.getPreferredTimeZone());
chart.getXYPlot().setDomainAxis(domainAxis);
}
} else {
plot.getDomainAxis().setStandardTickUnits(NumberAxis.createIntegerTickUnits(Locale.US));
((NumberAxis)plot.getDomainAxis()).setAutoRangeStickyZero(false);
((NumberAxis)plot.getDomainAxis()).setAutoRangeIncludesZero(false);
}
ValueAxis xAxis = plot.getDomainAxis();
if (indexAxis > -1)
xAxis.setLabel(getDataTable().getColumnName(indexAxis));
else
xAxis.setLabel(SERIESINDEX_LABEL);
xAxis.setAutoRange(true);
xAxis.setLabelFont(LABEL_FONT_BOLD);
xAxis.setTickLabelFont(LABEL_FONT);
xAxis.setVerticalTickLabels(isLabelRotating());
if (indexAxis > 0) {
if (getRangeForDimension(indexAxis) != null) {
xAxis.setRange(getRangeForDimension(indexAxis));
}
} else {
if (getRangeForName(SERIESINDEX_LABEL) != null) {
xAxis.setRange(getRangeForName(SERIESINDEX_LABEL));
}
}
// renderer and range axis
synchronized (dataTable) {
int numberOfSelectedColumns = 0;
for (int c = 0; c < dataTable.getNumberOfColumns(); c++) {
if (getPlotColumn(c)) {
if (dataTable.isNumerical(c)) {
numberOfSelectedColumns++;
}
}
}
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));
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series = new XYSeries(dataTable.getColumnName(c));
Iterator<DataTableRow> i = dataTable.iterator();
int index = 1;
while (i.hasNext()) {
DataTableRow row = i.next();
double value = row.getValue(c);
if ((indexAxis >= 0) && (!dataTable.isNominal(indexAxis))) {
double indexValue = row.getValue(indexAxis);
series.add(indexValue, value);
} else {
series.add(index++, value);
}
}
dataset.addSeries(series);
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
Color color = getColorProvider().getPointColor(1.0d);
if (numberOfSelectedColumns > 1) {
color = getColorProvider().getPointColor(columnCount / (double)(numberOfSelectedColumns - 1));
}
renderer.setSeriesPaint(0, color);
renderer.setSeriesStroke(0, new BasicStroke(1.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
renderer.setSeriesShapesVisible(0, false);
NumberAxis yAxis = new NumberAxis(dataTable.getColumnName(c));
if (getRangeForDimension(c) != null) {
yAxis.setRange(getRangeForDimension(c));
} else {
yAxis.setAutoRange(true);
yAxis.setAutoRangeStickyZero(false);
yAxis.setAutoRangeIncludesZero(false);
}
yAxis.setLabelFont(LABEL_FONT_BOLD);
yAxis.setTickLabelFont(LABEL_FONT);
if (numberOfSelectedColumns > 1) {
yAxis.setAxisLinePaint(color);
yAxis.setTickMarkPaint(color);
yAxis.setLabelPaint(color);
yAxis.setTickLabelPaint(color);
}
plot.setRangeAxis(columnCount, yAxis);
plot.setRangeAxisLocation(columnCount, AxisLocation.TOP_OR_LEFT);
plot.setDataset(columnCount, dataset);
plot.setRenderer(columnCount, renderer);
plot.mapDatasetToRangeAxis(columnCount, columnCount);
columnCount++;
}
}
}
}
chart.setBackgroundPaint(Color.white);
return chart;
}
/** Returns a line icon depending on the index. */
@Override
public Icon getIcon(int index) {
return null;
}
@Override
public int getValuePlotSelectionType() {
return MULTIPLE_SELECTION;
}
@Override
public void setPlotColumn(int index, boolean plot) {
if ((index >= 0) && (index < columns.length))
this.columns[index] = plot;
updatePlotter();
}
@Override
public boolean getPlotColumn(int index) {
return this.columns[index];
}
@Override
public String getPlotName() { return "Plot Series"; }
@Override
public int getNumberOfAxes() {
return 1;
}
@Override
public String getAxisName(int index) {
if (index == 0)
return "Index Dimension";
else
return "none";
}
@Override
public int getAxis(int index) {
if (index == 0)
return indexAxis;
else
return -1;
}
@Override
public void setAxis(int index, int dimension) {
if (index == 0) {
indexAxis = dimension;
updatePlotter();
}
}
@Override
protected void updatePlotter() {
JFreeChart chart = createChart();
AbstractChartPanel panel = getPlotterPanel();
if (panel == null) {
panel = createPanel(chart);
}
panel.setChart(chart);
// ATTENTION: WITHOUT THIS WE GET SEVERE MEMORY LEAKS!!!
panel.getChartRenderingInfo().setEntityCollection(null);
}
@Override
public String getPlotterName() {
return PlotterConfigurationModel.MULTIPLE_SERIES_PLOT;
}
@Override
public void dataTableSet() {
this.dataTable = getDataTable();
columns = new boolean[dataTable.getNumberOfColumns()];
updatePlotter();
}
@Override
public Collection<String> resolveXAxis(int axisIndex) {
if (indexAxis != -1)
return Collections.singletonList(dataTable.getColumnName(indexAxis));
else
return Collections.singletonList(SERIESINDEX_LABEL);
}
@Override
public Collection<String> resolveYAxis(int axisIndex) {
Collection<String> names = new LinkedList<String>();
int foundAxis = 0;
for (int i = 0; i <columns.length; i++) {
if (columns[i]) {
if (axisIndex == foundAxis) {
names.add(dataTable.getColumnName(i));
break;
}
foundAxis++;
}
}
return names;
}
}