Legend contains series twice

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
Jumbochart
Posts: 2
Joined: Wed Sep 17, 2014 7:58 am
antibot: No, of course not.

Legend contains series twice

Post by Jumbochart » Wed Sep 17, 2014 8:19 am

Hello,

my chart is supposed to contain three dataseries. Two should be rendered with a XYLineAndShapeRenderer but one of them with an area using an XYAreaRenderer. With the below code the two lines and one area are painted as expected, however the legend contains the series twice which is my problem. It seems this is caused by adding the dataset twice - once in the ChartFactory.createTimeSeriesChart(...) and again in my own code with plot.setDataset(1, dataset).

How could I draw two lines and one area within the same chart and at the same time have the legend contain only one entry for each series?

Regards,
Jumbochart

Code: Select all

public static JFreeChart createChart(final String title, final String xLabel, final String yLabel, final XYDataset dataset, 
                                     final List<Color> plotColors, final List<String> storkeStyles, final Collection<String> areaPlots) {

	boolean hasAreaPlots = areaPlots != null && areaPlots.size() > 0;
	final JFreeChart chart = hasAreaPlots ? ChartFactory.createTimeSeriesChart(title, xLabel, yLabel, dataset, true, true, true) : 
                                           ChartFactory.createXYStepChart(title, xLabel, yLabel, dataset, PlotOrientation.VERTICAL, true, true, true);

	final XYPlot plot = chart.getXYPlot();
	final DateAxis axis = (DateAxis) plot.getDomainAxis();
	axis.setDateFormatOverride(new SimpleDateFormat("dd.MM.yy,EE"));
	axis.setAutoRange(true);
	AbstractXYItemRenderer ar = null;
	final XYItemRenderer rr = plot.getRenderer();
	if (hasAreaPlots) {
		plot.setDataset(1, dataset);
		ar = new XYAreaRenderer();
		plot.setRenderer(1, ar);
	}
	for (int iSeries = 0; iSeries < dataset.getSeriesCount(); iSeries++) {
		if (plotColors != null && plotColors.size() > iSeries) {
			Color color = plotColors.get(iSeries);
			rr.setSeriesPaint(iSeries, color);
		}
		boolean isAreaPlot = false;
		if (ar != null) {
			isAreaPlot = areaPlots.contains(dataset.getSeriesKey(iSeries));
			rr.setSeriesVisibleInLegend(iSeries, Boolean.valueOf(!isAreaPlot));
			ar.setSeriesVisible(iSeries, Boolean.valueOf(isAreaPlot));
			ar.setSeriesPaint(iSeries, rr.getSeriesPaint(iSeries));
			ar.setSeriesFillPaint(iSeries, rr.getSeriesPaint(iSeries));
		}
	}

	return chart;
}

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: Legend contains series twice

Post by david.gilbert » Wed Sep 17, 2014 8:12 pm

By default, you'll get an entry for each series in all datasets. You can always override this method in one of the renderers:

Code: Select all

public LegendItem getLegendItem(int datasetIndex, int series);
...and return null for the series that you don't want to have in the legend.

Or override this method in XYPlot:

Code: Select all

public LegendItemCollection getLegendItems();
Or use the setFixedLegendItems() method in XYPlot.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

Jumbochart
Posts: 2
Joined: Wed Sep 17, 2014 7:58 am
antibot: No, of course not.

Re: Legend contains series twice

Post by Jumbochart » Sat Sep 20, 2014 10:56 am

The problem lies within XYPlot.getLegendItems. That method iterates over the datasets and within that again over the series. So if the plot has got two datasets and each has 3 (identical) series then 6 entries are printed. For my purposes it should iterate only over one dataset.

So overriding

Code: Select all

public LegendItem getLegendItem(int datasetIndex, int series);
in one of the renderes doesn't help since there is no iteration over renderes but first datasets and then series. If "seriesA" is in both of the datasets, for instance, it still would appear twice in the legend.

The other two proposals, however, worked. Overriding seemed to be the more elegant version so I used that one.

Thanks a lot for your support.

Locked