Graph plotting in Java Swing only draws points

14,616

Solution 1

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 image

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

sine image

Solution 2

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.

Solution 3

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: enter image description here

Share:
14,616
Admin
Author by

Admin

Updated on June 05, 2022

Comments

  • Admin
    Admin about 2 years

    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?