/*
* Copyright © 2010 by Ondrej Skalicka. All Rights Reserved
*/
package cz.cvut.felk.cig.jcop.result.render;
import cz.cvut.felk.cig.jcop.solver.message.*;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
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 java.awt.*;
/**
* Listens to solver and draws graph with best solutions.
*
* @author Ondrej Skalicka
*/
public class JFreeChartRender implements MessageListener {
/**
* Dataset containing all series.
*/
protected XYSeriesCollection dataSet;
/**
* Active series to add new values to.
*/
protected XYSeries activeSeries;
/**
* Number of iterations for current active series.
*/
protected int optimizeCounter;
/**
* Last best fitness, used if {@link #insertLast} is true.
*/
protected double lastBestFitness;
/**
* Chart which we render to.
*/
protected JFreeChart chart;
/**
* If true, when a solver ends, one last point will be added to chart.
*/
protected boolean insertLast = false;
/**
* Chart style used in the thesis.
* <p/>
* Uses:
* <p/>
* <ul> <li>setBaseShapesVisible(true)</li> <li>setBaseShapesFilled(false)</li> <li>setBaseLinesVisible(false)</li>
* <li>setLegendItemFont(new Font("Dialog", Font.PLAIN, 9))</li> <li>setBackgroundPaint(Color.white)</li>
* <li>setGridPaint(Color.gray)</li> <li>setInsertLast(false)</li> <li>removeLegend()</li> </ul>
*/
public final static int STYLE_THESIS = 0;
/**
* Chart style used in the thesis.
* <p/>
* Uses:
* <p/>
* <ul> <li>setBaseShapesVisible(true)</li> <li>setBaseShapesFilled(false)</li> <li>setBaseLinesVisible(false)</li>
* <li>setLegendItemFont(new Font("Dialog", Font.PLAIN, 9))</li> <li>setBackgroundPaint(Color.white)</li>
* <li>setGridPaint(Color.gray)</li> <li>setInsertLast(false)</li> </ul>
*/
public final static int STYLE_THESIS_LEGEND = 1;
/**
* Creates new JFreeChartRender with given title.
*
* @param title title of the chart
*/
public JFreeChartRender(String title) {
dataSet = new XYSeriesCollection();
chart = ChartFactory.createXYLineChart(
title, // chart title
"Optimization counter", // x axis label
"Fitness", // y axis label
dataSet, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
ChartFrame frame = new ChartFrame(title, chart);
frame.pack();
frame.setVisible(true);
}
public void onMessage(Message message) {
if (message instanceof MessageSolverStart) {
MessageSolverStart messageSolverStart = (MessageSolverStart) message;
this.activeSeries = new XYSeries(messageSolverStart.getAlgorithm() + "/" + messageSolverStart.getObjectiveProblem());
this.dataSet.addSeries(this.activeSeries);
this.optimizeCounter = 0;
return;
}
if (message instanceof MessageOptimize) {
this.optimizeCounter++;
return;
}
if (message instanceof MessageBetterConfigurationFound) {
this.lastBestFitness = ((MessageBetterConfigurationFound) message).getFitness();
this.activeSeries.add(this.optimizeCounter, this.lastBestFitness);
return;
}
if (message instanceof MessageSolverStop) {
if (this.activeSeries != null && this.insertLast)
this.activeSeries.add(this.optimizeCounter, this.lastBestFitness);
}
}
/**
* Returns render for this chart.
*
* @return render for this chart.
*/
protected XYLineAndShapeRenderer getRenderer() {
return ((XYLineAndShapeRenderer) ((XYPlot) chart.getPlot()).getRenderer());
}
/**
* Returns plot for this chart.
*
* @return plot for this chart.
*/
protected XYPlot getPlot() {
return (XYPlot) chart.getPlot();
}
/**
* Returns chart for this render.
*
* This method should be used for customization of chart if no better public method is provided by JFreeChartRender.
*
* @return chart for this render
*/
public JFreeChart getChart () {
return this.chart;
}
/**
* Sets if shapes are drawn in addition to lines.
* <p/>
* Default false.
*
* @param baseShapesVisible if true, shapes will be drawn in addition to lines.
* @return itself (fluent interface)
*/
public JFreeChartRender setBaseShapesVisible(boolean baseShapesVisible) {
getRenderer().setBaseShapesVisible(baseShapesVisible);
return this;
}
/**
* Sets if shapes are filled or not.
* <p/>
* Default true.
*
* @param baseShapesFilled if true, shapes are filled
* @return itself (fluent interface)
*/
public JFreeChartRender setBaseShapesFilled(boolean baseShapesFilled) {
getRenderer().setBaseShapesFilled(baseShapesFilled);
return this;
}
/**
* Sets if plot points are connected with lines.
* <p/>
* Default true.
*
* @param baseLinesVisible if true, plot points are connected with lines
* @return itself (fluent interface)
*/
public JFreeChartRender setBaseLinesVisible(boolean baseLinesVisible) {
getRenderer().setBaseLinesVisible(baseLinesVisible);
return this;
}
/**
* Sets font for legend.
*
* @param font new font for legend
* @return itself (fluent interface)
*/
public JFreeChartRender setLegendItemFont(Font font) {
chart.getLegend().setItemFont(font);
return this;
}
/**
* Sets background color for chart (both chart and plot).
*
* @param color new background color
* @return itself (fluent interface)
*/
public JFreeChartRender setBackgroundPaint(Color color) {
chart.setBackgroundPaint(color);
getPlot().setBackgroundPaint(color);
return this;
}
/**
* Sets color for grid in chart.
* <p/>
* Default grey.
*
* @param color new color for chart grid
* @return itself (fluent interface)
*/
public JFreeChartRender setGridPaint(Color color) {
getPlot().setRangeGridlinePaint(color);
getPlot().setDomainGridlinePaint(color);
return this;
}
/**
* Control if last element is added to plot on {@link cz.cvut.felk.cig.jcop.solver.message.MessageSolverStop}.
* <p/>
* Default false.
*
* @param insertLast if true, one more point is added to plot
* @return itself (fluent interface)
*/
public JFreeChartRender setInsertLast(boolean insertLast) {
this.insertLast = insertLast;
return this;
}
/**
* Removes legend from chart.
* <p/>
* Note that this is irreversible chane.
*
* @return itself (fluent interface)
*/
public JFreeChartRender removeLegend() {
this.chart.removeLegend();
return this;
}
/**
* Sets bounds for domain axis.
*
* @param lowerBound lower domain bound
* @param upperBound upper domain bound
* @return itself (fluent interface)
*/
public JFreeChartRender setDomainAxis(double lowerBound, double upperBound) {
ValueAxis valueAxis = getPlot().getDomainAxis();
valueAxis.setUpperBound(upperBound);
valueAxis.setLowerBound(lowerBound);
return this;
}
/**
* Sets bounds for range axis.
*
* @param lowerBound lower range bound
* @param upperBound upper range bound
* @return itself (fluent interface)
*/
public JFreeChartRender setRangeAxis(double lowerBound, double upperBound) {
ValueAxis valueAxis = getPlot().getRangeAxis();
valueAxis.setUpperBound(upperBound);
valueAxis.setLowerBound(lowerBound);
return this;
}
/**
* Applies prepared style to a chart.
*
* Recognizes {@link JFreeChartRender#STYLE_THESIS} and {@link JFreeChartRender#STYLE_THESIS_LEGEND}.
*
* @param style code of style
* @return updated chart
*/
public JFreeChartRender setStyle(int style) {
switch (style) {
case JFreeChartRender.STYLE_THESIS:
return this.setBaseShapesVisible(true).
setBaseShapesFilled(false).
setBaseLinesVisible(false).
setLegendItemFont(new Font("Dialog", Font.PLAIN, 9)).
setBackgroundPaint(Color.white).
setGridPaint(Color.gray).
setInsertLast(false).
removeLegend();
case JFreeChartRender.STYLE_THESIS_LEGEND:
return this.setBaseShapesVisible(true).
setBaseShapesFilled(false).
setBaseLinesVisible(false).
setLegendItemFont(new Font("Dialog", Font.PLAIN, 9)).
setBackgroundPaint(Color.white).
setGridPaint(Color.gray).
setInsertLast(false);
default:
return this;
}
}
}