Использование JFreeChart для отображения последних изменений во временном ряду

Как я могу использовать JFreeChart для отображения только самых последних данных в постоянно обновляемом временном ряду?

Приложения: полный рабочий пример, включающий принятый ответ, показан здесь. См. также этот вариант с двумя сериями. См. также этот Вопросы и ответы относительно setTimeBase().


person trashgod    schedule 19.02.2011    source источник


Ответы (3)


Вы также можете удалить ноль, сначала advanceTime(), затем appendData. (поменяйте местами, как они это делают в примере).

person Don    schedule 04.05.2011
comment
@Bahadır: Хороший вопрос. Когда мой ответ был единственным, я принял его, чтобы сохранить свою скорость; но баллы не присуждались. После принятия @Don получил +15 за ответ, который помог всем нам, а я получил +2 за принятие. Я бы назвал это взаимовыгодным! :-) Извините, я пропустил этот комментарий ранее, когда отвечал @Sundhas. - person trashgod; 29.06.2011
comment
@trashgod Будущим читателям будет полезнее, если ваш ответ будет принят. Это сбивало с толку на мгновение или два, пока я не понял, что это был вопрос в стиле часто задаваемых вопросов, а полный ответ приведен ниже! - person Duncan Jones; 24.04.2013
comment
@DuncanJones: Хороший вопрос; обновлено в вопросе. Я оставляю это как принятый ответ, поскольку он цитируется в другом месте. - person trashgod; 24.04.2013

Класс JFreeChart DynamicTimeSeriesCollection — хороший выбор.

Приложение: Как отметил @Bahadır, последняя точка серии постоянно равна нулю. @Don услужливо предлагает перевести время вперед и затем добавить данные.

dataset.advanceTime();
dataset.appendData(newData);

введите здесь описание изображения

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JComboBox;
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.ValueAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.time.DynamicTimeSeriesCollection;
import org.jfree.data.time.Second;
import org.jfree.data.xy.XYDataset;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.chart.ui.UIUtils;

/**
 * @see http://stackoverflow.com/a/15521956/230513
 * @see http://stackoverflow.com/questions/5048852
 */
public class DTSCTest extends ApplicationFrame {

    private static final String TITLE = "Dynamic Series";
    private static final String START = "Start";
    private static final String STOP = "Stop";
    private static final float MINMAX = 100;
    private static final int COUNT = 2 * 60;
    private static final int FAST = 100;
    private static final int SLOW = FAST * 5;
    private static final Random random = new Random();
    private Timer timer;

