Problem: Overlapping in Bar Chart when multiple datasets
-
- Posts: 7
- Joined: Wed Jul 20, 2005 7:30 am
- Location: Munich, Germany
Problem: Overlapping in Bar Chart when multiple datasets
Hi,
I have a severe problem: I'm creating a Category Chart (Bar Chart) and I'm using several datasets each with its own axis (there are also multiple series in each dataset). Problem is: I have to display all data as bars and the bars of one dataset overlap the bars of the other. But I need this multiple datasets because I need different axis.
It'a a bit like the Dual Axis Demo but the difference is that both datasets should display bars.
Is there any way to avoid the overlapping without strange workarounds?
Tnaks for your help.
Regards,
Juergen
I have a severe problem: I'm creating a Category Chart (Bar Chart) and I'm using several datasets each with its own axis (there are also multiple series in each dataset). Problem is: I have to display all data as bars and the bars of one dataset overlap the bars of the other. But I need this multiple datasets because I need different axis.
It'a a bit like the Dual Axis Demo but the difference is that both datasets should display bars.
Is there any way to avoid the overlapping without strange workarounds?
Tnaks for your help.
Regards,
Juergen
-
- JFreeChart Project Leader
- Posts: 11734
- Joined: Fri Mar 14, 2003 10:29 am
- antibot: No, of course not.
- Contact:
This is a murky area of the JFreeChart code. Can you give me some sample data for what you are trying to do? I'll take a look at it as soon as I can.
David Gilbert
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
JFreeChart Project Leader


