I wrote a cewolf ChartPostProcessor to modify the color of the series in a chart rather than using the default ones. Changing the actual series colors was easy, but I don't see a quick way to get the legend to refresh the color boxes next to the LegendItems with the new colors. The LegendItems themselves (retrieved via the plot.getLegendItems()) are immutable, and I can't see anyway to refresh the LegendTitle either. Am I missing something easy, or do I have to rebuild the whole legend by iterating over the existing one, creating new items with modified colors, adding those to a new LegendItemCollection, and then calling plot.setFixedLegendItems(newColl)?
adTHANKSvance
Eric
Refresh legend after changing series color?
Here is the class I wrote. It makes the assumption that the plot is an XYPlot of some form, but that can be worked around if necessary. It also invokes another utility class for checking if a plot is a combined plot and getting all subplots. You can either ignore that part, write your own, or get that class from the set of chart classes I wrote for the meta-jb project: http://sourceforge.net/project/showfile ... p_id=67888
Code: Select all
/**
* Allows setting of colors based on series name.
*/
public static class ColorSetterRenderer implements ChartPostProcessor
{
private Map<Comparable, Paint> seriesColorMap = new HashMap<Comparable, Paint>();
public void processChart(Object obj, Map params)
{
try
{
JFreeChart chart = (JFreeChart)obj;
changeSeriesColors(chart);
changeLegendColors(chart);
}
catch (Exception e)
{
log.error("Error setting colors ", e);
}
}
/**
* Iterate over all the plots in the chart and all the datasets in those plots and
* then all the series in the datasets, changing the color of series that match entries
* in our color map.
* @param chart
*/
private void changeSeriesColors(JFreeChart chart) {
List<Plot> plots = getPlots(chart);
LegendTitle lt = chart.getLegend();
for (Plot plot : plots)
{
DrawingSupplier rootSupplier = plot.getDrawingSupplier();
XYPlot xyPlot = (XYPlot)plot;
for (int i = 0; i < xyPlot.getDatasetCount(); i++)
{
XYDataset curDataset = xyPlot.getDataset(i);
XYItemRenderer curRenderer = xyPlot.getRendererForDataset(curDataset);
DrawingSupplier curSupplier = rootSupplier;
if (curRenderer instanceof AbstractXYItemRenderer)
curSupplier = ((AbstractXYItemRenderer)curRenderer).getDrawingSupplier();
//for each series in each dataset, see if there is an entry for the color
//in the color map. If not, make sure the currently assigned color doesn't
//conflict with one in the map.
for (int curSeries = 0; curSeries < curDataset.getSeriesCount(); curSeries++)
{
Comparable key = curDataset.getSeriesKey(curSeries);
Paint curPaint = curRenderer.getSeriesPaint(curSeries);
if (seriesColorMap.containsKey(key))
{
Paint assignedPaint = seriesColorMap.get(key);
if (!assignedPaint.equals(curPaint));
curRenderer.setSeriesPaint(curSeries, assignedPaint);
}
else if (seriesColorMap.containsValue(curPaint))
{
//change the color so we don't conflict with a series that is
//in the map
while (seriesColorMap.containsValue(curPaint))
curPaint = curSupplier.getNextPaint();
curRenderer.setSeriesPaint(curSeries, curPaint);
}
}
}
}
}
/**
* LegendItems are immutable, as is the Legend contents. So must go through
* all Legend items and create new ones when the color has changed. Then add
* them all to a new legend and set that.
* @param chart
*/
private void changeLegendColors(JFreeChart chart) {
LegendItemCollection newLegend = new LegendItemCollection();
XYPlot mainPlot = (XYPlot)chart.getPlot();
LegendItemCollection legend = mainPlot.getLegendItems();
for (Iterator iter = legend.iterator(); iter.hasNext();)
{
LegendItem item = (LegendItem) iter.next();
String label = item.getLabel();
Paint assignedPaint = seriesColorMap.get(label);
//if there is a new paint for the series that this item represents,
//create a new item for it
if (assignedPaint != null)
item = createLabel(item, assignedPaint);
//add either existing or new one to the new legend
newLegend.add(item);
}
//now set the new items as fixed so it won't regenerate it
if (newLegend.getItemCount() > 0)
mainPlot.setFixedLegendItems(newLegend);
}
private LegendItem createLabel(LegendItem item, Paint assignedPaint) {
LegendItem retVal = new LegendItem(item.getLabel(), item.getDescription(),
item.getToolTipText(), item.getURLText(), item.isShapeVisible(), item.getShape(),
item.isShapeFilled(), assignedPaint, item.isShapeOutlineVisible(),
item.getOutlinePaint(), item.getOutlineStroke(), item.isLineVisible(),
item.getLine(), item.getLineStroke(), item.getLinePaint());
return retVal;
}
public void setColor(Comparable seriesName, Paint color)
{
seriesColorMap.put(seriesName, color);
}
public Map<Comparable, Paint> getSeriesColorMap() {
return seriesColorMap;
}
public void setSeriesColorMap(Map<Comparable, Paint> seriesColorMap) {
this.seriesColorMap = seriesColorMap;
}
}
private static List<Plot> getPlots(JFreeChart chart) {
List<Plot> retVal = null;
XYPlot plot = (XYPlot) chart.getPlot();
if (ChartUtils.isCombinedPlot(plot))
{
retVal = ChartUtils.getSubPlots(plot);
}
else
{
retVal = new ArrayList<Plot>();
retVal.add(plot);
}
return retVal;
}