Problem with bar not centered over label with CategoryPlot

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
maxx
Posts: 8
Joined: Mon Feb 01, 2010 8:03 pm
antibot: No, of course not.

Problem with bar not centered over label with CategoryPlot

Post by maxx » Mon Feb 01, 2010 8:29 pm

I am trying to use CategoryPlot with the IntervalBarRenderer.

I have one series for each category. I am trying to control the width of the bars in the plot.

If I DO NOT use renderer.setMaximumBarWidth(0.05), the bars are centered over the category labels.

If I use renderer.setMaximumBarWidth(0.05), the bar is shifted to the left of center over the category label.

It looks like the bar is either left-justified vs. the label, or else there is a "second series" that is introduced, so that the first "real" series is plotted left of center, and the second/empty series is plotted to the right of center above the label.

Thanks for any help!

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

Re: Problem with bar not centered over label with CategoryPlot

Post by david.gilbert » Mon Feb 01, 2010 10:52 pm

Can you post a small self-contained demo for this? I suspect that you have an additional series in your dataset with null values (the renderer still leaves space for this non-visible series), but I can only guess.
David Gilbert
JFreeChart Project Leader

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

maxx
Posts: 8
Joined: Mon Feb 01, 2010 8:03 pm
antibot: No, of course not.

Re: Problem with bar not centered over label with CategoryPlot

Post by maxx » Tue Feb 02, 2010 5:48 pm

Below is a demo. Note that I have left the line 'renderer.setMaximumBarWidth(0.05);' active so you can see the offset. Commenting this out results in the bar being centered.

Thanks for your help!

import java.awt.Color;
import java.awt.Font;
import java.text.DecimalFormat;

import org.jfree.chart.*;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.renderer.category.IntervalBarRenderer;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.data.category.DefaultIntervalCategoryDataset;
import org.jfree.ui.TextAnchor;



public class IntervalBarRendererDemo {
/**
* The starting point for the demo.
*
* @param args ignored.
*/
public static void main(String[] args) {
// create a dataset...
double a = 5.539;
double b = 5.803;
double c = 3.389;
double d = 2.657;

String[] CATEGORIES = {"Cat A", "Cat B", "Cat C", "Cat D"};

DefaultIntervalCategoryDataset data = null;

double[][] lows = new double[1][4];
double[][] highs = new double[1][4];

lows[0][0] = a;
highs[0][0] = 9.0;
lows[0][1] = b;
highs[0][1] = 9.0;
lows[0][2] = 1.0;
highs[0][2] = c;
lows[0][3] = 1.0;
highs[0][3] = d;

data = new DefaultIntervalCategoryDataset(lows,highs);
data.setCategoryKeys(CATEGORIES);

// Renderer
final IntervalBarRenderer renderer = new IntervalBarRenderer();
renderer.setSeriesPaint(0, new Color(0,0,0));
// renderer.setLabelGenerator(new IntervalCategoryLabelGenerator());
renderer.setBaseItemLabelPaint(Color.black);
final ItemLabelPosition p = new ItemLabelPosition(
ItemLabelAnchor.CENTER, TextAnchor.CENTER
);
renderer.setBasePositiveItemLabelPosition(p);
renderer.setBaseItemLabelsVisible(true);
renderer.setDrawBarOutline(false);
renderer.setGradientPaintTransformer(null);
renderer.setMaximumBarWidth(0.05);
renderer.setBarPainter(new StandardBarPainter());
renderer.setItemMargin(0.0);

// X-axis
final CategoryAxis xAxis = new CategoryAxis("");
xAxis.setCategoryMargin(0.40); // Thins out the plot lines
xAxis.setMaximumCategoryLabelLines(2);
xAxis.setLowerMargin(0.10);
xAxis.setUpperMargin(0.10);

// Y-axis
final NumberAxis yAxis = new NumberAxis("");
yAxis.setRange(0.0,10.0);
yAxis.setNumberFormatOverride(new DecimalFormat("0.000"));

// Plot
final CategoryPlot plot = new CategoryPlot(data, xAxis, yAxis, renderer);
plot.setBackgroundPaint(Color.gray);
plot.setOutlinePaint(Color.white);
plot.setOrientation(PlotOrientation.VERTICAL);
Font titleFont = new Font("Helvetica", Font.BOLD, 14);
JFreeChart chart = new JFreeChart("IntervalBarRendererDemo", titleFont, plot, false);
chart.setBackgroundPaint(Color.white);


// create and display a frame...
ChartFrame frame = new ChartFrame("IntervalBarRendererDemo", chart);
frame.pack();
frame.setVisible(true);
}
}

maxx
Posts: 8
Joined: Mon Feb 01, 2010 8:03 pm
antibot: No, of course not.

Re: Problem with bar not centered over label with CategoryPlot

Post by maxx » Thu Feb 04, 2010 7:48 pm

With further experimentation...if I use smaller values with renderer.setMaximumBarWidth(), such as 0.02, the bar shifts further and further to the left. So it looks like it is the bar not being center-aligned over the label and not an empty data set.

Does anyone have ideas on what I may be doing wrong in this case?

Thanks!

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

Re: Problem with bar not centered over label with CategoryPlot

Post by paradoxoff » Sat Feb 06, 2010 12:33 pm

You haven´t done anything wrong, rather, you have discovered a bug!

The correct position of left edge of the rectangle representing the data item is dependent on a number of factors, such as the bar width, the number of visible series, item and category margins of the renderer and the CategoryAxis and on the availabe space. The calculation of the correct position is thus not trivial.
The IntervalBarRenderer uses an algorithm that does not use the various parameters in a correct way. Fortunately, the BarRenderer does, and the BarRenderer even has a protected method to calculate that value!
In short:
In IntervalBarRenderer.drawInterval, the section where rectY is calculated for a horizontal plot orientation (lines 213 to 222) needs to be replaced with:
rectY = calculateBarW0(plot, orientation, dataArea, domainAxis, state, row, column);
and the section where rectX is calculated for a vertical orientation (lines 232 to 242) needs to be replaced with
rectX = calculateBarW0(plot, orientation, dataArea, domainAxis, state, row, column);

maxx
Posts: 8
Joined: Mon Feb 01, 2010 8:03 pm
antibot: No, of course not.

Re: Problem with bar not centered over label with CategoryPlot

Post by maxx » Mon Feb 08, 2010 3:23 pm

Thanks!

Locked