【问题标题】:Glitchy graphing using JFreeChart使用 JFreeChart 进行故障绘图
【发布时间】:2009-10-13 12:41:34
【问题描述】:

我正在使用 JFreeChart 绘制几个 TimeSeries 图表。它似乎工作正常,但截至今天,所有图表似乎都在闪烁并且随机出现故障,使它们无法看到。如果我最小化和最大化,问题会在几秒钟内得到修复,直到下一次更新或单击鼠标。有人知道问题可能是什么吗?

代码很简单:

TimeSeries ts = new TimeSeries("Graph", Millisecond.class);
TimeSeriesCollection dataset = new TimeSeriesCollection(ts);
JFreeChart Graph = createChart(dataset);
ChartPanel panel_Graph = new ChartPanel(Graph);

....

JFrame newWindow = new JFrame("Graph");
newWindow.setLayout(new GridLayout());
newWindow.setContentPane(panel_Graph);
newWindow.setMinimumSize(new Dimension(600, 480));
newWindow.setLocationRelativeTo(null);
newWindow.setVisible(true);


static private JFreeChart createChart(TimeSeriesCollection dataset) {
        JFreeChart chart = ChartFactory.createTimeSeriesChart(
            "Graph",
            "Time",
            "Value",
            dataset,
            false,
            true,
            false
        );
        final XYPlot plot = chart.getXYPlot();
        ValueAxis timeaxis = plot.getDomainAxis();
        timeaxis.setAutoRange(true);
        timeaxis.setFixedAutoRange(60000.0);
        return chart;
}

【问题讨论】:

  • 为什么将 XYPlot 标记为最终图?
  • 嗯,这只是在互联网上尝试不同的解决方案以尝试解决问题的剩余部分。删除它没有任何区别。

标签: java graph jfreechart


【解决方案1】:

如果您看到不一致/损坏的图像,有时表示正在更新事件调度线程以外的线程上的数据集。我建议您添加一些断言语句来验证这一点:

断言 SwingUtilities.isEventDispatchThread();

另外,请注意,JFreeChart 并不是特别有效,因为它会在添加新数据点时重新渲染整个图表。您可以在此处进行的一项优化是:

  • 如果您的应用程序包含多个图表,则只为当前显示的图表传播DatasetChangeEvents。如果图表被隐藏(例如在不同的选项卡上),则只需记录它已过时并且需要在选择选项卡时重新呈现这一事实。

编辑

根据您对 Dan 回复的评论,听起来您的 I/O 线程接收消息也在更新 JFreeChart 数据集,而实际上更新应该在事件调度线程上执行(并且消息应该在单独的 I /O 线程)。为此,我建议您使用基于节流阀的方法,将 I/O 事件存储在一起。您可以使用BlockingQueue 来实现此目的;例如

// Message definition containing update information.
public interface Message { ... }

// BlockingQueue implementation used to enqueue updates received on I/O thread.
BlockingQueue<Message> msgQ = ...

// Method called by I/O thread when a new Message is received.
public void msgReceived(Message msg) {
  boolean wasEmpty = msgQ.isEmpty();

  msgQ.add(msg);

  // Queue was empty so need to re-invoke Swing thread to process queue.
  if (wasEmpty) {
    // processUpdates is a re-useable Runnable defined below.
    SwingUtilities.invokeLater(processUpdates);
  }
}

// Runnable that processes all enqueued events.  Much more efficient than:
// a) Creating a new Runnable each time.
// b) Processing one Message per call to run().
private final Runnable processUpdates = new Runnable() {
  public void run() {
    Message msg;

    while ((msg = msgQ.poll) != null) {
      // Add msg to dataset within Event Dispatch thread.
    }
  }
}

【讨论】:

  • 我已经把断言 SwingUtilities.isEventDispatchThread();就在收到消息后更新数据集的点上方,它似乎没有任何区别。此外,似乎如果我单击图表(没有拖动或任何东西),问题会变得更糟。 i18.photobucket.com/albums/b115/thodinc/jfreebug.jpg
  • 现在,我只是打开一个新的 JFrame 来显示图表,但选项卡式的想法听起来也不错。但是,即使只打开一个图形,也会出现问题。即使我移至旧版本的代码,它过去也不会发生,现在也会发生。
  • 虽然您的消息处理实现比我所做的要高效得多,但它似乎对图形部分没有任何影响。我已将 LinkedBlockingQueue 与 invokeLater 一起使用,但图表仍然损坏。
【解决方案2】:

您如何将数据点添加到图表中?你是在 AWT 事件调度线程上做的吗?您可能应该使用SwingUtilities.invokeAndWait。您可以使用 invokeLater,但如果您的程序忙于做其他事情,则 GUI 可能不会及时更新。

另外,您有多少数据点?我discovered 固定自动范围的代码对于大量数据点来说效率很低。这可能已在最新版本中修复(我不知道)。

【讨论】:

  • 好吧,我有一个单独的线程,它接收来自另一个节点的消息并将双精度值添加到系列中: ts.addOrUpdate(new Millisecond(), Update);在一种情况下,每 10 秒就有一个新数据点到达,而在另一种情况下,每秒最多 5 次。但是,两者似乎都遇到了同样的问题。
  • 此外,在以 10 秒为间隔的更新的情况下,第一个数据点在第二个数据点到达之前不会显示,然后两个点都可见。
  • 接收消息的线程需要将时间序列更新编组到事件调度线程。我建议使用 SwingUtilities.invokeLater 来防止你的 I/O 线程在 UI 更新时阻塞。
  • 我不确定到底是什么问题,因为我刚刚在另一台计算机上运行了该程序,而且看起来还不错。莫非是库坏了?
  • 问题已解决!似乎与我的图形驱动程序有冲突。我添加了以下标志,到目前为止没有问题:-Dsun.java2d.opengl=true
猜你喜欢
  • 1970-01-01
  • 2014-10-19
  • 2012-11-29
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 2012-02-22
  • 2018-10-14
  • 1970-01-01
相关资源
最近更新 更多