2

X 軸にリアルタイムが表示された TimeSeries グラフにライブ データを表示したい(または、少なくとも時間の速度をリアルタイムと同じにしたい)。

これは、ライブ入力として乱数を使用した問題の 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();
    }
}
4

1 に答える 1

4

初期スレッドでは許容さsleep()れますが、Swing GUI オブジェクトは、イベント ディスパッチ スレッドでのみ構築および操作する必要があります。代わりに、ここに示すように、a を使用して更新のペースを調整します。100 msの Aは、約 10 Hz で更新されます。javax.swing.Timerdelay

ドリフトが許容できない場合は、公称速度の半分で別のスレッドからホストのクロックをポーリングし、 を使用してデータセットを更新しEventQueue.invokeLater()ます。ホストが NTP サーバーに同期されていることを確認します。

補遺: あなたの更新に基づいて、すべてのSwing GUI オブジェクトjavax.swing.Timer. Swing の利点はTimer、EDT で起動することです。以下の変動は、ほぼリアルタイムでの 1 Hz データの 10 秒間を示しています。

補遺:ここ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);
            }
        });
    }
}
于 2014-01-23T11:49:02.860 に答える