Help with Multi-Series Stacked Bar Chart
Help with Multi-Series Stacked Bar Chart
I require a multi-series stacked bar chart like the following.
http://www.decisionsdecisions.net/examp ... _chart.png
I do not see any way of doing this 'out of the box' and am guessing therefore that I will need to look at subclassing:
[1] DefaultCategoryDataset
and
[2] DefaultCategoryItemRenderer.
Am I on the right lines here?
Thanks.
Alan
http://www.decisionsdecisions.net/examp ... _chart.png
I do not see any way of doing this 'out of the box' and am guessing therefore that I will need to look at subclassing:
[1] DefaultCategoryDataset
and
[2] DefaultCategoryItemRenderer.
Am I on the right lines here?
Thanks.
Alan
-
- Posts: 844
- Joined: Fri Oct 13, 2006 9:29 pm
- Location: Sunnyvale, CA
Re: Help with Multi-Series Stacked Bar Chart
I would think you are on the right lines. However, I see no need to extend DefaultCategoryDataset. Your chart still has a clear concept of series ("Target", "Current", and "Preview") and categories ("Cash", "Gifts", etc.). As long as your renderer knows how to parse the data correctly, you can still use this dataset.AlanH99 wrote:Am I on the right lines here?
As for the renderer, you would be better off looking at the BarRenderer and StackedBarRenderer for inspiration if you need to create your own custom renderer. However, I am not so sure you do since I have just discovered something new in the JFreeChart API. I have not tried it, but take a look at the GroupedStackedBarRenderer. From the JavaDoc, it looks like it might be what you are looking for--but I have not tried it.
Richard West
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA
I had a look at the GroupedStackedBarRenderer demo and associated source but couldn't get it to work as required.
Maybe I'm missing something however as I had terrible trouble getting my head round the concept!
My Data is as follows if anyone can advise how it should be grouped:
A Portfolio with 5 AssetAllocations - The 'Target' data e.g. Cash 26%
An Alternative Portfolio with 5 Asset Allocations - The 'Current' data e.g Cash 20%
A Further Alternative Portfolio with 5 Asset Allocations - The 'Preview' data e.g. Cash 15%
Maybe I'm missing something however as I had terrible trouble getting my head round the concept!
My Data is as follows if anyone can advise how it should be grouped:
A Portfolio with 5 AssetAllocations - The 'Target' data e.g. Cash 26%
An Alternative Portfolio with 5 Asset Allocations - The 'Current' data e.g Cash 20%
A Further Alternative Portfolio with 5 Asset Allocations - The 'Preview' data e.g. Cash 15%
-
- Posts: 844
- Joined: Fri Oct 13, 2006 9:29 pm
- Location: Sunnyvale, CA
The series would be "Target", "Current", and "Preview" since those are what you are wanting to plot. The categories are the five types of asset allocations. The values would be the percentages.
For the groups, try the following (I have not tested this):
This should have the Target series be in group 0, and the other two both in group 1. This seems to be the most obvious way to organize that data.
For the groups, try the following (I have not tested this):
Code: Select all
groupmap = KeyToGroupMap("Target");
groupmap.mapKeyToGroup("Target", 0);
groupmap.mapKeyToGroup("Current", 1);
groupmap.mapKeyToGroup("Preview", 1):
Richard West
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA
Thanks for your help Richard. The following gets me in the right direction. The only problem is with the Axis labels as can be seen from:
http://www.decisionsdecisions.net/examp ... rouped.png
http://www.decisionsdecisions.net/examp ... rouped.png
Code: Select all
for(AssetAllocation allocation : portfolio.getAssetAllocations().values())
{
dataset.addValue(allocation.getPercentage(),"Target", allocation.getAssetClass());
}
for(AssetAllocation allocation : objective.getAssetAllocations().values())
{
dataset.addValue(allocation.getPercentage(),"Current", allocation.getAssetClass());
}
dataset.addValue(23, "Preview", AssetClass.CASH);
GroupedStackedBarRenderer renderer = new GroupedStackedBarRenderer();
KeyToGroupMap groupMap = new KeyToGroupMap();
groupMap.mapKeyToGroup("Target", 0);
groupMap.mapKeyToGroup("Current", 1);
groupMap.mapKeyToGroup("Preview", 1);
renderer.setSeriesToGroupMap(groupMap);
-
- Posts: 844
- Joined: Fri Oct 13, 2006 9:29 pm
- Location: Sunnyvale, CA
I am not sure how to solve the axis label alignment issue. I believe it is a problem with the code for the GroupedStackedBarRenderer not specifying the space available to the label correctly. I did not write the code, so I am not sure. Hopefully, David Gilbert will have some ideas when he gets back from vacation in the next couple of days.
Richard West
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA
-
- JFreeChart Project Leader
- Posts: 11734
- Joined: Fri Mar 14, 2003 10:29 am
- antibot: No, of course not.
- Contact:
The default constructor for KeyToGroupMap sets up a default group that your code doesn't use but nevertheless the space is allocated for it in the chart. Use the other constructor that specifies the default group.AlanH99 wrote:Code: Select all
KeyToGroupMap groupMap = new KeyToGroupMap(); groupMap.mapKeyToGroup("Target", 0); groupMap.mapKeyToGroup("Current", 1); groupMap.mapKeyToGroup("Preview", 1); renderer.setSeriesToGroupMap(groupMap);
Here's what I came up with for your chart:
Code: Select all
/* --------------------
* GroupedBarChart.java
* --------------------
* (C) Copyright 2007, by Object Refinery Limited.
*
*/
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.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.GroupedStackedBarRenderer;
import org.jfree.data.KeyToGroupMap;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
/**
* A grouped stacked bar chart.
*/
public class GroupedBarChart extends ApplicationFrame {
/**
* Creates a new demo.
*
* @param title the frame title.
*/
public GroupedBarChart(String title) {
super(title);
JPanel chartPanel = createDemoPanel();
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
setContentPane(chartPanel);
}
/**
* Creates a sample dataset.
*
* @return A sample dataset.
*/
private static CategoryDataset createDataset() {
DefaultCategoryDataset result = new DefaultCategoryDataset();
result.addValue(4.0, "Target", "Cash");
result.addValue(2.0, "Current", "Cash");
result.addValue(1.0, "Preview", "Cash");
result.addValue(1.0, "Target", "Gilts");
result.addValue(0.8, "Current", "Gilts");
result.addValue(2.0, "Preview", "Gilts");
result.addValue(3.0, "Target", "Bonds");
result.addValue(2.0, "Current", "Bonds");
result.addValue(0.0, "Preview", "Bonds");
result.addValue(1.0, "Target", "Property");
result.addValue(3.5, "Current", "Property");
result.addValue(1.5, "Preview", "Property");
result.addValue(0.5, "Target", "UK Equity");
result.addValue(0.0, "Current", "UK Equity");
result.addValue(1.5, "Preview", "UK Equity");
result.addValue(5.0, "Target", "Overseas Equity");
result.addValue(3.0, "Current", "Overseas Equity");
result.addValue(2.0, "Preview", "Overseas Equity");
result.addValue(3.0, "Target", "Other");
result.addValue(2.5, "Current", "Other");
result.addValue(0.5, "Preview", "Other");
return result;
}
/**
* Creates a sample chart.
*
* @param dataset the dataset for the chart.
*
* @return A sample chart.
*/
private static JFreeChart createChart(CategoryDataset dataset) {
JFreeChart chart = ChartFactory.createStackedBarChart(
"Grouped Bar Chart", // chart title
null, // domain axis label
"Value", // range axis label
dataset, // data
PlotOrientation.VERTICAL, // the plot orientation
true, // legend
true, // tooltips
false // urls
);
GroupedStackedBarRenderer renderer = new GroupedStackedBarRenderer();
KeyToGroupMap map = new KeyToGroupMap("G1");
map.mapKeyToGroup("Target", "G1");
map.mapKeyToGroup("Current", "G2");
map.mapKeyToGroup("Preview", "G2");
renderer.setSeriesToGroupMap(map);
renderer.setItemMargin(0.10);
renderer.setSeriesPaint(0, Color.gray);
renderer.setSeriesPaint(1, Color.lightGray);
renderer.setSeriesPaint(2, Color.pink);
renderer.setDrawBarOutline(false);
CategoryPlot plot = (CategoryPlot) chart.getPlot();
plot.setRenderer(renderer);
return chart;
}
/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* @return A panel.
*/
public static JPanel createDemoPanel() {
JFreeChart chart = createChart(createDataset());
return new ChartPanel(chart);
}
/**
* Starting point for the demonstration application.
*
* @param args ignored.
*/
public static void main(String[] args) {
GroupedBarChart demo = new GroupedBarChart("Grouped Bar Chart");
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
}
}
David Gilbert
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
JFreeChart Project Leader


-
- Posts: 844
- Joined: Fri Oct 13, 2006 9:29 pm
- Location: Sunnyvale, CA
I should have realized this from the javadoc. Why does "DefaultGroup" get added to the map? The map does not need to be populated upon construction.david.gilbert wrote:The default constructor for KeyToGroupMap sets up a default group that your code doesn't use but nevertheless the space is allocated for it in the chart. Use the other constructor that specifies the default group.AlanH99 wrote:Code: Select all
KeyToGroupMap groupMap = new KeyToGroupMap(); groupMap.mapKeyToGroup("Target", 0); groupMap.mapKeyToGroup("Current", 1); groupMap.mapKeyToGroup("Preview", 1); renderer.setSeriesToGroupMap(groupMap);
Richard West
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA
Design Engineer II
Advanced Micro Devices
Sunnyvale, CA