使用jFreeChart的多个图形中的多个图形 [英] Multiple graphs in multiple figures using jFreeChart

查看:321
本文介绍了使用jFreeChart的多个图形中的多个图形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用jFreechart生成两个图形,每个图形有12个图形(在jFreeChart中称为系列)。然而,一些图表被简单地跳过了!我知道我在这里有同步问题,并试图使用用户@trashgod提供给我的方法, XYSeriesCollection 是图表的模型,所以关键是使用它。




说完这个,关于你的 SwingWorker 实现,它应该如下所示:

  SwingWorker< Void,XYSeries> worker = new SwingWorker< Void,XYSeries>(){

@Override
protected Void doInBackground()throws Exception {
/ *
*此部分摘自你的multiPlot()方法
*我刚刚缩小了比例因子并摆脱了双数组
* /
int numberOfElements = 100; //这是X轴上的元素数量
for(int y = 0; y< 12; y ++){//我们想要12个系列

XYSeries series = new XYSeries( 情节+ y);
for(int x = 0; x< numberOfElements; x ++){
series.add(x,y * 10); //添加x,y点
}
发布(系列);
Thread.sleep(100); //仅用于动画目的
}
返回null;
}

@Override
protected void process(List< XYSeries> chunks){
for(XYSeries series:chunks){
/ *
*在这里将系列添加到模型。
*它将通知视图数据已更改,最后一个数据将更新
*此处调用此选项以确保在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;

公共类FreeChartDemo {

XYSeriesCollection xySeriesCollection;
字符串标题;

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(填充图表);
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); //在这里添加ChartPanel
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);

形状交叉= 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);

返回新的ChartPanel(图表);
}

private void fillChart(){
SwingWorker< Void,XYSeries> worker = new SwingWorker< Void,XYSeries>(){

@Override
protected Void doInBackground()抛出异常{
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); //添加x,y点
}
发布(系列);
Thread.sleep(100); //仅用于动画目的
}
返回null;
}

@Override
protected void process(List< XYSeries> chunk){
for(XYSeries series:chunks){
xySeriesCollection.addSeries(系列);
}
}
};
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();
}
}) ;
}
}


I am trying to use jFreechart to generate two figures each of which with 12 graphs (being referred as series in jFreeChart ). However some of the graphs get simply skipped! I know I have synchronization issue here and tried to used the method the user @trashgod provided me here however I failed. I know the way I use swingworker is wrong! I dont know how to fix it

Each figure should contain 10 graphs which are parallel horizontal straight lines. As you see in the attached image some of the lines are missing. The two figures have to be identical too ( which are not). In practice I will have to generate multiple graphs in several locations of my applications at various times(random time interval between each figure and even graphs of individual figures) Any help will be very much appreciated

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

            } 

         }
      });
   }
}

解决方案

I know the way I use swingworker is wrong! I dont know how to fix it

Before start I have some tips:

  • Get rid of the arrays: you have several of them and you'll see they only mess the things up because you'll need indexes and loops everywhere to work with them and it's too easy make a mistake. I'd especially remove this one:

    private XYSeries [] xySeries; //XYSeriesCollection is intended to keep a series list, so...

  • Don't make your class extend from JFrame (or any Swing component) if you don't will add any functionality. You just can use a variable instead.

  • Besides the SwingWorker implementation needs to be fixed, it's more disturbing having a new Thread that calls this SwingWorker. Get rid of it too (it's no needed).

  • As @trahsgod pointed out in this comment, XYSeriesCollection is the chart's model so the key is working with it.

Having said this, about your SwingWorker implementation, it should look like this:

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

Working example

Here is a complete working example based on your work that you can take as start point. Hope it be helpful :)

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

这篇关于使用jFreeChart的多个图形中的多个图形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