JFreechart:如何自定义单个数据集中的每个时间序列
JFreechart : how to customize each time series in a single dataset
我需要创建一个包含多个时间序列的图表,其中一些绘制在左侧 Y 轴上,一些绘制在右侧 Y 轴上,一些是线,另一些是条形图。
我正在通过以下方式创建带有十字准线的图表,只有一个数据系列:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.text.SimpleDateFormat;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.data.general.DatasetUtils;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
public class Charts extends JFrame implements ChartMouseListener {
private ChartPanel chartPanel;
private Crosshair xCrosshair;
private Crosshair yCrosshair;
public Charts (List<CompanySummaryEuHistorical> sortedCos, String title) {
super(title);
setContentPane(createContent(sortedCos));
}
private JPanel createContent(List<CompanySummaryEuHistorical> sortedCos) {
// create chart with price and nav data series
JFreeChart chart = createChart(createDataset(sortedCos));
// getdatasets to format it
XYPlot plot = (XYPlot) chart.getPlot();
plot.getDataset().getSeriesKey(0);
plot.setRenderer(0,new XYBarRenderer());
// create crosshair
this.chartPanel = new ChartPanel(chart);
this.chartPanel.addChartMouseListener(this);
CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.xCrosshair.setLabelVisible(true);
this.xCrosshair.setLabelGenerator(crshr ->
new SimpleDateFormat("dd/MM/YYYY").format(crshr.getValue()));
this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yCrosshair.setLabelVisible(true);
crosshairOverlay.addDomainCrosshair(xCrosshair);
crosshairOverlay.addRangeCrosshair(yCrosshair);
chartPanel.addOverlay(crosshairOverlay);
return chartPanel;
}
private JFreeChart createChart(XYDataset dataset) {
return ChartFactory.createTimeSeriesChart("Chart",
"Date", "Value", dataset);
}
private XYDataset createDataset(List<CompanySummaryEuHistorical> sortedCos) {
TimeSeries priceSeries = new TimeSeries("Price");
TimeSeries navSeries = new TimeSeries("Nav");
for (CompanySummaryEuHistorical c : sortedCos) {
Day d = new Day(c.getDate_bom().getDayOfMonth(), c.getDate_bom().getMonthValue(), c.getDate_bom().getYear());
priceSeries.add(d, c.getPrice());
System.out.println("adding nav " + c.getNav() + "; date: " + c.getDate_bom());
navSeries.add(d, c.getNav());
}
final TimeSeriesCollection dataset = new TimeSeriesCollection(priceSeries);
dataset.addSeries(navSeries);
return dataset;
}
@Override
public void chartMouseClicked(ChartMouseEvent event) {
// ignore
}
@Override
public void chartMouseMoved(ChartMouseEvent event) {
Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
JFreeChart chart = event.getChart();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea,
RectangleEdge.BOTTOM);
double y = DatasetUtils.findYValue(plot.getDataset(), 0, x);
this.xCrosshair.setValue(x);
this.yCrosshair.setValue(y);
}
}
但是,我无法理解如何访问我独特的数据系列中的每个时间序列,以便将它们更改为条形图或更改它们的轴。我试过这个,但它改变了所有时间序列:
XYPlot plot = (XYPlot) chart.getPlot();
plot.getDataset().getSeriesKey(0);
plot.setRenderer(0,new XYBarRenderer());
谁能帮我解决这个问题?谢谢!
我最终放弃了使用具有多个序列的单个数据集的想法,而是使用了多个时间序列,正如我的问题的评论中所建议的那样,以 this code 作为模型。
public class Charts extends JFrame implements ChartMouseListener {
private TimeSeries priceSeries = new TimeSeries("Price");
private TimeSeries navSeries = new TimeSeries("Nav");
private ChartPanel chartPanel;
private Crosshair xCrosshair;
private Crosshair yCrosshair;
private Crosshair yNavCrosshair;
private Crosshair yDivCrosshair;
public Charts (List<CompanySummaryEuHistorical> sortedCos, String title) {
super(title);
setContentPane(createContent(sortedCos));
}
private JPanel createContent(List<CompanySummaryEuHistorical> sortedCos) {
// create series
createSeries(sortedCos);
XYDataset priceData = new TimeSeriesCollection(priceSeries);
XYLineAndShapeRenderer r0 = new XYLineAndShapeRenderer();
r0.setSeriesPaint(0, new Color(0, 0, 0x00));
r0.setSeriesShapesVisible(0, false);
XYLineAndShapeRenderer r2 = new XYLineAndShapeRenderer();
r2.setSeriesPaint(0, new Color(255, 41, 194));
r2.setSeriesShapesVisible(0, false);
XYLineAndShapeRenderer r3 = new XYLineAndShapeRenderer();
r3.setSeriesPaint(0, new Color(255, 49, 40));
r3.setSeriesShapesVisible(0, false);
// create chart with price and nav data series
JFreeChart chart = ChartFactory.createTimeSeriesChart(
title, "Date", "Value", priceData, true, true, true);
plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(192, 196, 196));
NumberAxis rangeAxis1 = (NumberAxis) plot.getRangeAxis();
rangeAxis1.setLowerMargin(0.40); // Leave room for volume bars
rangeAxis1.setNumberFormatOverride(NumberFormat.getCurrencyInstance(getCountry(sortedCos)));
plot.setRenderer(0, r0);
renderer = (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setDefaultToolTipGenerator(new StandardXYToolTipGenerator(
StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
new SimpleDateFormat("dd/MM/YYYY"), NumberFormat.getCurrencyInstance()));
// nav series in bars
plot.setDataset(1, new TimeSeriesCollection(navSeries));
Charts.NavRender myRenderer = new NavRender();
myRenderer.setShadowVisible(false);
myRenderer.setDefaultToolTipGenerator(new StandardXYToolTipGenerator(
StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
new SimpleDateFormat("dd/MM/YYYY"), NumberFormat.getNumberInstance()));
plot.setRenderer(1, myRenderer);
// div series on second axis
NumberAxis rangeAxis2 = new NumberAxis("Value");
rangeAxis2.setUpperBound(rangeAxis1.getUpperBound()/10); // Leave room for price line
plot.setRangeAxis(1, rangeAxis2);
plot.setDataset(2, new TimeSeriesCollection(divSeries));
plot.mapDatasetToRangeAxis(2, 1);
plot.setRenderer(2, r2);
// create crosshair
this.chartPanel = new ChartPanel(chart);
this.chartPanel.addChartMouseListener(this);
CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.xCrosshair.setLabelVisible(true);
this.xCrosshair.setLabelGenerator(crshr ->
new SimpleDateFormat("dd/MM/YYYY").format(crshr.getValue()));
this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yCrosshair.setLabelVisible(true);
this.yNavCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yNavCrosshair.setLabelVisible(true);
this.yDivCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yDivCrosshair.setLabelVisible(true);
crosshairOverlay.addDomainCrosshair(xCrosshair);
crosshairOverlay.addRangeCrosshair(yCrosshair);
chartPanel.addOverlay(crosshairOverlay);
return chartPanel;
}
private JFreeChart createChart(XYDataset dataset) {
return ChartFactory.createTimeSeriesChart("Chart",
"Date", "Value", dataset);
}
private void createSeries(List<CompanySummaryEuHistorical> sortedCos) {
for (CompanySummaryEuHistorical c : sortedCos) {
Day d = new Day(c.getDate_bom().getDayOfMonth(), c.getDate_bom().getMonthValue(), c.getDate_bom().getYear());
priceSeries.add(d, c.getPrice());
navSeries.add(d, c.getNav());
divSeries.add(d, c.getDiv());}
}
@Override
public void chartMouseClicked(ChartMouseEvent event) {
// ignore
}
@Override
public void chartMouseMoved(ChartMouseEvent event) {
Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
JFreeChart chart = event.getChart();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea,
RectangleEdge.BOTTOM);
double y = DatasetUtils.findYValue(plot.getDataset(), 0, x);
double yNav = DatasetUtils.findYValue(plot.getDataset(1), 0, x);
double yDiv = DatasetUtils.findYValue(plot.getDataset(2), 0, x);
this.xCrosshair.setValue(x);
this.yCrosshair.setValue(y);
this.yNavCrosshair.setValue(yNav);
this.yDivCrosshair.setValue(yDiv);
}
}
我需要创建一个包含多个时间序列的图表,其中一些绘制在左侧 Y 轴上,一些绘制在右侧 Y 轴上,一些是线,另一些是条形图。
我正在通过以下方式创建带有十字准线的图表,只有一个数据系列:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.text.SimpleDateFormat;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.panel.CrosshairOverlay;
import org.jfree.chart.plot.Crosshair;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.data.general.DatasetUtils;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
public class Charts extends JFrame implements ChartMouseListener {
private ChartPanel chartPanel;
private Crosshair xCrosshair;
private Crosshair yCrosshair;
public Charts (List<CompanySummaryEuHistorical> sortedCos, String title) {
super(title);
setContentPane(createContent(sortedCos));
}
private JPanel createContent(List<CompanySummaryEuHistorical> sortedCos) {
// create chart with price and nav data series
JFreeChart chart = createChart(createDataset(sortedCos));
// getdatasets to format it
XYPlot plot = (XYPlot) chart.getPlot();
plot.getDataset().getSeriesKey(0);
plot.setRenderer(0,new XYBarRenderer());
// create crosshair
this.chartPanel = new ChartPanel(chart);
this.chartPanel.addChartMouseListener(this);
CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.xCrosshair.setLabelVisible(true);
this.xCrosshair.setLabelGenerator(crshr ->
new SimpleDateFormat("dd/MM/YYYY").format(crshr.getValue()));
this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yCrosshair.setLabelVisible(true);
crosshairOverlay.addDomainCrosshair(xCrosshair);
crosshairOverlay.addRangeCrosshair(yCrosshair);
chartPanel.addOverlay(crosshairOverlay);
return chartPanel;
}
private JFreeChart createChart(XYDataset dataset) {
return ChartFactory.createTimeSeriesChart("Chart",
"Date", "Value", dataset);
}
private XYDataset createDataset(List<CompanySummaryEuHistorical> sortedCos) {
TimeSeries priceSeries = new TimeSeries("Price");
TimeSeries navSeries = new TimeSeries("Nav");
for (CompanySummaryEuHistorical c : sortedCos) {
Day d = new Day(c.getDate_bom().getDayOfMonth(), c.getDate_bom().getMonthValue(), c.getDate_bom().getYear());
priceSeries.add(d, c.getPrice());
System.out.println("adding nav " + c.getNav() + "; date: " + c.getDate_bom());
navSeries.add(d, c.getNav());
}
final TimeSeriesCollection dataset = new TimeSeriesCollection(priceSeries);
dataset.addSeries(navSeries);
return dataset;
}
@Override
public void chartMouseClicked(ChartMouseEvent event) {
// ignore
}
@Override
public void chartMouseMoved(ChartMouseEvent event) {
Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
JFreeChart chart = event.getChart();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea,
RectangleEdge.BOTTOM);
double y = DatasetUtils.findYValue(plot.getDataset(), 0, x);
this.xCrosshair.setValue(x);
this.yCrosshair.setValue(y);
}
}
但是,我无法理解如何访问我独特的数据系列中的每个时间序列,以便将它们更改为条形图或更改它们的轴。我试过这个,但它改变了所有时间序列:
XYPlot plot = (XYPlot) chart.getPlot();
plot.getDataset().getSeriesKey(0);
plot.setRenderer(0,new XYBarRenderer());
谁能帮我解决这个问题?谢谢!
我最终放弃了使用具有多个序列的单个数据集的想法,而是使用了多个时间序列,正如我的问题的评论中所建议的那样,以 this code 作为模型。
public class Charts extends JFrame implements ChartMouseListener {
private TimeSeries priceSeries = new TimeSeries("Price");
private TimeSeries navSeries = new TimeSeries("Nav");
private ChartPanel chartPanel;
private Crosshair xCrosshair;
private Crosshair yCrosshair;
private Crosshair yNavCrosshair;
private Crosshair yDivCrosshair;
public Charts (List<CompanySummaryEuHistorical> sortedCos, String title) {
super(title);
setContentPane(createContent(sortedCos));
}
private JPanel createContent(List<CompanySummaryEuHistorical> sortedCos) {
// create series
createSeries(sortedCos);
XYDataset priceData = new TimeSeriesCollection(priceSeries);
XYLineAndShapeRenderer r0 = new XYLineAndShapeRenderer();
r0.setSeriesPaint(0, new Color(0, 0, 0x00));
r0.setSeriesShapesVisible(0, false);
XYLineAndShapeRenderer r2 = new XYLineAndShapeRenderer();
r2.setSeriesPaint(0, new Color(255, 41, 194));
r2.setSeriesShapesVisible(0, false);
XYLineAndShapeRenderer r3 = new XYLineAndShapeRenderer();
r3.setSeriesPaint(0, new Color(255, 49, 40));
r3.setSeriesShapesVisible(0, false);
// create chart with price and nav data series
JFreeChart chart = ChartFactory.createTimeSeriesChart(
title, "Date", "Value", priceData, true, true, true);
plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(192, 196, 196));
NumberAxis rangeAxis1 = (NumberAxis) plot.getRangeAxis();
rangeAxis1.setLowerMargin(0.40); // Leave room for volume bars
rangeAxis1.setNumberFormatOverride(NumberFormat.getCurrencyInstance(getCountry(sortedCos)));
plot.setRenderer(0, r0);
renderer = (XYLineAndShapeRenderer) plot.getRenderer();
renderer.setDefaultToolTipGenerator(new StandardXYToolTipGenerator(
StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
new SimpleDateFormat("dd/MM/YYYY"), NumberFormat.getCurrencyInstance()));
// nav series in bars
plot.setDataset(1, new TimeSeriesCollection(navSeries));
Charts.NavRender myRenderer = new NavRender();
myRenderer.setShadowVisible(false);
myRenderer.setDefaultToolTipGenerator(new StandardXYToolTipGenerator(
StandardXYToolTipGenerator.DEFAULT_TOOL_TIP_FORMAT,
new SimpleDateFormat("dd/MM/YYYY"), NumberFormat.getNumberInstance()));
plot.setRenderer(1, myRenderer);
// div series on second axis
NumberAxis rangeAxis2 = new NumberAxis("Value");
rangeAxis2.setUpperBound(rangeAxis1.getUpperBound()/10); // Leave room for price line
plot.setRangeAxis(1, rangeAxis2);
plot.setDataset(2, new TimeSeriesCollection(divSeries));
plot.mapDatasetToRangeAxis(2, 1);
plot.setRenderer(2, r2);
// create crosshair
this.chartPanel = new ChartPanel(chart);
this.chartPanel.addChartMouseListener(this);
CrosshairOverlay crosshairOverlay = new CrosshairOverlay();
this.xCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.xCrosshair.setLabelVisible(true);
this.xCrosshair.setLabelGenerator(crshr ->
new SimpleDateFormat("dd/MM/YYYY").format(crshr.getValue()));
this.yCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yCrosshair.setLabelVisible(true);
this.yNavCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yNavCrosshair.setLabelVisible(true);
this.yDivCrosshair = new Crosshair(Double.NaN, Color.GRAY, new BasicStroke(0f));
this.yDivCrosshair.setLabelVisible(true);
crosshairOverlay.addDomainCrosshair(xCrosshair);
crosshairOverlay.addRangeCrosshair(yCrosshair);
chartPanel.addOverlay(crosshairOverlay);
return chartPanel;
}
private JFreeChart createChart(XYDataset dataset) {
return ChartFactory.createTimeSeriesChart("Chart",
"Date", "Value", dataset);
}
private void createSeries(List<CompanySummaryEuHistorical> sortedCos) {
for (CompanySummaryEuHistorical c : sortedCos) {
Day d = new Day(c.getDate_bom().getDayOfMonth(), c.getDate_bom().getMonthValue(), c.getDate_bom().getYear());
priceSeries.add(d, c.getPrice());
navSeries.add(d, c.getNav());
divSeries.add(d, c.getDiv());}
}
@Override
public void chartMouseClicked(ChartMouseEvent event) {
// ignore
}
@Override
public void chartMouseMoved(ChartMouseEvent event) {
Rectangle2D dataArea = this.chartPanel.getScreenDataArea();
JFreeChart chart = event.getChart();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea,
RectangleEdge.BOTTOM);
double y = DatasetUtils.findYValue(plot.getDataset(), 0, x);
double yNav = DatasetUtils.findYValue(plot.getDataset(1), 0, x);
double yDiv = DatasetUtils.findYValue(plot.getDataset(2), 0, x);
this.xCrosshair.setValue(x);
this.yCrosshair.setValue(y);
this.yNavCrosshair.setValue(yNav);
this.yDivCrosshair.setValue(yDiv);
}
}