当前位置: 首页 > 知识库问答 >
问题:

使用jFreeChart实现多个图形中的多个图形

松高爽
2023-03-14

我试图使用jFreechart生成两个图,每个图有12个图(在jFreechart中称为系列)。然而,有些图表被简单地跳过了!我知道我在这里有同步问题,并试图使用用户@trashgod在这里提供的方法,但我失败了。我知道我使用摇摆工人的方式是错误的!我不知道怎么修好它

每个图形应该包含10个平行的水平直线的图形。正如你在所附的图像中看到的,一些线条丢失了。这两个数字也必须相同(事实并非如此)。在实践中,我将不得不在不同的时间在我的应用程序的几个位置生成多个图形(每个图形之间的随机时间间隔,甚至单个图形的图形),任何帮助都将非常感谢

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: This dataset already contains a series with the key Plot 11
    at org.jfree.data.xy.XYSeriesCollection.addSeries(XYSeriesCollection.java:154)
    at swing.FastChart2$MySwingWorker.process(FastChart2.java:192)
    at javax.swing.SwingWorker$3.run(SwingWorker.java:414)
    at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
    at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:832)
    at sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
    at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:842)
    at javax.swing.Timer.fireActionPerformed(Timer.java:312)
    at javax.swing.Timer$DoPostEvent.run(Timer.java:244)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91) 

package swing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.util.ShapeUtilities;

public class FastChart2 extends JFrame {
   private XYSeries [] xySeries ;
   private XYPlot xyPlot;
   private XYSeriesCollection xySeriesCollection;
   private String title;
   private static int instanceNum=0;
   private int figNum=0;

   private ChartPanel chartPanel;

   public  FastChart2(String s) {
      super(s);
      figNum = instanceNum;
      instanceNum++;
      init(s);
   }

   private void init(String s){
      title = s;
      xySeries = new XYSeries[12];
      for (int i = 0; i < xySeries.length; i++) {
         xySeries[i]    = new XYSeries("Plot "+i);  
      }
      xySeriesCollection = new XYSeriesCollection();
      JFreeChart chart = ChartFactory.createScatterPlot(
            title, "X", "Y", xySeriesCollection,
            PlotOrientation.VERTICAL, true, true, false);

      xyPlot =  chart.getXYPlot();
      xyPlot.setDomainCrosshairVisible(true);
      xyPlot.setRangeCrosshairVisible(true);

      chartPanel = createChartPanel(chart);

      add(chartPanel, BorderLayout.CENTER);
      JPanel control = new JPanel();

      add(control, BorderLayout.SOUTH);

      setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
      pack();
      setLocationRelativeTo(null);
      setVisible(true);
   }

   private  ChartPanel createChartPanel(JFreeChart chart) {

      XYItemRenderer renderer = xyPlot.getRenderer();
      renderer.setSeriesPaint(0, Color.magenta);
      renderer.setSeriesPaint(1, Color.green);
      renderer.setSeriesPaint(2, Color.blue);
      renderer.setSeriesPaint(4, Color.black);
      renderer.setSeriesPaint(3, Color.yellow);
      Shape cross = ShapeUtilities.createDiagonalCross(3, 0);
      Shape plus = ShapeUtilities.createRegularCross(4,0);

      for (int i = 0; i <=3; i++) {
         renderer.setSeriesShape(0+i,    new Rectangle(-1, -1, 2, 2));
         renderer.setSeriesShape(4+i,    new Ellipse2D.Float(-2F, -2F, 5F, 5F));  
         renderer.setSeriesShape(8+i,    cross);
      }
      NumberAxis domain = (NumberAxis) xyPlot.getDomainAxis();
      domain.setRange(0,1000);
      NumberAxis range = (NumberAxis) xyPlot.getRangeAxis();
      range.setRange(0,1200);
      return new ChartPanel(chart);
   }