-
- Posts: 7
- Joined: Wed Jul 20, 2005 7:30 am
- Location: Munich, Germany
Here is a modified DualAxis Demo which shows the effect:
import java.awt.Color;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.block.BlockContainer;
import org.jfree.chart.block.BorderArrangement;
import org.jfree.chart.block.EmptyBlock;
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.title.CompositeTitle;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
public class OverlappingBarsBugDemo extends ApplicationFrame {
/**
* Creates a new demo instance.
*
* @param title the frame title.
*/
public OverlappingBarsBugDemo(String title) {
super(title);
JFreeChart chart = createChart();
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
/**
* Creates a sample dataset.
*
* @return The dataset.
*/
private static CategoryDataset createDataset1() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
// row keys...
String series1 = "S1";
String series2 = "S2";
String series3 = "S3";
// column keys...
String category1 = "Category 1";
String category2 = "Category 2";
String category3 = "Category 3";
String category4 = "Category 4";
String category5 = "Category 5";
String category6 = "Category 6";
String category7 = "Category 7";
String category8 = "Category 8";
// create the dataset...
dataset.addValue(1.0, series1, category1);
dataset.addValue(4.0, series1, category2);
dataset.addValue(3.0, series1, category3);
dataset.addValue(5.0, series1, category4);
dataset.addValue(5.0, series1, category5);
dataset.addValue(7.0, series1, category6);
dataset.addValue(7.0, series1, category7);
dataset.addValue(8.0, series1, category8);
dataset.addValue(5.0, series2, category1);
dataset.addValue(7.0, series2, category2);
dataset.addValue(6.0, series2, category3);
dataset.addValue(8.0, series2, category4);
dataset.addValue(4.0, series2, category5);
dataset.addValue(4.0, series2, category6);
dataset.addValue(2.0, series2, category7);
dataset.addValue(1.0, series2, category8);
dataset.addValue(4.0, series3, category1);
dataset.addValue(3.0, series3, category2);
dataset.addValue(2.0, series3, category3);
dataset.addValue(3.0, series3, category4);
dataset.addValue(6.0, series3, category5);
dataset.addValue(3.0, series3, category6);
dataset.addValue(4.0, series3, category7);
dataset.addValue(3.0, series3, category8);
return dataset;
}
private static CategoryDataset createDataset2() {
// row keys...
String series1 = "S4";
String series11 = "S4.1";
// column keys...
String category1 = "Category 1";
String category2 = "Category 2";
String category3 = "Category 3";
String category4 = "Category 4";
String category5 = "Category 5";
String category6 = "Category 6";
String category7 = "Category 7";
String category8 = "Category 8";
// create the dataset...
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(15.0, series1, category1);
dataset.addValue(24.0, series1, category2);
dataset.addValue(31.0, series1, category3);
dataset.addValue(25.0, series1, category4);
dataset.addValue(56.0, series1, category5);
dataset.addValue(37.0, series1, category6);
dataset.addValue(77.0, series1, category7);
dataset.addValue(18.0, series1, category8);
dataset.addValue(9.0, series11, category4);
dataset.addValue(11.0, series11, category5);
dataset.addValue(12.0, series11, category7);
dataset.addValue(15.0, series11, category8);
return dataset;
}
/**
* Creates the demo chart.
*
* @return The chart.
*/
private static JFreeChart createChart() {
// create the chart...
JFreeChart chart = ChartFactory.createBarChart(
"OverlappingBarsBugDemo", // chart title
"Category", // domain axis label
"Value", // range axis label
createDataset1(), // data
PlotOrientation.VERTICAL,
false, // include legend
true, // tooltips?
false // URL generator? Not required...
);
// NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
chart.setBackgroundPaint(Color.white);
// get a reference to the plot for further customisation...
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(0xEE, 0xEE, 0xFF));
plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
CategoryDataset dataset2 = createDataset2();
plot.setDataset(1, dataset2);
plot.mapDatasetToRangeAxis(1, 1); // this lets the second dataset use the axis of the first dataset!
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_45);
ValueAxis axis2 = new NumberAxis("Secondary");
plot.setRangeAxis(1, axis2);
BarRenderer renderer2 = new BarRenderer();
renderer2.setToolTipGenerator(new StandardCategoryToolTipGenerator());
plot.setRenderer(1, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
LegendTitle legend1 = new LegendTitle(plot.getRenderer(0));
legend1.setMargin(new RectangleInsets(2, 2, 2, 2));
legend1.setBorder(new BlockBorder());
LegendTitle legend2 = new LegendTitle(plot.getRenderer(1));
legend2.setMargin(new RectangleInsets(2, 2, 2, 2));
legend2.setBorder(new BlockBorder());
BlockContainer container = new BlockContainer(new BorderArrangement());
container.add(legend1, RectangleEdge.LEFT);
container.add(legend2, RectangleEdge.RIGHT);
container.add(new EmptyBlock(2000, 0));
CompositeTitle legends = new CompositeTitle(container);
legends.setPosition(RectangleEdge.BOTTOM);
chart.addSubtitle(legends);
return chart;
}
/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* @return A panel.
*/
public static JPanel createDemoPanel() {
JFreeChart chart = createChart();
return new ChartPanel(chart);
}
/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(String[] args) {
OverlappingBarsBugDemo demo = new OverlappingBarsBugDemo("OverlappingBarsBugDemo");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
import java.awt.Color;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.block.BlockContainer;
import org.jfree.chart.block.BorderArrangement;
import org.jfree.chart.block.EmptyBlock;
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.title.CompositeTitle;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.RefineryUtilities;
public class OverlappingBarsBugDemo extends ApplicationFrame {
/**
* Creates a new demo instance.
*
* @param title the frame title.
*/
public OverlappingBarsBugDemo(String title) {
super(title);
JFreeChart chart = createChart();
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
/**
* Creates a sample dataset.
*
* @return The dataset.
*/
private static CategoryDataset createDataset1() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
// row keys...
String series1 = "S1";
String series2 = "S2";
String series3 = "S3";
// column keys...
String category1 = "Category 1";
String category2 = "Category 2";
String category3 = "Category 3";
String category4 = "Category 4";
String category5 = "Category 5";
String category6 = "Category 6";
String category7 = "Category 7";
String category8 = "Category 8";
// create the dataset...
dataset.addValue(1.0, series1, category1);
dataset.addValue(4.0, series1, category2);
dataset.addValue(3.0, series1, category3);
dataset.addValue(5.0, series1, category4);
dataset.addValue(5.0, series1, category5);
dataset.addValue(7.0, series1, category6);
dataset.addValue(7.0, series1, category7);
dataset.addValue(8.0, series1, category8);
dataset.addValue(5.0, series2, category1);
dataset.addValue(7.0, series2, category2);
dataset.addValue(6.0, series2, category3);
dataset.addValue(8.0, series2, category4);
dataset.addValue(4.0, series2, category5);
dataset.addValue(4.0, series2, category6);
dataset.addValue(2.0, series2, category7);
dataset.addValue(1.0, series2, category8);
dataset.addValue(4.0, series3, category1);
dataset.addValue(3.0, series3, category2);
dataset.addValue(2.0, series3, category3);
dataset.addValue(3.0, series3, category4);
dataset.addValue(6.0, series3, category5);
dataset.addValue(3.0, series3, category6);
dataset.addValue(4.0, series3, category7);
dataset.addValue(3.0, series3, category8);
return dataset;
}
private static CategoryDataset createDataset2() {
// row keys...
String series1 = "S4";
String series11 = "S4.1";
// column keys...
String category1 = "Category 1";
String category2 = "Category 2";
String category3 = "Category 3";
String category4 = "Category 4";
String category5 = "Category 5";
String category6 = "Category 6";
String category7 = "Category 7";
String category8 = "Category 8";
// create the dataset...
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(15.0, series1, category1);
dataset.addValue(24.0, series1, category2);
dataset.addValue(31.0, series1, category3);
dataset.addValue(25.0, series1, category4);
dataset.addValue(56.0, series1, category5);
dataset.addValue(37.0, series1, category6);
dataset.addValue(77.0, series1, category7);
dataset.addValue(18.0, series1, category8);
dataset.addValue(9.0, series11, category4);
dataset.addValue(11.0, series11, category5);
dataset.addValue(12.0, series11, category7);
dataset.addValue(15.0, series11, category8);
return dataset;
}
/**
* Creates the demo chart.
*
* @return The chart.
*/
private static JFreeChart createChart() {
// create the chart...
JFreeChart chart = ChartFactory.createBarChart(
"OverlappingBarsBugDemo", // chart title
"Category", // domain axis label
"Value", // range axis label
createDataset1(), // data
PlotOrientation.VERTICAL,
false, // include legend
true, // tooltips?
false // URL generator? Not required...
);
// NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
chart.setBackgroundPaint(Color.white);
// get a reference to the plot for further customisation...
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(0xEE, 0xEE, 0xFF));
plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
CategoryDataset dataset2 = createDataset2();
plot.setDataset(1, dataset2);
plot.mapDatasetToRangeAxis(1, 1); // this lets the second dataset use the axis of the first dataset!
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_45);
ValueAxis axis2 = new NumberAxis("Secondary");
plot.setRangeAxis(1, axis2);
BarRenderer renderer2 = new BarRenderer();
renderer2.setToolTipGenerator(new StandardCategoryToolTipGenerator());
plot.setRenderer(1, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
LegendTitle legend1 = new LegendTitle(plot.getRenderer(0));
legend1.setMargin(new RectangleInsets(2, 2, 2, 2));
legend1.setBorder(new BlockBorder());
LegendTitle legend2 = new LegendTitle(plot.getRenderer(1));
legend2.setMargin(new RectangleInsets(2, 2, 2, 2));
legend2.setBorder(new BlockBorder());
BlockContainer container = new BlockContainer(new BorderArrangement());
container.add(legend1, RectangleEdge.LEFT);
container.add(legend2, RectangleEdge.RIGHT);
container.add(new EmptyBlock(2000, 0));
CompositeTitle legends = new CompositeTitle(container);
legends.setPosition(RectangleEdge.BOTTOM);
chart.addSubtitle(legends);
return chart;
}
/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* @return A panel.
*/
public static JPanel createDemoPanel() {
JFreeChart chart = createChart();
return new ChartPanel(chart);
}
/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(String[] args) {
OverlappingBarsBugDemo demo = new OverlappingBarsBugDemo("OverlappingBarsBugDemo");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
-
- Posts: 7
- Joined: Wed Jul 20, 2005 7:30 am
- Location: Munich, Germany
overlapping labels in dual axis
The way I got around this problem was to use null data sets. For example
The left axis has bar, bar, null, null
The right axis has null, null, bar, bar
I then subclassed the legends to only print legend that had a value
This is the main function:
/**
* Returns the legend items for the plot. By default, this method creates
* a legend item for each series in each of the datasets. You can change
* this behaviour by overriding this method.
*
* @return The legend items.
*/
public LegendItemCollection getLegendItems()
{
LegendItemCollection result = this.getFixedLegendItems();
if (result == null) {
result = new LegendItemCollection();
// get the legend items for the datasets...
// int count = this.datasets.size();
int count = 25; // no more than 25 datasets. yuk, but don't want to deal with fixeddatasets
for (int datasetIndex = 0; datasetIndex < count; datasetIndex++) {
CategoryDataset dataset = getDataset(datasetIndex);
if (dataset != null) {
CategoryItemRenderer renderer = getRenderer(datasetIndex);
if (renderer != null) {
int seriesCount = dataset.getRowCount();
for (int i = 0; i < seriesCount; i++) {
LegendItem item = renderer.getLegendItem(
datasetIndex, i
);
if (item.getLabel() == null || item.getLabel().length() == 0) {
continue;
}
if (item != null) {
result.add(item);
}
}
}
}
}
}
return result;
}
The left axis has bar, bar, null, null
The right axis has null, null, bar, bar
I then subclassed the legends to only print legend that had a value
This is the main function:
/**
* Returns the legend items for the plot. By default, this method creates
* a legend item for each series in each of the datasets. You can change
* this behaviour by overriding this method.
*
* @return The legend items.
*/
public LegendItemCollection getLegendItems()
{
LegendItemCollection result = this.getFixedLegendItems();
if (result == null) {
result = new LegendItemCollection();
// get the legend items for the datasets...
// int count = this.datasets.size();
int count = 25; // no more than 25 datasets. yuk, but don't want to deal with fixeddatasets
for (int datasetIndex = 0; datasetIndex < count; datasetIndex++) {
CategoryDataset dataset = getDataset(datasetIndex);
if (dataset != null) {
CategoryItemRenderer renderer = getRenderer(datasetIndex);
if (renderer != null) {
int seriesCount = dataset.getRowCount();
for (int i = 0; i < seriesCount; i++) {
LegendItem item = renderer.getLegendItem(
datasetIndex, i
);
if (item.getLabel() == null || item.getLabel().length() == 0) {
continue;
}
if (item != null) {
result.add(item);
}
}
}
}
}
}
return result;
}
-
- Posts: 7
- Joined: Wed Jul 20, 2005 7:30 am
- Location: Munich, Germany
Re: overlapping labels in dual axis
Yeah, that's the same workaround we used, but as we have more and more datasets and series and axis' and now we want to have an overlaying line chart everything gets very complicated with this workaround; I would prefer to have this fixed in JFreeChart itself to concentrate on the rest of the problems...guyknight wrote:The way I got around this problem was to use null data sets. For example
I'm using this workaraund, too, because I'm using a Barchart with multiple datasets and want them printed side by side, because you cannot see smaller bars when a bar of higher value is rendered before. But this workaround implies that I'm not able to display more than one series per dataset.
But I feel like this is a conceptual problem of using Barcharts for this scenario... How would you display all this data? If you render each and every bar side-by-side, how can you see then which bar belongs to which series or category?
In my oppinion the answer lies in using a 3D-Renderer which can group Bars belonging to one dataset but to different series on the z-axis, and the dataset groups (with multiple bars for the different series again) side-by-side.
There is a 3D-renderer which is a hack as David says, but maybe we can get it to work like that. What do think David?
Tom
But I feel like this is a conceptual problem of using Barcharts for this scenario... How would you display all this data? If you render each and every bar side-by-side, how can you see then which bar belongs to which series or category?
In my oppinion the answer lies in using a 3D-Renderer which can group Bars belonging to one dataset but to different series on the z-axis, and the dataset groups (with multiple bars for the different series again) side-by-side.
There is a 3D-renderer which is a hack as David says, but maybe we can get it to work like that. What do think David?
Tom