    public DTSCTest(final String title) {
        super(title);
        final DynamicTimeSeriesCollection dataset =
            new DynamicTimeSeriesCollection(1, COUNT, new Second());
        dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 2011));
        dataset.addSeries(gaussianData(), 0, "Gaussian data");
        JFreeChart chart = createChart(dataset);

        final JButton run = new JButton(STOP);
        run.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String cmd = e.getActionCommand();
                if (STOP.equals(cmd)) {
                    timer.stop();
                    run.setText(START);
                } else {
                    timer.start();
                    run.setText(STOP);
                }
            }
        });

        final JComboBox combo = new JComboBox();
        combo.addItem("Fast");
        combo.addItem("Slow");
        combo.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if ("Fast".equals(combo.getSelectedItem())) {
                    timer.setDelay(FAST);
                } else {
                    timer.setDelay(SLOW);
                }
            }
        });

        this.add(new ChartPanel(chart) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(640, 480);
            }
        }, BorderLayout.CENTER);
        JPanel btnPanel = new JPanel(new FlowLayout());
        btnPanel.add(run);
        btnPanel.add(combo);
        this.add(btnPanel, BorderLayout.SOUTH);

        timer = new Timer(FAST, new ActionListener() {
            float[] newData = new float[1];

            @Override
            public void actionPerformed(ActionEvent e) {
                newData[0] = randomValue();
                dataset.advanceTime();
                dataset.appendData(newData);
            }
        });
    }

    private float randomValue() {
        return (float) (random.nextGaussian() * MINMAX / 3);
    }

    private float[] gaussianData() {
        float[] a = new float[COUNT];
        for (int i = 0; i < a.length; i++) {
            a[i] = randomValue();
        }
        return a;
    }

    private JFreeChart createChart(final XYDataset dataset) {
        final JFreeChart result = ChartFactory.createTimeSeriesChart(
            TITLE, "hh:mm:ss", "milliVolts", dataset, true, true, false);
        final XYPlot plot = result.getXYPlot();
        ValueAxis domain = plot.getDomainAxis();
        domain.setAutoRange(true);
        ValueAxis range = plot.getRangeAxis();
        range.setRange(-MINMAX, MINMAX);
        return result;
    }

    public void start() {
        timer.start();
    }

    public static void main(final String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                DTSCTest demo = new DTSCTest(TITLE);
                demo.pack();
                UIUtils.centerFrameOnScreen(demo);
                demo.setVisible(true);
                demo.start();
            }
        });
    }
}
person trashgod    schedule 19.02.2011
comment
Спасибо за этот отличный образец. Знаете ли вы, как сделать так, чтобы последняя точка линии не равнялась нулю? - person Bahadır Yağan; 28.04.2011
comment
@Bahadır: Похоже, это преднамеренный эффект advanceTime(). У меня никогда не было варианта использования другого базового значения. Есть предположения? Не забудьте проголосовать за ответы, которые показались вам полезными. :-) - person trashgod; 28.04.2011
comment
Последний раз вы голосовали за этот ответ 25 апреля в 13:11 Я всегда так делаю. Кстати, я исправил это, используя TimeSeriesCollection вместо динамического. Затем заменил dataset.appendData на add и установил время жизни для набора данных. Он дает примерно такой же функционал. - person Bahadır Yağan; 29.04.2011
comment
@Bahadır: А, понятно; спасибо за это, а также за альтернативный подход. - person trashgod; 29.04.2011
comment
@Bahadir, могу я попросить вас поделиться кодом, который вы реализовали? - person Sundhas; 28.06.2011
comment
Я хочу спросить вас, @trashgod, можем ли мы сохранить этот график и сделать его видимым на нашей веб-странице? если да то как? - person Sundhas; 29.06.2011
comment
@Sundhas Я бы использовал код TrashGod с исправлением Дона, если бы делал это снова и снова. Но я могу найти его завтра, когда буду на работе, если он тебе еще нужен. - person Bahadır Yağan; 29.06.2011
comment
@Sundhas сохранение графика - это другой вопрос, пожалуйста, создайте для этого новый вопрос. - person Bahadır Yağan; 29.06.2011
comment
@Sundhas: для моментального снимка используйте ChartUtilities с сервлетом/JSP, как предлагается здесь; для живого я бы использовал Java Web Start. @Bahadır: Спасибо за подтверждение. - person trashgod; 29.06.2011
comment
@trashgod Я не хочу сохранять его как снимок, я хочу, чтобы движущийся график был на моей веб-странице. - person Sundhas; 29.06.2011
comment
@Sundhas: интерактивный? Я бы использовал апплет через JWS. - person trashgod; 29.06.2011
comment
@trashgod Как добавить еще одну строку и еще одну ось Y слева с помощью DynamicTimeSeries? - person Forrest; 28.08.2016
comment
@DươngAnhKhoa: начните с варианта, указанного в вопросе и этом пример. - person trashgod; 28.08.2016

Одним из альтернативных подходов к ответу @thrashgod было бы использование TimeSeriesCollection и установка возраста элемента в файле TimeSeries. Ниже код может настроить график для отображения данных за последний 1 час с интервалом в 1 минуту.

private TimeSeriesCollection dataset;
private TimeSeries sensorSeries;
sensorSeries = new TimeSeries("name", Minute.class);
sensorSeries.setMaximumItemAge(60);
dataset = new TimeSeriesCollection();
dataset.addSeries(sensorSeries);

.. и вы добавите данные по мере их поступления:

sensorSeries.add(new Minute(new Date()), newData);
person Bahadır Yağan    schedule 29.06.2011
comment
См. также этот Вопросы и ответы. - person trashgod; 02.08.2011