15

私は1秒間に約5〜50回変数を更新するアプリケーションを持っており、この変化の連続XYプロットをリアルタイムで描画する方法を探しています。

JFreeChartはこのような高い更新率にはお勧めできませんが、多くのユーザーはそれでもうまくいくと言っています。このデモを使用してランダム変数を表示するように変更しましたが、常に100%のCPU使用率を消費しているようです。それを無視しても、フォームを作成するためにJFreeChartのuiクラスに制限されたくはありません(ただし、その機能が正確に何であるかはわかりません)。それをJavaの「フォーム」およびドロップダウンメニューと統合することは可能でしょうか?(VBで利用可能)それ以外の場合、私が調べることができる代替案はありますか?

編集:私はSwingを初めて使用するので、JFreeChartの機能をテストするためだけにコードをまとめました(Swingのコンボでどのように機能するかわからないため、JFreeのApplicationFrameクラスの使用は避けています)ボックスとボタン)。現在、グラフはすぐに更新されており、CPU使用率が高くなっています。new Millisecond()で値をバッファリングし、1秒に2回更新することは可能でしょうか?また、JFreeChartを中断せずに、JFrameの残りの部分に他のコンポーネントを追加できますか?どうすればいいですか?frame.getContentPane()。add(new Button( "Click"))がグラフを上書きしているようです。

package graphtest;

import java.util.Random;
import javax.swing.JFrame;
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.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;

public class Main {
    static TimeSeries ts = new TimeSeries("data", Millisecond.class);

    public static void main(String[] args) throws InterruptedException {
        gen myGen = new gen();
        new Thread(myGen).start();

        TimeSeriesCollection dataset = new TimeSeriesCollection(ts);
        JFreeChart chart = ChartFactory.createTimeSeriesChart(
            "GraphTest",
            "Time",
            "Value",
            dataset,
            true,
            true,
            false
        );
        final XYPlot plot = chart.getXYPlot();
        ValueAxis axis = plot.getDomainAxis();
        axis.setAutoRange(true);
        axis.setFixedAutoRange(60000.0);

        JFrame frame = new JFrame("GraphTest");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ChartPanel label = new ChartPanel(chart);
        frame.getContentPane().add(label);
        //Suppose I add combo boxes and buttons here later

        frame.pack();
        frame.setVisible(true);
    }

    static class gen implements Runnable {
        private Random randGen = new Random();

        public void run() {
            while(true) {
                int num = randGen.nextInt(1000);
                System.out.println(num);
                ts.addOrUpdate(new Millisecond(), num);
                try {
                    Thread.sleep(20);
                } catch (InterruptedException ex) {
                    System.out.println(ex);
                }
            }
        }
    }

}
4

8 に答える 8

8

変数がそれほど速く更新されている場合、チャートを毎回更新しても意味がありません。

変数の変更をバッファリングし、別のスレッド、たとえば5秒ごとにグラフを更新することを考えましたか?JFreeChartがそのような更新レートをうまく処理できることがわかるはずです。

JFreeChartは通常のデスクトップライブラリであるため、標準のSwingアプリケーションと非常に簡単に統合できます。または、Webアプリケーションを介してグラフ化するために使用できます(JPEG / PNGなどにレンダリングします。JFreeChartは画像マップも自動的に生成できるため、マウスオーバーなどを使用できます)。

于 2009-09-07T12:53:10.333 に答える
4

CPU を 100% より十分に低くして GUI の応答性を維持するには、チャートの更新速度を下げる必要があります。毎秒約 24 フレームの最大更新レートは、リアルタイム チャートには理にかなっています。いずれにせよ、より速いものは多かれ少なかれ区別がつきません。データがその速度よりも速く入ってくる場合は、バックグラウンドでデータをバッファリングし、必要な更新速度でフォアグラウンドでグラフを更新するだけです。次の例では、バックグラウンド スレッドと共にXChartを使用しています。SwingWorkerデータ キャプチャは 5 ミリ秒ごとに 1 つの割合でシミュレートされ、チャートは 1 秒あたり 24 フレームで更新されます。この概念は、JFreeCharts やその他のグラフ作成ライブラリでも、わずかな変更で機能するはずです。免責事項: 私は XChart の主任開発者です。

import java.util.LinkedList;
import java.util.List;

import javax.swing.SwingWorker;

import org.knowm.xchart.QuickChart;
import org.knowm.xchart.SwingWrapper;
import org.knowm.xchart.XYChart;

/**
 * Creates a real-time chart using SwingWorker
 */
public class SwingWorkerRealTime {

  MySwingWorker mySwingWorker;
  SwingWrapper<XYChart> sw;
  XYChart chart;

  public static void main(String[] args) throws Exception {

    SwingWorkerRealTime swingWorkerRealTime = new SwingWorkerRealTime();
    swingWorkerRealTime.go();
  }

  private void go() {

    // Create Chart
    chart = QuickChart.getChart("SwingWorker XChart Real-time Demo", "Time", "Value", "randomWalk", new double[] { 0 }, new double[] { 0 });
    chart.getStyler().setLegendVisible(false);
    chart.getStyler().setXAxisTicksVisible(false);

    // Show it
    sw = new SwingWrapper<XYChart>(chart);
    sw.displayChart();

    mySwingWorker = new MySwingWorker();
    mySwingWorker.execute();
  }

  private class MySwingWorker extends SwingWorker<Boolean, double[]> {

    LinkedList<Double> fifo = new LinkedList<Double>();

    public MySwingWorker() {

      fifo.add(0.0);
    }

