Problem: Overlapping in Bar Chart when multiple datasets

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
Juggle4Evr
Posts: 7
Joined: Wed Jul 20, 2005 7:30 am
Location: Munich, Germany

Problem: Overlapping in Bar Chart when multiple datasets

Post by Juggle4Evr » Wed Jul 05, 2006 11:35 am

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

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 » Wed Jul 05, 2006 1:08 pm

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

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

Juggle4Evr
Posts: 7
Joined: Wed Jul 20, 2005 7:30 am
Location: Munich, Germany

Post by Juggle4Evr » Wed Jul 05, 2006 2:23 pm

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);
}

}

Juggle4Evr
Posts: 7
Joined: Wed Jul 20, 2005 7:30 am
Location: Munich, Germany

Post by Juggle4Evr » Tue Aug 01, 2006 3:21 pm

Any new insights for this problem?

Morwen
Posts: 26
Joined: Sat Apr 02, 2005 6:26 pm

Post by Morwen » Wed Aug 02, 2006 5:50 am

I'm experiencing the same problem as well.
I've seen the work around in the demo example.
Aren't there any other options?

Morwen.

guyknight
Posts: 10
Joined: Fri Dec 02, 2005 4:16 pm

overlapping labels in dual axis

Post by guyknight » Mon Aug 07, 2006 1:55 pm

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;
}

Juggle4Evr
Posts: 7
Joined: Wed Jul 20, 2005 7:30 am
Location: Munich, Germany

Re: overlapping labels in dual axis

Post by Juggle4Evr » Mon Aug 07, 2006 2:22 pm

guyknight wrote:The way I got around this problem was to use null data sets. For example
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...

Morwen
Posts: 26
Joined: Sat Apr 02, 2005 6:26 pm

Post by Morwen » Mon Aug 07, 2006 4:56 pm

Same here.
I used the same solution as they did in the examples, as described above.
The problem is that it's mainly used for Bar graphs, which is an inconvinience.

Tom
Posts: 32
Joined: Mon Dec 11, 2006 2:50 pm

Post by Tom » Wed May 09, 2007 12:20 pm

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

Tom
Posts: 32
Joined: Mon Dec 11, 2006 2:50 pm

Post by Tom » Thu May 10, 2007 2:51 pm

Just saw the LayeredBarChart in the demo... That should solve the problem, too.

Tom

Locked