Can we draw a line chart by GroupedStackedBarChart

I am trying to create a GroupedStackBar chart that shows the revenue for each customer for the last three months for each product and adds a line chart (s) showing the meetings made with the customer during each period. I use JasperReports to create a PDF report using the usual chart adapters to prepare it.

The following snapshot suggests the chart I'm trying to create:

chart image .

The report should display monthly income and meetings for each client. As with the case, show that Client1 provided X mn in revenue and had meetings M in November, Y mn in revenue and N meetings in December, etc.

So, my X axis has two groups - customers and the month in the last quarter. In addition, income fits more into products. Thus, I’m going to merge two different data sets: an income indicator for each client, months, a product versus Meetings measure for each client, a month to build a chart.

An example program that I created to create a chart:

 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.NumberAxis; import org.jfree.chart.axis.SubCategoryAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.category.GroupedStackedBarRenderer; import org.jfree.chart.renderer.category.LineAndShapeRenderer; 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; public class GroupedStackedBarLineChart extends ApplicationFrame { public GroupedStackedBarLineChart(final String title) { super(title); // final JFreeChart chart = constructBarOverLineChart(); final JFreeChart chart = constructLineOverBarChart(); final ChartPanel panel = new ChartPanel(chart); setContentPane(panel); } private JFreeChart constructLineOverBarChart() { final JFreeChart chart = ChartFactory.createLineChart( "Stacked Grouped Bar Line Chart", "Products/Month", "Meetings/Month", fetchMeetingDataSet(), PlotOrientation.VERTICAL, true, true, false); final KeyToGroupMap map = new KeyToGroupMap("Jan13"); map.mapKeyToGroup("Jan13 (Product1)", "Jan13"); map.mapKeyToGroup("Jan13 (Product2)", "Jan13"); map.mapKeyToGroup("Jan13 (Product3)", "Jan13"); map.mapKeyToGroup("Feb13 (Product1)", "Feb13"); map.mapKeyToGroup("Feb13 (Product2)", "Feb13"); map.mapKeyToGroup("Feb13 (Product3)", "Feb13"); map.mapKeyToGroup("Mar13 (Product1)", "Mar13"); map.mapKeyToGroup("Mar13 (Product2)", "Mar13"); map.mapKeyToGroup("Mar13 (Product3)", "Mar13"); final GroupedStackedBarRenderer renderer = new GroupedStackedBarRenderer(); renderer.setSeriesToGroupMap(map); renderer.setItemMargin(0.076); final SubCategoryAxis domainAxis = new SubCategoryAxis("Products/Month"); domainAxis.addSubCategory("Jan13"); domainAxis.addSubCategory("Feb13"); domainAxis.addSubCategory("Mar13"); domainAxis.setCategoryMargin(0.28); final CategoryPlot subPlot1 = (CategoryPlot) chart.getPlot(); subPlot1.setDataset(1, fetchRevenueDataSet()); subPlot1.setDomainAxis(domainAxis); final ValueAxis revenueAxis = new NumberAxis("Revenue"); subPlot1.setRangeAxis(1, revenueAxis); subPlot1.setRenderer(1, renderer); return chart; } private JFreeChart constructBarOverLineChart() { final JFreeChart chart = ChartFactory.createStackedBarChart( "Stacked Grouped Bar Line Chart", "Clients", "Revenue", fetchRevenueDataSet(), PlotOrientation.VERTICAL, true, true, false); final KeyToGroupMap map = new KeyToGroupMap("Jan13"); map.mapKeyToGroup("Jan13 (Product1)", "Jan13"); map.mapKeyToGroup("Jan13 (Product2)", "Jan13"); map.mapKeyToGroup("Jan13 (Product3)", "Jan13"); map.mapKeyToGroup("Feb13 (Product1)", "Feb13"); map.mapKeyToGroup("Feb13 (Product2)", "Feb13"); map.mapKeyToGroup("Feb13 (Product3)", "Feb13"); map.mapKeyToGroup("Mar13 (Product1)", "Mar13"); map.mapKeyToGroup("Mar13 (Product2)", "Mar13"); map.mapKeyToGroup("Mar13 (Product3)", "Mar13"); final GroupedStackedBarRenderer renderer = new GroupedStackedBarRenderer(); renderer.setSeriesToGroupMap(map); renderer.setItemMargin(0.076); final SubCategoryAxis domainAxis = new SubCategoryAxis("Products/Month"); domainAxis.addSubCategory("Jan13"); domainAxis.addSubCategory("Feb13"); domainAxis.addSubCategory("Mar13"); domainAxis.setCategoryMargin(0.28); final CategoryPlot subPlot1 = (CategoryPlot) chart.getPlot(); subPlot1.setDomainAxis(domainAxis); subPlot1.setRenderer(renderer); final ValueAxis meetingAxis = new NumberAxis("Meetings"); subPlot1.setDataset(1, fetchMeetingDataSet()); // subPlot1.mapDatasetToDomainAxis(1, 1); subPlot1.setRangeAxis(1, meetingAxis); subPlot1.setRangeAxisLocation(0, AxisLocation.BOTTOM_OR_LEFT); subPlot1.setRangeAxisLocation(1, AxisLocation.TOP_OR_RIGHT); subPlot1.setRenderer(1, new LineAndShapeRenderer(true, false)); return chart; } private CategoryDataset fetchRevenueDataSet() { final DefaultCategoryDataset revenueDataSet = new DefaultCategoryDataset(); revenueDataSet.addValue(20.3, "Jan13 (Product1)", "Client1"); revenueDataSet.addValue(27.2, "Jan13 (Product2)", "Client1"); revenueDataSet.addValue(19.7, "Jan13 (Product3)", "Client1"); revenueDataSet.addValue(19.4, "Feb13 (Product1)", "Client1"); revenueDataSet.addValue(10.9, "Feb13 (Product2)", "Client1"); revenueDataSet.addValue(18.4, "Feb13 (Product3)", "Client1"); revenueDataSet.addValue(16.5, "Mar13 (Product1)", "Client1"); revenueDataSet.addValue(15.9, "Mar13 (Product2)", "Client1"); revenueDataSet.addValue(16.1, "Mar13 (Product3)", "Client1"); revenueDataSet.addValue(23.3, "Jan13 (Product1)", "Client2"); revenueDataSet.addValue(16.2, "Jan13 (Product2)", "Client2"); revenueDataSet.addValue(28.7, "Jan13 (Product3)", "Client2"); revenueDataSet.addValue(12.7, "Feb13 (Product1)", "Client2"); revenueDataSet.addValue(17.9, "Feb13 (Product2)", "Client2"); revenueDataSet.addValue(12.6, "Feb13 (Product3)", "Client2"); revenueDataSet.addValue(15.4, "Mar13 (Product1)", "Client2"); revenueDataSet.addValue(21.0, "Mar13 (Product2)", "Client2"); revenueDataSet.addValue(11.1, "Mar13 (Product3)", "Client2"); revenueDataSet.addValue(23.8, "Jan13 (Product1)", "Client3"); revenueDataSet.addValue(23.4, "Jan13 (Product2)", "Client3"); revenueDataSet.addValue(19.3, "Jan13 (Product3)", "Client3"); revenueDataSet.addValue(11.9, "Feb13 (Product1)", "Client3"); revenueDataSet.addValue(31.0, "Feb13 (Product2)", "Client3"); revenueDataSet.addValue(22.7, "Feb13 (Product3)", "Client3"); revenueDataSet.addValue(15.3, "Mar13 (Product1)", "Client3"); revenueDataSet.addValue(14.4, "Mar13 (Product2)", "Client3"); revenueDataSet.addValue(25.3, "Mar13 (Product3)", "Client3"); return revenueDataSet; } private CategoryDataset fetchMeetingDataSet() { final DefaultCategoryDataset meetingDataSet = new DefaultCategoryDataset(); meetingDataSet.addValue(20, "Jan13", "Client1"); meetingDataSet.addValue(8, "Feb13", "Client1"); meetingDataSet.addValue(35, "Mar13", "Client1"); meetingDataSet.addValue(7, "Jan13", "Client2"); meetingDataSet.addValue(20, "Feb13", "Client2"); meetingDataSet.addValue(12, "Mar13", "Client2"); meetingDataSet.addValue(25, "Jan13", "Client3"); meetingDataSet.addValue(17, "Feb13", "Client3"); meetingDataSet.addValue(7, "Mar13", "Client3"); return meetingDataSet; } public static void main(String[] args) { GroupedStackedBarLineChart demo = new GroupedStackedBarLineChart( "Client Revenue and Meetings"); demo.pack(); RefineryUtilities.centerFrameOnScreen(demo); demo.setVisible(true); } } 

The above program does not display the graph as required. Instead, the line diagram shows P meetings for January 13 with Client1 , Q meetings for January 13 with Client2 , R meetings for January 13 with Client3 and X meetings for February 13 with Client2 , Y for February 13 with Client2 , etc. That is, the grouping for the client is not respected. I tried changing the row / column key in a line chart set without a lesson.

Could you please point me to the correct line chart?

Thanks.

+4
source share
1 answer

My first thought was to implement my own renderer - a mixture of GroupStackedBarRenderer and LineAndShapeRenderer - but the next fake grouping was easier;)

So, I replaced GroupedStackedBarRenderer with StackeBarRenderer and inserted a dummy column between groups. Grouped category labels for customers were archived by the second domain axis - lucky, the labels of the second axis of the category are centered within the groups of the first axis, regardless of how many customers / groups are used ...

 import java.awt.Graphics2D; import org.apache.commons.beanutils.PropertyUtilsBean; 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.NumberAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.category.StackedBarRenderer; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; import org.jfree.text.G2TextMeasurer; import org.jfree.text.TextBlock; import org.jfree.text.TextUtilities; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RectangleEdge; import org.jfree.ui.RefineryUtilities; public class GroupedStackedBarLineChart extends ApplicationFrame { public GroupedStackedBarLineChart(final String title) { super(title); // final JFreeChart chart = constructBarOverLineChart(); final JFreeChart chart = constructLineOverBarChart(); final ChartPanel panel = new ChartPanel(chart); setContentPane(panel); } private JFreeChart constructLineOverBarChart() { final JFreeChart chart = ChartFactory.createLineChart( "Stacked Grouped Bar Line Chart", "", "Meetings/Month", fetchMeetingDataSet(), PlotOrientation.VERTICAL, true, true, false); final StackedBarRenderer renderer = new StackedBarRenderer(); renderer.setItemMargin(0.076); final CategoryPlot cp = chart.getCategoryPlot(); cp.setDataset(1, fetchRevenueDataSet()); final ValueAxis revenueAxis = new NumberAxis("Revenue"); cp.setRangeAxis(1, revenueAxis); cp.setRenderer(1, renderer); chopCategoryLabels(cp); insertFakeGrouping(cp); CategoryAxis ca = new CategoryAxis("Products/Month"); cp.setDomainAxis(1, ca); cp.setDataset(2, anotherDataSet()); cp.mapDatasetToDomainAxis(2, 1); cp.setDomainAxisLocation(1, AxisLocation.BOTTOM_OR_LEFT); ca.setAxisLineVisible(false); ca.setTickMarksVisible(false); return chart; } private void insertFakeGrouping(CategoryPlot cp) { for (int i=0; i<cp.getDatasetCount(); i++) { assert(cp.getDataset(i) instanceof DefaultCategoryDataset); CategoryDataset cd = cp.getDataset(i); Comparable<?> firstRow = cd.getRowKey(0); DefaultCategoryDataset dcd = new DefaultCategoryDataset(); for (int col=0; col<cd.getColumnCount(); col++) { if (col > 0) { String c1 = cd.getColumnKey(col-1).toString(); c1 = c1.substring(c1.indexOf('_')); String c2 = cd.getColumnKey(col).toString(); c2 = c2.substring(c2.indexOf('_')); if (!c1.equals(c2)) { dcd.addValue(null, firstRow, "dummy"+col); } } for (int row=0; row<cd.getRowCount(); row++) { Comparable<?> rowKey = cd.getRowKey(row); Comparable<?> columnKey = cd.getColumnKey(col); dcd.addValue(cd.getValue(rowKey, columnKey), rowKey, columnKey); } } cp.setDataset(i, dcd); } } private void chopCategoryLabels(CategoryPlot cp) { CategoryAxis caOld = cp.getDomainAxis(); CategoryAxis caNew = new CategoryAxis(){ protected TextBlock createLabel(Comparable category, float width, RectangleEdge edge, Graphics2D g2) { String cat = category.toString(); cat = (cat.contains("_")) ? cat.substring(0, cat.indexOf('_')) : ""; TextBlock label = TextUtilities.createTextBlock(cat, getTickLabelFont(category), getTickLabelPaint(category), width, getMaximumCategoryLabelLines(), new G2TextMeasurer(g2)); return label; } }; try { new PropertyUtilsBean().copyProperties(caNew, caOld); cp.setDomainAxis(0, caNew); } catch (Exception e) { throw new RuntimeException("not really?", e); } } private CategoryDataset anotherDataSet() { final DefaultCategoryDataset ds = new DefaultCategoryDataset(); ds.addValue(1, "1", "Client 1"); ds.addValue(1, "2", "Client 2"); ds.addValue(1, "3", "Client 3"); return ds; } private CategoryDataset fetchRevenueDataSet() { final DefaultCategoryDataset revenueDataSet = new DefaultCategoryDataset(); revenueDataSet.addValue(20.3, "Product 1", "Jan13_1"); revenueDataSet.addValue(27.2, "Product 2", "Jan13_1"); revenueDataSet.addValue(19.7, "Product 3", "Jan13_1"); revenueDataSet.addValue(19.4, "Product 1", "Feb13_1"); revenueDataSet.addValue(10.9, "Product 2", "Feb13_1"); revenueDataSet.addValue(18.4, "Product 3", "Feb13_1"); revenueDataSet.addValue(16.5, "Product 1", "Mar13_1"); revenueDataSet.addValue(15.9, "Product 2", "Mar13_1"); revenueDataSet.addValue(16.1, "Product 3", "Mar13_1"); revenueDataSet.addValue(23.3, "Product 1", "Jan13_2"); revenueDataSet.addValue(16.2, "Product 2", "Jan13_2"); revenueDataSet.addValue(28.7, "Product 3", "Jan13_2"); revenueDataSet.addValue(12.7, "Product 1", "Feb13_2"); revenueDataSet.addValue(17.9, "Product 2", "Feb13_2"); revenueDataSet.addValue(12.6, "Product 3", "Feb13_2"); revenueDataSet.addValue(15.4, "Product 1", "Mar13_2"); revenueDataSet.addValue(21.0, "Product 2", "Mar13_2"); revenueDataSet.addValue(11.1, "Product 3", "Mar13_2"); revenueDataSet.addValue(23.8, "Product 1", "Jan13_3"); revenueDataSet.addValue(23.4, "Product 2", "Jan13_3"); revenueDataSet.addValue(19.3, "Product 3", "Jan13_3"); revenueDataSet.addValue(11.9, "Product 1", "Feb13_3"); revenueDataSet.addValue(31.0, "Product 2", "Feb13_3"); revenueDataSet.addValue(22.7, "Product 3", "Feb13_3"); revenueDataSet.addValue(15.3, "Product 1", "Mar13_3"); revenueDataSet.addValue(14.4, "Product 2", "Mar13_3"); revenueDataSet.addValue(25.3, "Product 3", "Mar13_3"); return revenueDataSet; } private CategoryDataset fetchMeetingDataSet() { final DefaultCategoryDataset meetingDataSet = new DefaultCategoryDataset(); meetingDataSet.addValue(20, "Meetings", "Jan13_1"); meetingDataSet.addValue(8, "Meetings", "Feb13_1"); meetingDataSet.addValue(35, "Meetings", "Mar13_1"); meetingDataSet.addValue(7, "Meetings", "Jan13_2"); meetingDataSet.addValue(20, "Meetings", "Feb13_2"); meetingDataSet.addValue(12, "Meetings", "Mar13_2"); meetingDataSet.addValue(25, "Meetings", "Jan13_3"); meetingDataSet.addValue(17, "Meetings", "Feb13_3"); meetingDataSet.addValue(7, "Meetings", "Mar13_3"); return meetingDataSet; } public static void main(String[] args) { GroupedStackedBarLineChart demo = new GroupedStackedBarLineChart( "Client Revenue and Meetings"); demo.pack(); RefineryUtilities.centerFrameOnScreen(demo); demo.setVisible(true); } } 
+2
source

All Articles