Java中的实时绘图

Java中的实时绘图,java,graph,real-time,jfreechart,Java,Graph,Real Time,Jfreechart,我有一个应用程序,它每秒更新一个变量大约5到50次,我正在寻找某种方法来实时绘制这个变化的连续XY图 虽然JFreeChart不推荐这么高的更新率,但许多用户仍然说它适合他们。我尝试过使用demo并修改它来显示一个随机变量,但它似乎一直在使用100%的CPU。即使我忽略了这一点,我也不想局限于JFreeChart的ui类来构造表单(尽管我不确定它的功能到底是什么)。是否可以将其与Java的“表单”和下拉菜单集成?(如VB中提供的)否则,我有没有其他选择 EDIT:我是Swing新手,所以我编写了

我有一个应用程序,它每秒更新一个变量大约5到50次,我正在寻找某种方法来实时绘制这个变化的连续XY图

虽然JFreeChart不推荐这么高的更新率,但许多用户仍然说它适合他们。我尝试过使用demo并修改它来显示一个随机变量,但它似乎一直在使用100%的CPU。即使我忽略了这一点,我也不想局限于JFreeChart的ui类来构造表单(尽管我不确定它的功能到底是什么)。是否可以将其与Java的“表单”和下拉菜单集成?(如VB中提供的)否则,我有没有其他选择

EDIT:我是Swing新手,所以我编写了一段代码,只是为了测试JFreeChart的功能(同时避免使用JFree的ApplicationFrame类,因为我不确定如何使用Swing的组合框和按钮)。目前,图形正在立即更新,CPU使用率很高。是否可以使用new millis秒()缓冲该值,并可能每秒更新两次?另外,我可以在不中断JFreeChart的情况下将其他组件添加到JFrame的其余部分吗?我该怎么做?frame.getContentPane().add(新建按钮(“单击”)似乎覆盖了图形

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

}

如果变量更新得那么快,那么每次更新图表都没有意义

您是否考虑过缓冲变量更改,并在不同的线程上刷新图表,例如,每5秒刷新一次?您应该发现JFreeChart可以很好地处理此类更新率


由于JFreeChart是一个普通的桌面库,因此您可以非常轻松地将其与标准Swing应用程序集成。或者,您可以使用它通过web应用程序绘制图表(通过渲染为JPEG/PNG等。JFreeChart也可以自动生成图像贴图,因此您可以使用鼠标盖等)。

前面回答过。您的变量每秒最多更改50次,但在大多数情况下,您不需要在每次更改时都进行更新。相反,您可以定期更新图表(例如,每100ms更新一次)。

如果数据更新的频率高于您生成图表的频率,那么您应该在一个单独的线程中有一个任务来重新生成图表,并在完成后启动另一个重新生成。经常运行它并没有什么意义,但如果它的cpu负载太大,您可以限制它重新启动的频率。如果没有更新,则不会触发重新生成。我最近在工作中也做过类似的事情。除了节流,它什么都做

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;
    }
}
package net.commerce.zocalo.freechart;
//版权所有2009年克里斯·希伯特。版权所有。
//本软件根据麻省理工学院许可证的条款发布,一份副本
//其中的已包含在此发行版中的许可证文件中。
导入java.util.concurrent.AtomicBoolean;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Callable;
导入java.util.concurrent.Future;
导入java.util.Map;
导入java.util.HashMap;
/**安排一项任务,如生成价格历史图。可能会有多个请求
零星地。我们希望确保一次只处理一个。如果我们
忙着处理当一个请求进来时,我们会记得在这个请求发出时启动另一个请求
完成。处理过程中出现的多个请求将刺激一次重新启动*/
公共类图表调度器{
静态专用记录器log=Logger.getLogger(ChartScheduler.class);
静态私有映射调度器=新HashMap();
私有AtomicBoolean生成=新的AtomicBoolean(false);
请求的私有AtomicBoolean=新AtomicBoolean(false);
私有ExecutorService线程=Executors.newCachedThreadPool();
私有可调用可调用;
私有整数运行=0;
私有字符串名称;
私有ChartScheduler(字符串名称,最终可运行辅助进程){
this.name=名称;
callable=新的callable(){
公共布尔调用()引发异常{
worker.run();
运行++;
restartIfNeeded();
返回true;
}
};
}
公共静态图表调度器创建(字符串名称,可运行工作程序){
ChartScheduler sched=find(名称);
if(sched==null){
sched=新图表调度器(名称、工作人员);
schedulers.put(名称,sched);
}
返回时间表;
}
公共静态图表调度程序查找(字符串名称){
返回schedulers.get(名称);
}
公共布尔generateNewChart(){
请求。设置(true);
if(生成.compareAndSet(false,true)){
startNewThread();
返回true;
}否则{
返回false;
}
}
私有未来startNewThread(){
生成.set(true);
请求。设置(false);
返回线程。提交(可调用);
}
私有布尔重新启动需要(){
生成.set(false);
if(request.get()){
返回generateNewChart();
}否则{
返回false;
}
}
公共布尔值isBusy(){
返回生成.get();
}
公共int运行(){
回程;
}
}

也许您可以使用两个线程。一个用于更新变量witch优先级等于10。 第二个线程的绘制速度非常快,可能的女巫优先级等于5

在我正在写的一个游戏中,我也必须这样做


有可能我不理解你的问题。

我也在使用JFreechart进行高更新。JFreeChart更新速度高达10到15帧/秒,但使用100%的CPU使用率。但是如果我想以更高的频率更新它,它将不会被更新。如果您找到任何可以以每秒20帧的速度更新并可以使用的库