简体   繁体   中英

Graph plotting in Java Swing only draws points

I'm currently working on a program where certain numerical variables, which evolve over time, have their value displayed on each iteration. That works well enough, but now I want to plot a graph that shows their evolution over time. So, I looked into an example of code for plotting graphs in Swing. My final code looks like this:

public class Populus3 extends JPanel
{
    public static void main(String[] args) throws IOException {

        final Populus3 pop = new Populus3();

        JFrame f = new JFrame(); //where I want to plot the graph
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new GraphingData());
        f.setSize(400,400);
        f.setLocation(200,200);
        f.setVisible(true);


        frame = new JFrame("Animation Frame"); //where I'm running animation for another element of the program
        frame.add(pop, BorderLayout.CENTER);
        frame.setSize(graphSize, graphSize);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //insert all sort of things

    }


    public void paint(Graphics g) 
    {
        super.paint(g);
        paintCell(g, 1);
        Toolkit.getDefaultToolkit().sync(); // necessary for linux users to draw  and animate image correctly
        g.dispose();
    }


      public void actionPerformed(ActionEvent e) {
        repaint();
    }



    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        for(int i = 0; i < particleType.length; i++)
            paintCell(g, i);  //a method that draws a small circle for the animation panel
    }



    public static class GraphingData extends JPanel {
        int[] data = {
            21, 14, 18, 03, 86, 88, 74, 87, 54, 77,
            61, 55, 48, 60, 49, 36, 38, 27, 20, 18
        };
        final int PAD = 20;

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D)g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                                RenderingHints.VALUE_ANTIALIAS_ON);
            int w = getWidth();
            int h = getHeight();
            // Draw ordinate.
            g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));

            // Draw abcissa.
            g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
            double xInc = (double)(w - 2*PAD)/(data.length-1);
            double scale = (double)(h - 2*PAD)/getMax();
            // Mark data points.
            g2.setPaint(Color.red);
            for(int i = 0; i < data.length; i++) {
                double x = PAD + i*xInc;
                double y = h - PAD - scale*data[i];
                g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
            }
        }

        private int getMax() {
            int max = -Integer.MAX_VALUE;
            for(int i = 0; i < data.length; i++) {
                if(data[i] > max)
                    max = data[i];
            }
            return max;
        }
    }
}

Now, the animation panel works just fine. The graph panel, on the other hand...when I run the program, it displays a bunch of red dots, without lines to connect them. What am I doing wrong?

In addition to @Hovercraft's helpful suggestions, also consider these other approaches:

  • Accumulate the points in a GeneralPath that may be rendered as required, for example .

lissajou图片

  • Connect the points using repeated calls to drawLine() using a suitable coordinate system, outlined here .

正弦图像

Your code confuses me:

  • You override both paint and paintComponent for your Populus3 JPanel -- why? You should only override paintComponent unless you absolutely have to have your drawing affect a component's children and borders.
  • You dispose of the Graphics object passed into paint -- a very dangerous thing to do. You should never dispose of a Graphics object given to you by the JVM, only Graphics objects that you yourself create.
  • You repeatedly call a method not defined here for us, paintCell(...) .
  • I've never heard of the need for Toolkit.getDefaultToolkit().sync(); for Swing applications. Do you have a reference for this need?
  • You mention "animation" but I see no animation code.
  • In your GraphingData class's paintComponent method you fill ellipses in your for loop, but you don't connect them with lines ever, so it shouldn't be surprising that you're only seeing dots in your graph and no lines.

Consider isolating your problem more and posting an sscce , a minimal test program that we can compile, run, modify and correct and that shows us your problem, but has no extra code not related to the problem or required for demonstration.

The following code demonstrates a real-time Java chart using XChart where the line is updated as the data evolves over time. Creating real-time charts is as simple as calling updateXYSeries for one or more series objects through the XYChart instance and triggering a redraw of the JPanel containing the chart. This works for all chart types including XYChart , CategoryChart , BubbleChart and PieChart , for which example source code can be found here: https://github.com/timmolter/XChart/tree/develop/xchart-demo/src/main/java/org/knowm/xchart/demo/charts/realtime . Examples demonstrate using the SwingWrapper with repaintChart() method as well as XChartPanel with revalidate() and repaint() . Disclaimer, I'm the main developer of the XChart library.

public class SimpleRealTime {

  public static void main(String[] args) throws Exception {

    double phase = 0;
    double[][] initdata = getSineData(phase);

    // Create Chart
    final XYChart chart = QuickChart.getChart("Simple XChart Real-time Demo", "Radians", "Sine", "sine", initdata[0], initdata[1]);

    // Show it
    final SwingWrapper<XYChart> sw = new SwingWrapper<XYChart>(chart);
    sw.displayChart();

    while (true) {

      phase += 2 * Math.PI * 2 / 20.0;

      Thread.sleep(100);

      final double[][] data = getSineData(phase);

      chart.updateXYSeries("sine", data[0], data[1], null);
      sw.repaintChart();

    }

  }

  private static double[][] getSineData(double phase) {

    double[] xData = new double[100];
    double[] yData = new double[100];
    for (int i = 0; i < xData.length; i++) {
      double radians = phase + (2 * Math.PI / xData.length * i);
      xData[i] = radians;
      yData[i] = Math.sin(radians);
    }
    return new double[][] { xData, yData };
  }
}

This results in the following Java Swing real-time chart app: 在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM