【问题标题】:JFreeChart - How to show real-time on the X-Axis of a TimeSeries chartJFreeChart - 如何在 TimeSeries 图表的 X 轴上实时显示
【发布时间】:2014-02-13 11:09:57
【问题描述】:

我想在 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();
    }
}

【问题讨论】:

    标签: java real-time jfreechart timeserieschart


    【解决方案1】:

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

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

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

    附录:您可以调整传递给setTimeBase()的时间,如图here

    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);
                }
            });
        }
    }
    

    【讨论】:

    • 我已更改 SSCCE 代码以使用您对 Timer 和 EventQueue.invokeLater() 的建议。但问题仍然存在。我不知道如何“轮询主机的时钟”或“确保主机与 NTP 服务器同步”。我不知道如何设置图表的时间。
    • 对您的附录的评论:您的示例图表似乎以实时速度显示时间,但是当我将计时器的速率更改为 1 Hz 以外的任何值时,图表显示时间为不同的速度。我希望图表能够以真实速度显示时间,而不管数据更新率如何。感谢您迄今为止所做的努力。
    • 实时为1Hz;您可以合并以不同速率到达的事件。
    • 我希望图表能够以高于 1Hz 的速率进行视觉更新,并以真实速度显示时间。你知道怎么做吗?
    • 您可能能够使用不同的刻度单位获得所需的效果,提到了here
    猜你喜欢
    • 1970-01-01
    • 2012-01-09
    • 1970-01-01
    • 2012-10-02
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 2012-08-23
    • 1970-01-01
    相关资源
    最近更新 更多