Graph plotting in Java Swing only draws points
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.
- Connect the points using repeated calls to
drawLine()
using a suitable coordinate system, outlined here.
- Look at
JFreeChart
.
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:
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on June 05, 2022Comments
-
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?