Multiple Colors in Bar

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
sdd
Posts: 3
Joined: Thu Apr 06, 2006 4:24 pm

Multiple Colors in Bar

Post by sdd » Thu Apr 06, 2006 4:45 pm

Hello,

Is it possible to assign a single Bar in a Bar Chart multiple colors? I would like to be able to assign specific colors to a range of values such that, for example, the bar would be green from 0-500 units, yellow from 501-1000 units, and red from 1001-1500 units. So, if the bar is to display a value of 1500, the colors displayed would be as described above, however, if the value to be displayed is 506, the bar would show the green color from 0-500 and yellow from 501-506.

The appearance of the StackedBarChart (with green, yellow, and red bars) is what I'm trying for, but would like to be able to achieve this effect by assigning multiple colors to one bar.

Thanks!

SomeOtherUser
Posts: 13
Joined: Thu Apr 06, 2006 7:55 pm

Different colors for positive and negative values

Post by SomeOtherUser » Thu Apr 06, 2006 8:11 pm

Interesting idea sdd. I hope you find a solution. You might consider (I haven't even looked at trying this) extending BarRenderer.
I want to do almost an identical thing: for a single category, I want the positive values to have one color and the negative values to have a different color.

For ("row", "column", 5), the bar should be colored blue.
For ("row", "column", -3), the bar should be colored red.
And so on...

Do I need to extend the BarRenderer?

Thanks for the help.

skunk
Posts: 1087
Joined: Thu Jun 02, 2005 10:14 pm
Location: Brisbane, Australia

Post by skunk » Thu Apr 06, 2006 9:58 pm

Subclass the renderer and override

Code: Select all

public Paint getItemPaint(int series, int item)

SomeOtherUser
Posts: 13
Joined: Thu Apr 06, 2006 7:55 pm

Post by SomeOtherUser » Thu Apr 06, 2006 11:06 pm

Thank you. :D

kanishk
Posts: 10
Joined: Mon May 01, 2006 2:57 am

Post by kanishk » Mon May 01, 2006 2:59 am

SomeOtherUser wrote:Thank you. :D
Hey..
Can you please shed some light on how to override this method?

this is the code snippet for my renderer.
LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot
.getRenderer();
renderer.setShapesVisible(true);
renderer.setDrawOutlines(true);
renderer.setUseFillPaint(true);
renderer.setFillPaint(Color.white);

SomeOtherUser
Posts: 13
Joined: Thu Apr 06, 2006 7:55 pm

Post by SomeOtherUser » Mon May 01, 2006 5:35 pm

You need to be more specific about what kind of help you need.

kanishk
Posts: 10
Joined: Mon May 01, 2006 2:57 am

Post by kanishk » Tue May 02, 2006 7:31 am

I am trying to create a XYLine graph where values less that 50 should be filled with black colour and rest red.

Code: Select all

	JFreeChart chart = ChartFactory.createLineChart(
				"Reading Status for MOTE# " + moteId, // chart title
				"Date/Time", // x axis label
				"Reading", // y axis label
				getDataset(reading), // data
				PlotOrientation.VERTICAL, 
				true, // include legend
				true, // tooltips
				false // urls
				);

		chart.setBackgroundPaint(Color.white);
		CategoryPlot plot = (CategoryPlot) chart.getPlot();
		plot.setBackgroundPaint(Color.lightGray);
		plot.setRangeGridlinePaint(Color.white);

		// customise the range axis...
		NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
		rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

		// customize the renderer...
		LineAndShapeRenderer renderer = new MyRenderer();
		renderer = (LineAndShapeRenderer) plot
				.getRenderer();
		
		renderer.setShapesVisible(true);
		renderer.setDrawOutlines(true);
		renderer.setUseFillPaint(true);
		renderer.setFillPaint(Color.BLACK);
		
		ChartUtilities.saveChartAsJPEG(new File("test.jpg"), chart, 500, 300);
		return chart;

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

Post by david.gilbert » Tue May 02, 2006 9:02 am

You've got this in your code:

Code: Select all

LineAndShapeRenderer renderer = new MyRenderer();
renderer = (LineAndShapeRenderer) plot.getRenderer();
That creates a new renderer then immediately overwrites it with the plot's renderer. I doubt that's what you intended...
David Gilbert
JFreeChart Project Leader

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

kanishk
Posts: 10
Joined: Mon May 01, 2006 2:57 am

Post by kanishk » Tue May 02, 2006 1:39 pm

I created a subclass to override this method.
public Paint getItemPaint(int series, int item)

BUT, what do I write in the code body to give the functionality?

I have apparently only 1 series and all I want is that points with value below 50 should be filled with black, else white.

angel
Posts: 899
Joined: Thu Jan 15, 2004 12:07 am
Location: Germany - Palatinate

Post by angel » Tue May 02, 2006 1:56 pm

Compare your fixed value to dataset.getValue().

SomeOtherUser
Posts: 13
Joined: Thu Apr 06, 2006 7:55 pm

Post by SomeOtherUser » Tue May 02, 2006 5:44 pm

Thank you for the added info, kanishk. I think I can help you. The problem is that the Renderer knows nothing about the dataset. The only time it ever is given information about the dataset is in drawItem, which is called when the chart needs to be repainted. (See http://java.sun.com/docs/books/tutorial ... editrender to understand the mechanism employed here.) So simply overriding getItemPaint will be insufficient for your purposes.
I'm using a BarRenderer and wanted negative values to be one color and positive another. What I had to do was subclass BarRenderer and add a data structure to remember the other colors, then override methods for setting the Paint (setPaint or setSeriesPaint) to allow me to add my alternate colors, getItemPaint to return my alternate color when a condition is met, and drawItem to establish the conditions that determine which Paint to use.

I've included my code below. It's a bit of a hack, but it gets the job done.

Code: Select all

public class NegativeBarRenderer extends BarRenderer
{
	private boolean negative = false;
	private HashMap negativePaint = new HashMap();
	
	public void setSeriesPaint(int series, Paint positive, Paint negative)
	{
		negativePaint.put(positive, negative);
		setSeriesPaint(series, positive);
	}
	
	public Paint getNegativeSeriesPaint(int series)
	{
		return (Paint)negativePaint.get(getSeriesPaint(series));
	}
	
	public Paint getItemPaint(int series, int item)
	{
		if(negative)
			return (Paint)negativePaint.get(super.getItemPaint(series, item));
		else
			return super.getItemPaint(series, item);
	}
	
	public void drawItem(Graphics2D g2, CategoryItemRendererState state, Rectangle2D dataArea, CategoryPlot plot,
			 CategoryAxis domainAxis, ValueAxis rangeAxis, CategoryDataset dataset, int row, int column, int pass)
	{
		// This is the only place we have access to the data values.  Establish positive or negative here.
                if(dataset.getValue(row, column).doubleValue() < 0)
			negative = true;
		// Draw like normal, which will call getItemPaint()
                super.drawItem(g2, state, dataArea, plot, domainAxis, rangeAxis, dataset, row, column, pass);
		// Return to normal
                negative = false;
	}
}
If you have further questions, just ask.

skunk
Posts: 1087
Joined: Thu Jun 02, 2005 10:14 pm
Location: Brisbane, Australia

Post by skunk » Tue May 02, 2006 9:58 pm

How about this?

Code: Select all

plot.setRenderer(new BarRenderer() {
    public java.awt.Paint getItemPaint(int row, int column) {
        double v = getPlot().getDataset().getValue(row, column).doubleValue();
        if (v < 0)
            return Color.red;
        else
            return Color.green;
    }
});
In the real world you might want a few null checks. If you have multiple datasets in the plot you would need to modify the code accordingly.

SomeOtherUser
Posts: 13
Joined: Thu Apr 06, 2006 7:55 pm

Post by SomeOtherUser » Tue May 02, 2006 10:01 pm

How did I miss getPlot()? I don't know. Yes, much cleaner code; thanks for the correction.

kanishk
Posts: 10
Joined: Mon May 01, 2006 2:57 am

Post by kanishk » Wed May 24, 2006 4:15 am

I am not sure how will this work when using XY chart? I tried using skunk's code and it painted the line AND the dot as BLACK..where as I wanted ONLY the dot to be black. here is the code...

Code: Select all

public class MyRenderer extends LineAndShapeRenderer {

	private Boolean[] anomaly;
	
	/**
	 * 
	 *
	 */
	public MyRenderer(Boolean[] anomaly) {
		
		super();
		this.anomaly = anomaly;
	}


	/**
	 * 
	 */
	public Paint getItemPaint(int series, int item) {
	
		if(anomaly[item].booleanValue())
			return Color.BLACK;
		
		return super.getItemPaint(series,item);
	}

}

Locked