Drawing lots of shapes at once (in a JPanel)?

This isn’t a for a game, but for plotting points in a graph. I’m hoping the problem is similar to what someone else might have encountered in a 2D game.

Basically I’ve got a JPanel subclass (in a Swing GUI application) with a custom paintComponent() method to draw the plots, axes, labels, etc.

Currently I’d like to plot a large number of points on a plot at once time (say, greater than 1000 points at a time). These are typically drawn as circles and may also have lines connecting points.

When the number of points increases, the time to re-draw the plot increases (I guess this is a “duh”), but I am wondering if there is a better way (performance-wise) to draw this.

One thought is to draw the plot on an image of some sort, then the overhead for the scaling etc. of drawing isn’t there for later re-draws. This would work fine for static display of data, but I also need to deal with the case where new data is added to the graph (forcing old data either to be compressed or moved off one end of the plot), so the image would also need to be updated.

I’ve got some ways around this (limiting the number of points to plot, using “summary” plots like histograms), but users want to “push the system” and display more data than is “reasonable” (from the developer’s point of view :)), so I am trying to account for this.

Switching to another framework (i.e., SWT) isn’t an option - maybe sometime down the road (if needed), but for now, it has to be Swing.

Thanks,

Greg

Yes having a graph image that you simply update and display to the screen is the best route.

Something like:

private void resetPoints()
{
//gc (Graphics Configuration)
Image tempGraph = gc.createCompatibleImage(Width, Height, Transparency.BITMASK);
Graphics2D g = (Graphics2D)graph.getGraphics();
drawGraph(g); //this is where you will draw your cirles/lines and any background art to this image
g.dispose();
graphImg = tempGraph;
}

Then simply render your graphImg in your repaint and when you need to add more points call this method again.

What is causing the redraw?

If the content of the screen is completely new, it has to be drawn. If later redraw come from panning e.g., think of using a JScrollpane and make sure that you evaluate the clip rectangle established in the graphics object by Swing.

IIRC, JScrollPane optimizes redraws and also does that kind of image buffering.

JScrollPane does not optimise redraws (unless I seem to remember the scrolled component is a JTable). I believe the reason for this is that the general API doesn’t distinguish between an area being invalidated because the screen content was lost or because the underlying data has changed. So it always redisplays the entire area. (There also used to be some bugs with the copyArea methods.)

To speed up drawing

  1. use a small image instead of repeatedly drawing a circle/triangle/etc as markers. The image is likely to be cached on the display card instead of being drawn each time.
  2. if drawing wide lines, try to use polylines of around 100 points at a time. The technique used to render wide lines is not linear in the number of points (as I discovered when attempting to draw the coastline of Norway!). Too few points at a time incurs excessive setup overhead, while too many hits this non linear algorithm problem.

Someone will no doubt suggest that 42 points at a time would be more appropriate … (HHGTG).

Hm, I still think it DOES optimize. We have a viewer for biological sequence data, that has to render many many many rectangles and characters. While scrolling in a JScrollPane, we found that only those parts had to be rendered that newly came into sight. The rest has been blitted around automatically w/o redraw.

Thanks for the tips - I’m in the middle of some other stuff now, and just planning on how to attack this problem at the moment (so it will be a few days before I can test some of this).

In response to Herkules, the redraw is caused by adding data to the plot. If auto-scaling is on (an option), then the plot axes are re-scaled. As you said, I’ll need to redraw in this case.

Thanks again,

Greg