    @Override
    protected Boolean doInBackground() throws Exception {

      while (!isCancelled()) {

        fifo.add(fifo.get(fifo.size() - 1) + Math.random() - .5);
        if (fifo.size() > 500) {
          fifo.removeFirst();
        }

        double[] array = new double[fifo.size()];
        for (int i = 0; i < fifo.size(); i++) {
          array[i] = fifo.get(i);
        }
        publish(array);

        try {
          Thread.sleep(5);
        } catch (InterruptedException e) {
          // eat it. caught when interrupt is called
          System.out.println("MySwingWorker shut down.");
        }

      }

      return true;
    }

    @Override
    protected void process(List<double[]> chunks) {

      System.out.println("number of chunks: " + chunks.size());

      double[] mostRecentDataSet = chunks.get(chunks.size() - 1);

      chart.updateXYSeries("randomWalk", null, mostRecentDataSet, null);
      sw.repaintChart();

      long start = System.currentTimeMillis();
      long duration = System.currentTimeMillis() - start;
      try {
        Thread.sleep(40 - duration); // 40 ms ==> 25fps
        // Thread.sleep(400 - duration); // 40 ms ==> 2.5fps
      } catch (InterruptedException e) {
      }

    }
  }
}

XChart SwingWorker リアルタイム Java チャート

于 2016-08-09T12:54:07.763 に答える
1

このブログ投稿によると:

http://jonathanwatmough.com/2008/02/prototyping-code-in-clojure/

KJ DSPライブラリを使用して、オーディオスペクトルの「リアルタイム」表示を実装することが可能です。

http://sirk.sytes.net/software/libs/kjdss/index.htm

したがって、かなり単純なチャートでうまくいくことができれば、JFreeChartの代わりになるかもしれません。

于 2009-09-10T05:44:12.617 に答える
1

グラフを生成できるよりも頻繁にデータが更新される場合は、グラフを再生成し、完了時に別の再生成を開始する別のスレッドにタスクを用意する必要があります。それ以上頻繁に実行してもほとんど意味がありませんが、CPU 負荷が高すぎることが判明した場合は、再起動の頻度を下げることができます。更新が届かない場合は、再生成をトリガーしません。私は 最近、私のZocalo プロジェクトでそのようなことをしました。スロットルバック以外のすべてを行います。

package net.commerce.zocalo.freechart;

// Copyright 2009 Chris Hibbert.  All rights reserved.

// This software is published under the terms of the MIT license, a copy
// of which has been included with this distribution in the LICENSE file.

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.Map;
import java.util.HashMap;

/**  Schedule a task like generating a price history graph.  Multiple requests may come
 in sporadically.  We want to ensure that only one is being processed at a time.  If we're
 busy processing when a request comes in, we'll remember to start another when this one is
 done.  Multiple requests that come in while processing will spur a single restart. */
public class ChartScheduler {
    static private Logger log = Logger.getLogger(ChartScheduler.class);
    static private Map<String, ChartScheduler> schedulers = new HashMap<String, ChartScheduler>();
    private AtomicBoolean generating = new AtomicBoolean(false);
    private AtomicBoolean requested = new AtomicBoolean(false);
    private ExecutorService threads = Executors.newCachedThreadPool();
    private Callable<Boolean> callable;
    private int runs = 0;
    private String name;


    private ChartScheduler(String name, final Runnable worker) {
        this.name = name;
        callable = new Callable<Boolean>() {
            public Boolean call() throws Exception {
                worker.run();
                runs++;
                restartIfNeeded();
                return true;
            }
        };
    }

    public static ChartScheduler create(String name, Runnable worker) {
        ChartScheduler sched = find(name);
        if (sched == null) {
            sched = new ChartScheduler(name, worker);
            schedulers.put(name, sched);
        }
        return sched;
    }

    public static ChartScheduler find(String name) {
        return schedulers.get(name);
    }

    public boolean generateNewChart() {
        requested.set(true);
        if (generating.compareAndSet(false, true)) {
            startNewThread();
            return true;
        } else {
            return false;
        }
    }

    private Future<Boolean> startNewThread() {
        generating.set(true);
        requested.set(false);

        return threads.submit(callable);
    }

    private boolean restartIfNeeded() {
        generating.set(false);
        if (requested.get()) {
            return generateNewChart();

        } else {
            return false;
        }
    }

    public boolean isBusy() {
        return generating.get();
    }

    public int runs() {
        return runs;
    }
}
于 2009-09-07T15:48:57.013 に答える
0

ここの前に答えた。変数は 1 秒あたり最大 50 回変更されますが、ほとんどの場合、変更が行われるたびに更新する必要はありません。代わりに、一定の間隔で (たとえば 100 ミリ秒ごとに) グラフを更新できます。

于 2009-09-07T13:02:16.150 に答える
0

VisualVM (JDK の一部) からチャートを試してみてください。イントロ: http://java.dzone.com/news/real-time-charts-java-desktop

于 2013-10-07T19:31:23.817 に答える
0

まあ、私はJFreechartを使って最新情報を更新しています。JFreeChart は毎秒 10 ~ 15 フレームまで更新しますが、CPU 使用率は 100% です。しかし、もっと高い頻度で更新したい場合は、更新されません。約 20 fps で更新でき、Java でアプリケーションを開発するために使用できるライブラリを見つけた場合は、私にも提案してください。多くのライブラリJFreeChart FAQを見てきましたが、約 20 fps での更新に誰かが使用できるかどうかはわかりません。

于 2009-09-10T05:15:12.220 に答える
0

たぶん、2つのスレッドを使用できます。1 つは変数のウィッチ優先度を更新するためのもので、10 に等しくなります。そして、可能なウィッチ優先度が 5 に等しいほど高速に描画する 2 番目のスレッド。

私が書いているゲームでも同じことをしなければなりませんでした。

私はあなたの質問を理解していなかった可能性があります。

于 2009-09-07T17:29:59.807 に答える