Converting a Jfreechart Timeseries Series with Day Data to Week or Month Data

JFreeChart: create a chart with java.time.LocalDate or java.time.LocalDateTime

In the case of LocalDate, you can create a time series chart by constructing the corresponding Day, as shown below.

LocalDate ld = entry.getKey();
Day d = new Day(ld.getDayOfMonth(), ld.getMonthValue(), ld.getYear());
series.add(d, entry.getValue());

If you have relevant time zone data, you can use it when constructing the Day. A similar approach can be used for LocalDateTime and any desired concrete RegularTimePeriod. See also the approach shown here and here, given an Instant. Moreover, a custom implementation of XYDataset, seen here, can simply convert the result of toEpochMilli() and return it from getX().

image


import java.awt.Dimension;
import java.awt.EventQueue;
import java.text.DateFormat;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;

/**
* @see https://stackoverflow.com/a/66713994/230513
* @see https://stackoverflow.com/a/12481509/230513
*/
public class XYTest {

private static final int N = 16;

private XYDataset createDataset() {
long t = LocalDate.now().toEpochDay();
Map<LocalDate, Integer> dateToCountMap = new HashMap<>();
for (int i = 0; i < N; i++) {
dateToCountMap.put(LocalDate.ofEpochDay(t + i), (int) Math.pow(i, 1.61));
}
TimeSeries series = new TimeSeries("Data)");
for (Map.Entry<LocalDate, Integer> entry : dateToCountMap.entrySet()) {
LocalDate ld = entry.getKey();
Day d = new Day(ld.getDayOfMonth(), ld.getMonthValue(), ld.getYear());
series.add(d, entry.getValue());
}
return new TimeSeriesCollection(series);
}

private JFreeChart createChart(final XYDataset dataset) {
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"Test", "Day", "Value", dataset, false, false, false);
XYPlot plot = (XYPlot) chart.getPlot();
DateAxis domain = (DateAxis) plot.getDomainAxis();
domain.setDateFormatOverride(DateFormat.getDateInstance());
return chart;
}

static void create() {
JFrame frame = new JFrame("Bar Chart");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
XYTest xyTest = new XYTest();
XYDataset dataset = xyTest.createDataset();
JFreeChart chart = xyTest.createChart(dataset);
ChartPanel chartPanel = new ChartPanel(chart) {

@Override
public Dimension getPreferredSize() {
return new Dimension(800, 300);
}
};
frame.add(chartPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) {
EventQueue.invokeLater(XYTest::create);
}
}

Plotting data over time with JFreeChart

The RelativeDateFormat class is designed for exactly this purpose. Your data doesn't need to change (it is correct as-is), just the presentation needs to be adapted. So create an instance of RelativeDateFormat, passing it the start time of your simulation, and use this as the date formatter for your axis. It will display times relative to the start time.

Combining XYPlot and TimeSeries elements in JFreeChart

You'll need to combine several elements to get the desired effect:

  • Start with ChartFactory.createXYBarChart(), as shown below and here.

  • Use a DateAxis for the domain axis, as shown here.

  • Use setDateFormatOverride() on the domain axis to apply your SimpleDateFormat.

  • Use a SymbolAxis for the range axis to replace integer values with your symbols, as shown here and here.

image

RegularTimePeriod creation or convertion in java

You can override the date format. Related examples may be found here and here.

axis.setDateFormatOverride(DateFormat.getTimeInstance());

JFreeChart using shifting one series by a given offset value

DefaultXYDataset is convenient for accessing individual elements of different series, but it doesn't expose the methods needed to manipulate the internal data structures in this way. Instead, implement the XYDataset interface by extending AbstractXYDataset, as shown here, where you can encapsulate the offset plumbing. You may also want to look at SlidingXYDataset, cited here.

Relative Timestamps in a TimeSeries

ChartFactory.createXYLineChart() creates two instances of NumberAxis, one for each of the domain and range. As an alternative, consider ChartFactory.createTimeSeriesChart(), which uses a DateAxis for the domain. In either case, you can use setXxxFormatOverride() on the axis to get any desired format. The example shown here specifies a factory DateFormat.

JFreeChart with truncated data points

This is my current approach on the chart how data is being rendered...

private static JFreeChart buildChart(TimeSeriesCollection dataset,
String title, boolean endPoints) throws IOException {
// Create the chart
JFreeChart chart0 = ChartFactory.createTimeSeriesChart(
title,
"Hour", "Count",
dataset,
true,
true,
false);

// Setup the appearance of the chart

chart0.setBackgroundPaint(Color.white);
XYPlot plot = (XYPlot) chart0.getXYPlot();
plot.getDomainAxis().setAutoRange(true);
plot.getRangeAxis().setRange(1.0, SucMaxi);
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
plot.getAxisOffset();
plot.setAxisOffset(new RectangleInsets(10.0, 10.0, 10.0, 10.0));
plot.setDomainCrosshairVisible(true);
plot.setRangeCrosshairVisible(true);

// Display data points or just the lines?

if (endPoints) {
XYItemRenderer renderer = plot.getRenderer();
if (renderer instanceof StandardXYItemRenderer) {
StandardXYItemRenderer rr = (StandardXYItemRenderer) renderer;
rr.setBaseShapesVisible(true);
rr.setBaseShapesFilled(true);
rr.setDrawSeriesLineAsPath(true);
rr.setSeriesPaint(0, Color.blue.brighter());
rr.setSeriesVisible(0, true); // default
rr.setSeriesVisibleInLegend(0, true); // default
}
}

// Tell the chart how we would like dates to read

DateAxis axis = (DateAxis) plot.getDomainAxis();

// Tick the X Axis by unit tick 1 hour
axis.setTickUnit(new DateTickUnit(DateTickUnitType.HOUR, 1));
axis.setDateFormatOverride(new SimpleDateFormat("HH:mm"));

try {
ChartUtilities.saveChartAsJPEG(
new File("suc.jpg"), 1.0f, chart0, 1000, 700);
} catch (IOException e) {
e.printStackTrace();
}

return chart0;
}

Sample Image



Related Topics



Leave a reply



Submit