JFreeChart – 如何在TimeSeries图表的X轴上显示实时

我想在TimeSeries图表上显示实时数据, 实时显示在x轴上 (或者至少具有与实时相同的时间速度)。

这是一个问题的SSCCE,随机数作为实时输入。 x轴上显示的时间比实时快得多(假设它以hh:mm:ss格式显示):

public class DynamicTimeSeriesChart extends JPanel { private DynamicTimeSeriesCollection dataset; private JFreeChart chart = null; public DynamicTimeSeriesChart(final String title) { dataset = new DynamicTimeSeriesCollection(1, 2000, new Second()); dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 1990)); // date 1st jan 0 mins 0 secs dataset.addSeries(new float[1], 0, title); chart = ChartFactory.createTimeSeriesChart( title, "Time", title, dataset, true, true, false); final XYPlot plot = chart.getXYPlot(); ValueAxis axis = plot.getDomainAxis(); axis.setAutoRange(true); axis.setFixedAutoRange(200000); // proportional to scroll speed axis = plot.getRangeAxis(); final ChartPanel chartPanel = new ChartPanel(chart); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); add(chartPanel); } public void update(float value) { float[] newData = new float[1]; newData[0] = value; dataset.advanceTime(); dataset.appendData(newData); } public static void main(String[] args) { JFrame frame = new JFrame("testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final DynamicTimeSeriesChart chart = new DynamicTimeSeriesChart("random numbers"); frame.add(chart); frame.pack(); frame.setVisible(true); Timer timer = new Timer(100, new ActionListener() { public void actionPerformed(ActionEvent e) { EventQueue.invokeLater(new Runnable() { @Override public void run() { chart.update((float) (Math.random() * 10)); } }); } }); timer.start(); } } 

虽然在初始线程上可以接受sleep() ,但是应该在事件分派线程上构造和操作Swing GUI对象。 相反,使用javax.swing.Timer来调整更新速度,如下所示。 delay 100 ms将以大约10 Hz的频率更新。

如果漂移是不可接受的,则以另一个线程以标称速率的一半轮询主机的时钟,并使用EventQueue.invokeLater()更新数据集。 确保主机已同步到NTP服务器。

附录:根据您的更新,请注意,必须在事件派发线程上构建和操作所有 Swing GUI对象,而不仅仅是javax.swing.Timer 。 Swing Timer的优点是它可以在EDT上触发。 下面的变化显示近似实时的10秒1 Hz数据。

附录:您可以调整传递给setTimeBase()的时间,如下所示。

图片

 import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.SimpleDateFormat; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; 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.DynamicTimeSeriesCollection; import org.jfree.data.time.Second; /** * @see https://stackoverflow.com/a/21307289/230513 */ public class DynamicTimeSeriesChart extends JPanel { private final DynamicTimeSeriesCollection dataset; private final JFreeChart chart; public DynamicTimeSeriesChart(final String title) { dataset = new DynamicTimeSeriesCollection(1, 1000, new Second()); dataset.setTimeBase(new Second(0, 0, 0, 23, 1, 2014)); dataset.addSeries(new float[1], 0, title); chart = ChartFactory.createTimeSeriesChart( title, "Time", title, dataset, true, true, false); final XYPlot plot = chart.getXYPlot(); DateAxis axis = (DateAxis) plot.getDomainAxis(); axis.setFixedAutoRange(10000); axis.setDateFormatOverride(new SimpleDateFormat("ss.SS")); final ChartPanel chartPanel = new ChartPanel(chart); add(chartPanel); } public void update(float value) { float[] newData = new float[1]; newData[0] = value; dataset.advanceTime(); dataset.appendData(newData); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame("testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); final DynamicTimeSeriesChart chart = new DynamicTimeSeriesChart("Alternating data"); frame.add(chart); frame.pack(); Timer timer = new Timer(1000, new ActionListener() { private boolean b; @Override public void actionPerformed(ActionEvent e) { chart.update(b ? 1 : 0); b = !b; } }); timer.start(); frame.setVisible(true); } }); } }