Setting labelPaint, resizing a JFrame, RemoveLegend() bug?

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
Siniz
Posts: 30
Joined: Mon Jul 21, 2008 10:38 am

Setting labelPaint, resizing a JFrame, RemoveLegend() bug?

Post by Siniz » Tue Aug 05, 2008 2:41 pm

I've got three questions, as stated in the topic. I know I've been posting quite a few questions recently and I apologize for that. I'll try to balance it out by helping some people in some posts, since I've got some experience with JFreeChart now. I appreciate any help I can get anyway, since these are issues that are harder to just figure out.

Question 1)
I've got 7 valueAxis as range-axises and 1 timeAxis as domain-axis. I've got 7 TimeSeriesCollection datasets, each with it's own StandardXYItemRenderer. Now, when he chart gets painted, each dataset gets it's own color (a color which gets set automatically). So each dataset line has it's own color.

Now, I want the labelPaint for each valueAxis to get the exact same color as each dataset renderer. I've tried setting the labelPaint for each valueAxis via alueAxis[a].setLabelPaint(renderer[a].getSeriesPaint(0)) where a is the index of an axis and renderer. It won't work because somehow the color that each dataset gets isn't defined until rendering. The only way I could figure out how to do it was to override paintGraphics for the ChartPanel and inside that function call the setLabelPaint. This worked because now the dataset lines had already been painted with respective color. This wasn't good for a few reasons however (slowing graphics down while zooming).
So, how would I go about having the samel labelPaint on an axis as the paint for the dataset renderer the axis corresponds to?

Question 2)
When I resize the JFrame I have my ChartPanel in it all gets funkily large. One would think only the actual graph area would become bigger, but everything becomes bigger. Text/lines/legends/etc. It looks very weird. I'll need to supply screenshots here to better give you an idea what's wrong. First you see a normal sized window, then you see the window when I've enlarged it.

link removed
link removed

Question 3)
Now this is really strange and possibly a bug? I have a ChartPanel with a JFReeChart attached and 7 TimeSeriesCollection datasets, each with its own renderer (as explained in question 1 also). As you know, JFReeChart automatically assign a new color to each TimeSeriesCollection dataset line (renderer).

First I compile and run the chart without using the chart.removeLegend() function. Each of the 7 dataset lines has their own nice colors. When I then just add one line of code, the chart.removeLegend() code as shown below, compile and run, the 7 dataset lines gets another set of colors, not the same as before. Why is this? It's very annoying for me for certain reasons. I can get around it by creating a button that when clicked calls chart.RemoveLegend(). But I don't want to have to click a button, I want to remove the legend before everythign is renderer and setVisible on the screen but still have the same colors on the lines as when showing the legend.

Code: Select all

JFreeChart chart = new JFreeChart(plot);
		chart.removeLegend();
		setChart(chart);
I know this was a lot, but I'm a positive person and hope for some answers :) Thanks beforehand for taking all this time reading this!
Last edited by Siniz on Mon Nov 23, 2009 4:36 pm, edited 1 time in total.

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Re: Setting labelPaint, resizing a JFrame, RemoveLegend() bu

Post by paradoxoff » Wed Aug 06, 2008 8:06 am

Siniz wrote: Now, when he chart gets painted, each dataset gets it's own color (a color which gets set automatically). So each dataset line has it's own color.
What means "automatically set"? I assume that you are not setting any color or other renderer property explcitly and instead rely on the defaults.
This would explain why you need to draw the plot before you get non-null paint values.
This might also explain problem 3: I have briefly checked the source. The draw method of StandardXYItemRenderer finally calls lookupSeriesPaint(int row) to get the paint used for drawing the series which in turns asks the DrawingSupplier for the paint by calling DrawingSupplier.getNextPaint().

Though one would have to deeply dive into the source code to verify the following assumption, I assume that removing the title without having the chart or plot drawn might induce a shift in the internal pointer of the DrawingSupplier that then points to a new, different paint when the chart is finally drawn.

Removing the legend triggers a ChartChangeEvent which might lead to the "pointer shift" in the DrawingSupplier. To ensure that it is indeed a general ChartChangeEvent instead of something that has specifically to do with the removal of the legend, you could try to induce a ChartChangeEvent via another way, e. g. by changing the background color before you draw the chart.