   public  void multiPlot(){
      Thread thread = null;
      thread = new Thread (){
         public void run() {
            final double [] x = new double[1000];
            final double [] y = new double[1000];

            try{    
               for (int k = 0; k < 12; k++) {

                  for (int i = 0; i < y.length; i++) {
                     x[i] = i;
                     y[i] = k*100;
                  }

                  try {
                     Thread.sleep(100);
                  } catch (InterruptedException e) {
                  }

                  plot2d(k % 12, x, y," Fig:"+figNum+" Seri:"+k);
               }
            } catch (Exception e){
               System.out.println();
            }     
         }
      };
      thread.start();
   }


   public synchronized void plot2d( final int iSeriesN,  final double [] dX,  final double [] dY, final String sT){

      if (dY.length != dX.length){
         throw new IllegalArgumentException("Error! inputs x and y have to be of same size.");
      }

            MySwingWorker mySwingWorker = new MySwingWorker( iSeriesN, dX, dY, sT);

            mySwingWorker
            .addPropertyChangeListener(new PropertyChangeListener() {

               public void propertyChange(PropertyChangeEvent pcEvt) {
                  if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
                    System.out.println("done");
                  }
                 if ("progress".equals(pcEvt.getPropertyName())) {
                     System.out.println("progress");
                   }
               }
            });

            mySwingWorker.execute(); 

   }

   private class MySwingWorker extends SwingWorker<Void, Double> {

      private double [] dX ;
      private double [] dY ;
      private String title;
      private int iSeriesN;
      private MySwingWorker(int iSeriesN, double [] ix, double[] iy, String st){
        dX = ix.clone();
        dY = iy.clone();
        title= st;
        this.iSeriesN = iSeriesN;
        xySeriesCollection.removeAllSeries();
        System.out.println("xySeriesCollection.removeAllSeries();");
      }

      @Override
      public Void doInBackground() throws IOException {

    //    chartPanel.getChart().removeChangeListener((ChartChangeListener) chartPanel);


         xySeries[iSeriesN].clear();
         for (int i = 0; i < dX.length; i++) {
            xySeries[iSeriesN].add(dX[i], dY[i]);
         }

         for (int i = 0; i < xySeries.length; i++) {
            setProgress(i * (100 / xySeries.length));
            publish(Double.valueOf(i));
            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {
            } // simulate latency

        }
         return null;
      }


      @Override
      protected void process(List<Double> chunks) {
         for (double d : chunks) {
            xySeriesCollection.addSeries(xySeries[(int) d]);
        }

      }
      @Override
      protected void done() {
          try {


     //        chartPanel.getChart().addChangeListener((ChartChangeListener) chartPanel);
             xySeries[iSeriesN].setKey(title);

          } catch (Exception ignore) {
          }
      }
   }

   public XYSeries addXY(final int iSeriesN, final double [] dX, final double [] dY){
      XYSeries series = new XYSeries("Plot ");

      for (int i = 0; i < dX.length; i++) {
         series.add(dX[i], dY[i]);
      }
      return series;
   }

   public static void main(String args[]) {
      EventQueue.invokeLater(new Runnable() {
         @Override
         public void run() {
            FastChart2 [] demo = new FastChart2[2];
            for (int i = 0; i < demo.length; i++) {
               demo[i] = new FastChart2("Figure "+i);
               demo[i].multiPlot();

            } 

         }
      });
   }
}

共有1个答案

柯国安
2023-03-14

我知道我使用摇摆工人的方式是错误的!我不知道怎么修好它

在开始之前,我有一些建议:

>

  • 去掉数组:您有几个数组,您会看到它们只会把事情搞得一团糟,因为您需要到处都有索引和循环来处理它们,而且很容易出错。我会特别删除这个:

    正如@trahsgod在这篇评论中指出的那样,XySeriesCollection是图表的模型,所以关键是使用它。

    话虽如此,关于SwingWorker实现,应该如下所示:

    SwingWorker<Void, XYSeries> worker = new SwingWorker<Void, XYSeries>() {
    
       @Override
       protected Void doInBackground() throws Exception {
           /* 
            * This part is extracted from your multiPlot() method
            * I've just reduced the scale factor and get rid of double arrays
            */
           int numberOfElements = 100; // this is the number of elementes in X axis    
           for(int y = 0; y < 12; y++) { // we want 12 series
    
               XYSeries series = new XYSeries("Plot " + y);
               for (int x = 0; x < numberOfElements; x++) {
                   series.add(x, y*10); //add x,y point
               }
               publish(series);
               Thread.sleep(100);// just for animation purpose
           }
           return null;              
       }
    
       @Override
       protected void process(List<XYSeries> chunks) {
           for(XYSeries series : chunks){
               /* 
                * Add the series to the "model" here.
                * It will notify the "view" data has been changed and this last one will be updated
                * It's important make this call here to ensure the "view" is updated in the EDT.
                */
               xySeriesCollection.addSeries(series);
           }
       }
    };
    

    这里是一个完整的工作例子,基于你的工作,你可以作为起点。希望能有所帮助:)

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.FlowLayout;
    import java.awt.Rectangle;
    import java.awt.Shape;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.Ellipse2D;
    import java.util.List;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    import javax.swing.SwingWorker;
    import org.jfree.chart.*;
    import org.jfree.chart.axis.NumberAxis;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.chart.plot.XYPlot;
    import org.jfree.chart.renderer.xy.XYItemRenderer;
    import org.jfree.data.xy.XYSeries;
    import org.jfree.data.xy.XYSeriesCollection;
    import org.jfree.util.ShapeUtilities;
    
    public class FreeChartDemo {
    
      XYSeriesCollection xySeriesCollection;
      String title;
    
      public FreeChartDemo(String title){
          this.title = title;
      }
    
      public void initGUI(){
    
          JButton clearChart =  new JButton("Clear chart");
          clearChart.addActionListener(new ActionListener() {
              @Override
              public void actionPerformed(ActionEvent e) {
                  xySeriesCollection.removeAllSeries();
              }
          });
    
          JButton fillChart = new JButton("Fill chart") ;
          fillChart.addActionListener(new ActionListener() {
              @Override
              public void actionPerformed(ActionEvent e) {
                  xySeriesCollection.removeAllSeries();
                  fillChart();
              }
          });
    
          JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
          controlPanel.add(clearChart);
          controlPanel.add(fillChart);
    
          JPanel content = new JPanel(new BorderLayout(5, 5));
          content.add(getFreeChartPanel(), BorderLayout.CENTER); //add the ChartPanel here
          content.add(controlPanel, BorderLayout.SOUTH);
    
          JFrame frame = new JFrame("JFreeChart demo");
          frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          frame.getContentPane().add(content);
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       private JPanel getFreeChartPanel(){
           xySeriesCollection = new XYSeriesCollection();
    
           JFreeChart chart = ChartFactory.createScatterPlot(title, "X axis", "Y axis", xySeriesCollection, 
                                                             PlotOrientation.VERTICAL, true, true, false);       
           XYPlot plot = chart.getXYPlot();
           plot.setDomainCrosshairVisible(true);
           plot.setRangeCrosshairVisible(true);
    
           XYItemRenderer renderer = plot.getRenderer();
           renderer.setSeriesPaint(0, Color.magenta);
           renderer.setSeriesPaint(1, Color.green);
           renderer.setSeriesPaint(2, Color.blue);
           renderer.setSeriesPaint(4, Color.black);
           renderer.setSeriesPaint(3, Color.yellow);
    
           Shape cross = ShapeUtilities.createDiagonalCross(3, 0);
    
           for (int i = 0; i <= 3; i++) {
               renderer.setSeriesShape(0+i, new Rectangle(-1, -1, 2, 2));
               renderer.setSeriesShape(4+i, new Ellipse2D.Float(-2F, -2F, 5F, 5F));  
               renderer.setSeriesShape(8+i, cross);
           }
    
           NumberAxis domain = (NumberAxis) plot.getDomainAxis();
           domain.setRange(0,100);
           NumberAxis range = (NumberAxis) plot.getRangeAxis();
           range.setRange(0,120);
    
           return new ChartPanel(chart);
       }
    
       private void fillChart() {
           SwingWorker<Void, XYSeries> worker = new SwingWorker<Void, XYSeries>() {
    
               @Override
               protected Void doInBackground() throws Exception {
                   int numberOfElements = 1000;    
                   for(int y = 0; y < 12; y++) {
                       XYSeries series = new XYSeries("Plot " + y);
                       for (int x = 0; x < numberOfElements; x++) {
                           series.add(x, y*10); //add x,y point
                       }
                       publish(series);
                       Thread.sleep(100);// just for animation purpose
                   }
                   return null;              
               }
    
               @Override
               protected void process(List<XYSeries> chunks) {
                   for(XYSeries series : chunks){
                       xySeriesCollection.addSeries(series);
                   }
               }
           };
           worker.execute();
       }
    
       public static void main(String args[]) {
          SwingUtilities.invokeLater(new Runnable() {
             @Override
             public void run() {
                 new FreeChartDemo("JFreeChart #1").initGUI();
                 new FreeChartDemo("JFreeChart #2").initGUI();
             }
          });
       }
    }
    

  •  类似资料:
    • 问题内容: 我是python的新手,正在尝试使用matplotlib在同一图中绘制多条线。我的Y轴的值存储在字典中,并在下面的代码中在X轴中进行相应的值 我的代码是这样的: 但是我得到的是一个单独的图,一个图一个图。有人可以帮助我弄清楚我们的代码有什么问题吗?为什么不能生成多条线图?非常感谢! 问题答案: 这很简单: 您可以随意添加多次。至于,您需要首先指定颜色。所以对于蓝色,它是。对于正常的线是

    • 我需要一种在ChartJS中显示堆叠条形图中多个数据段的方法。在官方文档中,标签属于堆栈的每个部分,但我需要这些部分是独立的。 我已经模拟了我需要实现的输出类型。我们每天有三个堆叠的条,每个条显示一个单独的数据集。在每个数据集中,我们有一个段,它实际上是该条的子集。 不幸的是,中的属性似乎不接受数组。这个图表可以使用ChartJS吗?

    • 我正在绘图中绘制多个多边形: 结果图正确地显示了我的多边形,但我想知道哪个多边形对应于图上的哪个索引(例如:绿色多边形是处的多边形)。理想情况下,我想要一个将多边形的颜色与其索引关联起来的图例,但我不知道如何在这样的循环中添加这样的图例。我试过但这不起作用。 多边形的数量是可变的,所以严格分配颜色是不可能的。 如何添加图例?

    • 我试图将多个图形绘制到一个PDF,但它会生成损坏的PDF。 我应该如何修改上面的代码,以便我在一个PDF文件中成功地获得4个图。

    • 我有几个绘图函数,每个函数都接收不同类型的数据并用自己的标题和图例进行绘图。然而,当我试图在同一个图形上绘制它们时,前一个图形被覆盖。 我知道这样做的一种方法是调用,但是由于图例是在函数内部创建的,所以这似乎是不可能的。是否有任何类型的可以执行此操作?从每个绘图中检索图例并在图形上显示它们?我应该从每个函数返回图例吗? 这是我所拥有的简化代码: 我不确定这是否是最好的方法,但由于我多次使用这些绘图

    • 我正在制作一个类似飞鸟的飞机游戏,在一个类中,我有移动的背景,然后我将其添加到主jPanel中,它在自己的类中,在另一个类中,我有玩家,我将其添加到主jPanel中。但是,当我将第二个类添加到JPanel时,我添加的第一个类将消失。这是我的背景课: 这是我的平面类:导入java.awt.图形;导入java.awt.event.动作事件;导入java.awt.event.动作监听器;导入java.a