【问题标题】:Preserve user zoom state when updating JFreeChart更新 JFreeChart 时保留用户缩放状态
【发布时间】:2012-07-30 16:27:15
【问题描述】:

我正在使用JFreeChart 1.0.14 绘制XYSeries。我确实可以访问所有元素(ChartPanelJFreeChartXYSeriesCollectionXYSeries)。不时有新数据要绘制,所以我更新我的系列(为简单起见,我们假设只有一个系列):

SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        XYSeries xyData = new XYSeries("Trace");
        for (int i = 0; i < n; i++)
            xyData.add(data[0][i], data[1][i], false);

        collection.removeAllSeries();
        collection.addSeries(xyData);

        chart.getXYPlot().setRangeAxis(createNewAxis());
    }
});

这一切都很好。但我有一个问题。用户可以通过在绘图中拖动来进行缩放。每次都会重置此缩放,更新数据。这是有道理的,因为我创建了新轴。如何保留用户缩放状态?由于用户还可以选择自动量程/量程,我不想对这些 (Axis#setRange/setAutoRange) 进行某种破解。我发现了一些关于ChartPanel#getScaleX() 的信息。但这始终是上述invokeLater 开头的1.0。我也找不到任何ChartPanel.setScaleX

我做错了什么还是有另一种方法可以在不更改轴的范围/自动范围行为的情况下保留用户缩放状态?

顺便说一句:我必须重新创建坐标区,因为它们还可以在 logscale 和 linscale 之间切换。

【问题讨论】:

    标签: java jfreechart


    【解决方案1】:

    我不认为每次添加新点或调用removeAllSeries()时都需要创建新的XYSeries xyData

    这个例子展示了如何将动态数据添加到XYSeriesCollection

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JPanel;
    
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartPanel;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.axis.LogAxis;
    import org.jfree.chart.axis.NumberAxis;
    import org.jfree.chart.axis.ValueAxis;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.chart.plot.XYPlot;
    import org.jfree.data.time.Millisecond;
    import org.jfree.data.xy.XYDataset;
    import org.jfree.data.xy.XYSeries;
    import org.jfree.data.xy.XYSeriesCollection;
    import org.jfree.ui.ApplicationFrame;
    import org.jfree.ui.RefineryUtilities;
    
    /**
     * A demonstration application showing a XYseries chart where you can
     * dynamically add (random) data by clicking on a button.
     */
    public class DynamicDataDemo1 extends ApplicationFrame {
        /**
         * Constructs a new demonstration application.
         * 
         * @param title
         *            the frame title.
         */
        public DynamicDataDemo1(String title) {
            super(title);
            MyDemoPanel demoPanel = new MyDemoPanel();
            setContentPane(demoPanel);
        }
    
    
    
        static class MyDemoPanel extends DemoPanel implements ActionListener {
            /** The time series data. */
    
            /** The most recent value added. */
            private double lastValue1 = 200.0;
            private double lastValue2 = 200.0;
            private XYPlot plot;
            private boolean logAxis = false;
            private String lastSeries = "";
            private final XYSeriesCollection dataset;
            private static String SERIES_NAME =  "Random Data ";
            private static int seriesNumber =  0;
            /**
             * Creates a new instance.
             */
            public MyDemoPanel() {
                super(new BorderLayout());
                lastSeries = SERIES_NAME + (seriesNumber++);
                XYSeries series = new XYSeries(lastSeries);
                dataset = new XYSeriesCollection(series);
                ChartPanel chartPanel = new ChartPanel(createChart(dataset));
                chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
                addChart(chartPanel.getChart());
                JPanel buttonPanel = new JPanel();
                buttonPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
                JButton button = new JButton("Add New Data Item");
                button.setActionCommand("ADD_DATA");
                button.addActionListener(this);
                buttonPanel.add(button);
                {
                    JButton button2 = new JButton("Switch Axis");
                    button2.setActionCommand("SWITCH_AXIS");
                    button2.addActionListener(this);
                    buttonPanel.add(button2);
                }
                {
                    JButton button2 = new JButton("Add Series");
                    button2.setActionCommand("ADD_SERIES");
                    button2.addActionListener(this);
                    buttonPanel.add(button2);
                }
                add(chartPanel);
                add(buttonPanel, BorderLayout.SOUTH);
            }
    
            private JFreeChart createChart(XYDataset dataset) {
                JFreeChart result = ChartFactory.createXYLineChart("Dynamic Data Demo", "Time", "Value", dataset, PlotOrientation.VERTICAL, true, true, false);
                plot = (XYPlot) result.getPlot();
                ValueAxis domainAxis = plot.getDomainAxis();
                domainAxis.setAutoRange(true);
                final ValueAxis rangeAxis = plot.getRangeAxis();
                rangeAxis.setAutoRange(true);
                return result;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                if (e.getActionCommand().equals("ADD_DATA")) {
                    double factor1 = 0.90 + 0.2 * Math.random();
                    double factor2 = 0.90 + 0.2 * Math.random();
                    this.lastValue1 = this.lastValue1 * factor1;
                    this.lastValue2 = this.lastValue2 * factor2;
                    Millisecond now = new Millisecond();
                    System.out.println("Now = " + now.toString());
                    XYSeries series = dataset.getSeries(lastSeries);
                    series.add(this.lastValue2, this.lastValue1);
                } else if (e.getActionCommand().equals("SWITCH_AXIS")) {
                    if (!logAxis) {
                        LogAxis xAxis = new LogAxis("X");
                        LogAxis yAxis = new LogAxis("Y");               
                        updateZoom(xAxis,yAxis);
                    logAxis = true;
                    } else {
                        NumberAxis xAxis = new NumberAxis("X");
                        NumberAxis yAxis = new NumberAxis("Y");
                        updateZoom(xAxis,yAxis);
                        logAxis = false;
                    }
                } else if (e.getActionCommand().equals("ADD_SERIES")) {
                    lastSeries = SERIES_NAME + (seriesNumber++);
                    XYSeries series = new XYSeries(lastSeries);
                    dataset.addSeries(series);
                }
            }
    
            private void (ValueAxis xAxis, ValueAxis yAxis) {
                double domainMin = plot.getDomainAxis().getRange().getLowerBound();
                double domainMax = plot.getDomainAxis().getRange().getUpperBound();
                System.out.println(domainMin + "," + domainMax);
    
                double rangeMin = plot.getRangeAxis().getRange().getLowerBound();
                double rangeMax = plot.getRangeAxis().getRange().getUpperBound();
                System.out.println(rangeMin + "," + rangeMax);                  
    
                xAxis.setRange(domainMin, domainMax);
                plot.setDomainAxis(xAxis);
                yAxis.setRange(rangeMin, rangeMax);
                plot.setRangeAxis(yAxis);
    
            }
        }
    
        public static JPanel createDemoPanel() {
            return new DynamicDataDemo1.MyDemoPanel();
        }
    
        public static void main(String[] args) {
            DynamicDataDemo1 demo = new DynamicDataDemo1("JFreeChart: Dynamic XYSeries");
            demo.pack();
            RefineryUtilities.centerFrameOnScreen(demo);
            demo.setVisible(true);
        }
    }
    

    本示例基于 JFreeChart:DynamicDataDemo1.java。每次单击“添加新数据项”时,都会添加一个新点。在此示例中,当您添加数据点时将保留缩放,但在更改轴时不会保留。

    要在将轴从正常比例更改为对数比例时保持缩放,反之亦然,使用两个轴的当前上限和下限,并设置新轴的Range,如updateZoom所示

    【讨论】:

    • 不幸的是,这对我没有帮助,因为在您的示例中保留了缩放的原因是因为轴没有更新。我不能这样做(如我的问题中所述)。我想,这与我创作新系列无关。
    • 另外,我的应用程序的集合中可以有无限数量的系列(并且在运行时添加/删除它们),所以我不能只使用一组固定的系列而从不添加/删除他们从集合中。
    • 感谢您的贡献。 :)
    • @brimborium 你能在Runnable 中使用collection.getSeries("") 来更新系列吗?这样你就不必将系列变成一个属性。
    • 我不明白。我不只是在我的系列中添加一些点,还有全新系列要显示,有时它们会替换已经显示的系列(在这种情况下我不必删除旧系列),有时,它们会被添加(而显示的系列仍然存在)。
    【解决方案2】:

    我不知道如何将“用户缩放状态”从一个轴转移到另一个轴。因此,如果不需要,我确保不要刷新轴(=对数/线性之间的比例没有变化)。如果有变化,用户缩放状态将丢失,这是不幸的。但这不会经常发生,并且是用户控制的,因此用户可能会接受缩放状态重置。

    【讨论】:

      猜你喜欢
      • 2011-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 2016-02-09
      • 1970-01-01
      • 2019-03-20
      相关资源
      最近更新 更多