In order to solve the issue (instead of just understanding why it is happening) you could try a couple of things:
1. use an XYLineAndShapeRenderer instead. Though you will still have to draw the chart before you get non-null paints, the paint difference that is dependent on whether the legend was removed or not might go away.
2. If you do not want to have the legend created, simply use a constructor that allows you to set the flag createLegend and set it to false.
3. To get the paints of the axis and the series consistent, I would recommend to set them explicitly before everything is drawn. You could define your own array of paints as "paint source" to achieve this or get them from the drawing supplier of the plot and call DrawingSupplier.getNextPaint() for each new dataset or axis.

Question 2 is easy. The ChartPanel has the properties minium and maximum draw width and height. If the actual size of the chart exceeds these limits, the chart will still be drawn within the e. g. 600x400 pixel area but then be scaled to fill the complete space of e.g. 1024x768. Font, shapes, lines ... will thus get bigger. To avoid that when e. g. enlarging the ChartPanel to full screen size, set a number for the maximum draw width and height that are identical to the physical resolution of your screen.
Good luck
Paradoxoff

Siniz
Posts: 30
Joined: Mon Jul 21, 2008 10:38 am

Post by Siniz » Wed Aug 06, 2008 11:06 am

Very thorough reply paradoxoff. You are entirely correct when you assume that I am not setting any renderer property color explicitly and I rely on defaults. I do however set other renderer properties. Just not the color property.

A petty detail, but I assume you mean that StandardXYItemRenderer calls lookupSeriesPaint(int series)?

The assumption is a good one, thank you for diving into the source code. When you explain things, it seems like DrawingSupplier is really a top-level class for drawing everything. What I assumed was that each new series would get a color just out of an array, independent of other things beeing paint on the chart, like the legend. It makes sense that this isn't the case, since removing the legend changes the colors. I would have wished though that the assignment of colors would have happened before the chart beeing painted. It'd be easier for me and probably others ;)

I am going to go ahead and try thoose changes you suggested, either today or tomorrow, and I will report back with my findings. I did fix my last question though, it worked like a charm thanks!

Yet again I thank you very, very much paradoxoff for spending your time on this. Hats of to you.

paradoxoff
Posts: 1634
Joined: Sat Feb 17, 2007 1:51 pm

Post by paradoxoff » Wed Aug 06, 2008 12:24 pm

Siniz wrote: A petty detail, but I assume you mean that StandardXYItemRenderer calls lookupSeriesPaint(int series)?
Since lookupSeriesPaint(int series) is defined in AbstractRenderer I would assume that every renderer has at least the option implemented to call lookupSeriesPaint.
For StandardXYItemRenderer, the situation is as follows: in its drawItem method (which is declared in the XYItemRenderer interface and automatically called by the XYPlot), a local variable paint is defined which gets the return value of getItemPaint(series, item).
This method is not implemented in either StandardXYItemRenderer or its superclass AbstractXYItemRenderer, but it is inherited from the base class AbstractRenderer. And AbstractRenderer.getItemPaint(series, item) simply returns lookupSeriesPaint(series). lookupSeriesPaint(series) calls getSeriesPaint(series), and if this method returns null, the paint is requested from the drawing supplier.
The question is now the return value of getSeriesPaint(series). This method is again not defined in either StandardXYItemRenderer or AbstractXYItemRenderer but inherited from AbstractRenderer and returns this.paintList.getPaint(series). This.paintList is initialized as an initially empty PaintList() that will return null if the value for an index is requested that exceeds the current size of the PaintList.
So in short: unless you have explicitly set the paint in the renderer (which will fill the paintList), you will always end up asking the drawing supplier.
Regards, paradoxoff

Siniz
Posts: 30
Joined: Mon Jul 21, 2008 10:38 am

Post by Siniz » Thu Aug 21, 2008 2:52 pm

Hi again paradoxoff! I've been having a vacation so I didn't get time to test anything. I'm on it now and just wanted to report my findings.

I tried changing the background color, but the same effect didn't happen. So it does indeed have to do with removing the legend. Also, a very strange thing is that when removing the legend the colors gets choosen backwards. Let's say I have 7 renderers and color A to G gets painted. When I remove the legend the renderers get the color G to A.

Anyway, onto the results of the other things you suggested.
Suggestion1: Didn't work changing to a XYLineAndShapeRenderer. Same error persists.
Suggestion2: Didn't work. Same error persists.
Suggestion3: Only option I have left :(

I'm going by suggestion 3. Not much else I can do to fix it it seems. Very strange! Thanks for the help!

Locked