JFreeChart - How to show real-time on the X-Axis of a TimeSeries chart

ぐ巨炮叔叔 提交于 2019-11-26 22:25:10

问题


I want to show live data on a TimeSeries chart with real time shown on the x-axis (or at least have the speed of the time the same as real-time).

Here is a SSCCE of the problem with random numbers as the live input. The time shown on the x-axis is much faster than real-time (assuming it is shown in hh:mm:ss format):

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

回答1:


While it is acceptable to sleep() on the initial thread, Swing GUI objects should be constructed and manipulated only on the event dispatch thread. Instead, use a javax.swing.Timer to pace the updates, as shown here. A delay of 100 ms will update at approximately 10 Hz.

If the drift is unacceptable, poll the host's clock from another thread at half the nominal rate and update the dataset using EventQueue.invokeLater(). Ensure that the host is synchronized to an NTP server.

Addendum: Based on your update, note that all Swing GUI objects must be constructed and manipulated only on the event dispatch thread, not just the javax.swing.Timer. The advantage of a Swing Timer is that it fires on the EDT. The variation below shows 10 seconds of 1 Hz data at approximately real time.

Addendum: You can adjust the time passed to setTimeBase() as shown 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);
            }
        });
    }
}


来源:https://stackoverflow.com/questions/21299096/jfreechart-how-to-show-real-time-on-the-x-axis-of-a-timeseries-chart

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!