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!
Problem with bar not centered over label with CategoryPlot
-
- 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
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
Read my blog
Support JFree via the Github sponsorship program
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
Re: Problem with bar not centered over label with CategoryPlot
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);
}
}
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);
}
}
Re: Problem with bar not centered over label with CategoryPlot
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!
Does anyone have ideas on what I may be doing wrong in this case?
Thanks!
-
- Posts: 1634
- Joined: Sat Feb 17, 2007 1:51 pm
Re: Problem with bar not centered over label with CategoryPlot
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);
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);