package edu.mit.blocks.codeblockutil;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Insets;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;
public class CLineGraph extends JLabel {
private static final long serialVersionUID = 328149080211L;
private static final Color DEFAULT_BACKGROUND = CGraphite.blue;
private JFreeChart chart;
private LineData chartData;
private Color background;
private BufferedImage img = null;
private boolean lock = false;
private ChartPanel output = null;
public CLineGraph(String title, int seriesNum, Color background) {
super("", SwingConstants.CENTER);
this.chartData = new LineData(title, true, 0.0, 30.0, 0.0, 100.0, seriesNum);
this.chart = chartData.makeChart();
this.background = background == null ? DEFAULT_BACKGROUND : background;
this.chart.setBackgroundPaint(this.background);
this.chart.setBorderPaint(null);
ImageIcon icon = new ImageIcon(chart.createBufferedImage(150, 100));
this.setLayout(null);
this.setIcon(icon);
this.setBounds(0, 0, 170, 130);
}
public Insets getInsets() {
return new Insets(15, 10, 15, 10);
}
public void clearChart() {
if (!lock) {
this.chart = chartData.makeChart();
this.chart.setBackgroundPaint(this.background);
this.chart.setBorderPaint(null);
if (output != null) {
JFreeChart newChart = new JFreeChart(chart.getPlot());
newChart.getLegend().setPosition(RectangleEdge.TOP);
newChart.getLegend().setPadding(5, 5, 5, 5);
newChart.setBackgroundPaint(background);
output.setChart(newChart);
output.invalidate();
output.repaint();
}
}
}
public void updateDomain(String title, int seriesNum, Color background) {
if (!lock) {
this.chartData.setSeriesNum(seriesNum);
this.chart = chartData.makeChart();
this.background = background == null ? DEFAULT_BACKGROUND : background;
this.chart.setBackgroundPaint(this.background);
this.chart.setBorderPaint(null);
if (output != null) {
JFreeChart newChart = new JFreeChart(chart.getPlot());
newChart.getLegend().setPosition(RectangleEdge.TOP);
newChart.getLegend().setPadding(5, 5, 5, 5);
newChart.setBackgroundPaint(background);
output.setChart(newChart);
output.invalidate();
output.repaint();
}
}
}
/**
* Clears all values for all series, leaving the same number of series
*/
public void clearValues() {
if (!lock) {
for (int i = 0; i < chart.getXYPlot().getSeriesCount(); i++) {
XYSeries s = ((XYSeriesCollection) chart.getXYPlot().getDataset()).getSeries(i);
while (s.getItemCount() > 0) {
s.remove(0);
}
}
}
}
/**
* Clear the graph starting from the startTime.
* @param startTime an x-value on the graph
*/
public void clearValues(int index, double startTime) {
if (!lock) {
XYSeries s = ((XYSeriesCollection) chart.getXYPlot().getDataset()).getSeries(index);
int i = s.indexOf(startTime);
if (i >= 0) {
int total = s.getItemCount();
for (; i < total; total--) {
s.remove(i);
}
}
}
}
/**
* Updates the values for the specified seriesName with the given values
* @param seriesName the name a series in the graph
* @param index the index of the desired series to update
* @param time the time at which to update
* @param value the value to update
*/
public void updateValues(String seriesName, int index, double time, double value) {
if (!lock) {
XYSeries s = ((XYSeriesCollection) chart.getXYPlot().getDataset()).getSeries(index);
s.setKey(seriesName);
s.addOrUpdate(time, value);
}
}
/**
* Updates the series name at the specified index
* @param seriesName the new seriesName to set at the specified index
* @param index the desired index to set the new seriesName to
*/
public void updateSeriesNameAt(String seriesName, int index) {
if (!lock) {
XYSeries s = ((XYSeriesCollection) chart.getXYPlot().getDataset()).getSeries(index);
s.setKey(seriesName);
}
}
/**
* Updates the graph image displayed of this.
* Image includes graph data, axis, and legend.
*/
public void updateImage() {
if (!lock) {
GraphicsManager.recycleGCCompatibleImage(img);
img = GraphicsManager.getGCCompatibleImage(150, 100);
chart.draw(img.createGraphics(), new Rectangle2D.Double(0, 0, 150, 100), null);
ImageIcon icon = new ImageIcon(img);
//ImageIcon icon = new ImageIcon(chart.createBufferedImage(150, 100, 150.0, 100.0, null));
this.setIcon(icon);
}
}
public ChartPanel getOutputPanel() {
//we return a copy of the chart because we only want to show the
//legend in the larger view of the graph
//not the small runtime graph block view
JFreeChart newChart = new JFreeChart(chart.getPlot());
newChart.getLegend().setPosition(RectangleEdge.TOP);
newChart.getLegend().setPadding(5, 5, 5, 5);
newChart.setBackgroundPaint(background);
output = new ChartPanel(newChart);
return output;
}
public BufferedImage getBufferedImage(int width, int height) {
return chart.createBufferedImage(width, height);
}
public String getCSV() {
lock = true;
int max = 0;
List<List<String>> columns = new ArrayList<List<String>>();
for (int i = 0; i < chartData.getSeriesNum(); i++) {
if (i == 0) {
List<String> time = new ArrayList<String>();//{name, v1, v2, v3}
XYSeries s = ((XYSeriesCollection) chart.getXYPlot().getDataset()).getSeries(i);
max = Math.max(max, s.getItemCount());
time.add("TIME,");
for (Object o : s.getItems()) {
XYDataItem item = (XYDataItem) o;
time.add(item.getX() + ",");
}
columns.add(time);
}
List<String> values = new ArrayList<String>();//{name, v1, v2, v3}
XYSeries s = ((XYSeriesCollection) chart.getXYPlot().getDataset()).getSeries(i);
max = Math.max(max, s.getItemCount());
values.add(s.getKey().toString() + ",");
for (Object o : s.getItems()) {
XYDataItem item = (XYDataItem) o;
values.add(item.getY() + ",");
}
columns.add(values);
}
StringBuilder output = new StringBuilder();
for (int i = 0; i < max; i++) {
for (int j = 0; j < columns.size(); j++) {
if (i < columns.get(j).size()) {
output.append(columns.get(j).get(i));
} else {
output.append(",");
}
}
output.append("\n");
}
lock = false;
return output.toString();
}
private class LineData extends ChartData {
private boolean autoRange;
private double xMin;
private double xMax;
private double yMin;
private double yMax;
private int seriesNum;
public LineData(String title, boolean autoRange, double xMin, double xMax, double yMin, double yMax, int seriesNum) {
super(title);
this.autoRange = autoRange;
this.xMin = xMin;
this.xMax = xMax;
this.yMin = yMin;
this.yMax = yMax;
this.seriesNum = seriesNum;
}
public JFreeChart makeChart() {
JFreeChart chart;
XYSeriesCollection lineDataset = new XYSeriesCollection();
for (int i = 0; i < getSeriesNum(); i++) {
lineDataset.addSeries(new XYSeries(new Integer(i)));
}
chart = ChartFactory.createXYLineChart("", "", "", lineDataset,
PlotOrientation.VERTICAL, false, false, false);
XYItemRenderer r = chart.getXYPlot().getRenderer();
for (int i = 0; i < getSeriesNum(); i++) {
//int colorValue = Color.HSBtoRGB(i*17/240f, 1f,0.5f);
int colorValue = Color.HSBtoRGB(((float) i) / getSeriesNum(), 1f, 0.5f);
Color color = new Color(colorValue);
r.setSeriesPaint(i, color);
r.setSeriesStroke(i, new BasicStroke(2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
}
NumberAxis rangeAxis = (NumberAxis) chart.getXYPlot().getRangeAxis();
rangeAxis.setNumberFormatOverride(new DecimalFormat("######.###"));
NumberAxis domainAxis = (NumberAxis) chart.getXYPlot().getDomainAxis();
if (autoRange) {
rangeAxis.setAutoRange(true);
domainAxis.setAutoRange(true);
} else {
domainAxis.setRange(xMin, xMax);
rangeAxis.setRange(yMin, yMax);
}
return chart;
}
public int getSeriesNum() {
return seriesNum;
}
public void setSeriesNum(int seriesNum) {
this.seriesNum = seriesNum;
}
}
}