Display 2 datasets as stacked charts using dual axis

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
flash
Posts: 6
Joined: Wed Sep 10, 2008 5:22 am

Display 2 datasets as stacked charts using dual axis

Post by flash » Fri Sep 12, 2008 4:33 am

Hi!

Based on my previous post I now need to draw two datasets each with stacked bar charts and dual axis. I tried to modify the code for DualAxisDemo6 (see below). My problems with this is that I would like the charts to display side by side with a space in between and same width for each category, in this case the second graph displays too wide.

Please advise

Code: Select all

import javax.swing.JPanel;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItemCollection;
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.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.GroupedStackedBarRenderer;
import org.jfree.chart.renderer.category.StackedBarRenderer;
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;

/**
 * This demo shows how to create a dual axis bar chart that combines a stacked
 * bar chart and a regular bar chart.  A workaround is used to prevent the
 * two renderers from overlapping the bars for the two datasets - see
 * DualAxisDemo5.java for a simpler case.
 */
public class DualAxisStackedDemo extends ApplicationFrame {

    /**
     * Creates a new demo instance.
     *
     * @param title  the frame title.
     */
    public DualAxisStackedDemo(String title) {
        super(title);
        JPanel chartPanel = createDemoPanel();
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);
    }

    /**
     * Creates a sample dataset.
     *
     * @return  The dataset.
     */
    private static CategoryDataset createDataset1() {

        // row keys...
        String series1 = "Series 1A";
        String series2 = "Series 1B";

        // column keys...
        String category1 = "Category 1";
        String category2 = "Category 2";
        String category3 = "Category 3";
        String category4 = "Category 4";

        // create the dataset...
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        //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(3.0, series2, category1);
        dataset.addValue(6.0, series2, category2);
        dataset.addValue(1.0, series2, category3);
        dataset.addValue(5.0, series2, category4);

        return dataset;

    }

    /**
     * Creates a sample dataset.
     *
     * @return  The dataset.
     */
    private static CategoryDataset createDataset2() {

        // row keys...
        String series1 = "Series 2A";
        String series2 = "Series 2B";

        // column keys...
        String category1 = "Category 1";
        String category2 = "Category 2";
        String category3 = "Category 3";
        String category4 = "Category 4";

        // create the dataset...
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        dataset.addValue(20.0, series1, category1);
        dataset.addValue(30.0, series1, category2);
        dataset.addValue(40.0, series1, category3);
        dataset.addValue(30.0, series1, category4);

        dataset.addValue(75.0, series2, category1);
        dataset.addValue(87.0, series2, category2);
        dataset.addValue(96.0, series2, category3);
        dataset.addValue(68.0, series2, category4);

        return dataset;

    }

    /**
     * Creates a chart.
     *
     * @param dataset1  the first dataset.
     * @param dataset2  the second dataset.
     *
     * @return A chart.
     */
    private static JFreeChart createChart(CategoryDataset dataset1,
                                          CategoryDataset dataset2) {

        CategoryAxis domainAxis = new CategoryAxis("Category");
        NumberAxis rangeAxis = new NumberAxis("Value");
        GroupedStackedBarRenderer renderer1 = new GroupedStackedBarRenderer();
        KeyToGroupMap map = new KeyToGroupMap("G1");
        map.mapKeyToGroup("Series 1A", "G1");
        map.mapKeyToGroup("Series 1B", "G1");
        // define a second group, but nothing maps to it
        map.mapKeyToGroup("NOTHING", "G2");
        renderer1.setSeriesToGroupMap(map);
        CategoryPlot plot = new CategoryPlot(dataset1, domainAxis, rangeAxis,
                renderer1) {

            /**
             * Override the getLegendItems() method to handle special case.
             *
             * @return the legend items.
             */
            public LegendItemCollection getLegendItems() {

                LegendItemCollection result = new LegendItemCollection();

                // we can use all the series from renderer 1
                result.addAll(getRenderer().getLegendItems());

                CategoryDataset dset2 = getDataset(1);
                if (dset2 != null) {
                    CategoryItemRenderer renderer2 = getRenderer(1);
                    if (renderer2 != null) {
                        result.addAll(renderer2.getLegendItems());
                    }
                }

                return result;

            }

        };

        JFreeChart chart = new JFreeChart("Dual Axis Stacked Bar Chart", plot);
        plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
        plot.setDataset(1, dataset2);
        plot.mapDatasetToRangeAxis(1, 1);
        ValueAxis axis2 = new NumberAxis("Secondary");
        plot.setRangeAxis(1, axis2);
        plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_RIGHT);
        StackedBarRenderer renderer2 = new StackedBarRenderer();
        plot.setRenderer(1, renderer2);
       // ChartUtilities.applyCurrentTheme(chart);
        return chart;
    }

    /**
     * Creates a panel for the demo (used by SuperDemo.java).
     *
     * @return A panel.
     */
    public static JPanel createDemoPanel() {
        JFreeChart chart = createChart(createDataset1(), createDataset2());
        return new ChartPanel(chart);
    }

    /**
     * Starting point for the demonstration application.
     *
     * @param args  ignored.
     */
    public static void main(String[] args) {
        DualAxisStackedDemo demo = new DualAxisStackedDemo(
                "JFreeChart: DualAxisDemo6.java");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }

}
[/code]

flash
Posts: 6
Joined: Wed Sep 10, 2008 5:22 am

Post by flash » Thu Sep 18, 2008 7:55 am

Hi!

I finally got this going by modifying the previous code and using the latest version of JFreeChart (I was using an old one 1.0.1). some bugs got fixed probably in the bar renderer..

Code: Select all

import javax.swing.JPanel;

import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItemCollection;
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.labels.StandardCategoryToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
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;

/**
 * This demo shows how to create a dual axis bar chart that combines a stacked
 * bar chart and a regular bar chart.  A workaround is used to prevent the
 * two renderers from overlapping the bars for the two datasets - see
 * DualAxisDemo5.java for a simpler case.
 */
public class DualAxisStackedDemo extends ApplicationFrame {

    /**
     * Creates a new demo instance.
     *
     * @param title  the frame title.
     */
    public DualAxisStackedDemo(String title) {
        super(title);
        JPanel chartPanel = createDemoPanel();
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);
    }

    /**
     * Creates a sample dataset.
     *
     * @return  The dataset.
     */
    private static CategoryDataset createDataset1() {

        // row keys...
        String series1 = "Series 1A";
        String series2 = "Series 1B";

        String series3 = "dummy3";
        String series4 = "dummy4";
        // column keys...
        String category1 = "Category 1";
        String category2 = "Category 2";
        String category3 = "Category 3";
        String category4 = "Category 4";

        // create the dataset...
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        //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(3.0, series2, category1);
        dataset.addValue(6.0, series2, category2);
        dataset.addValue(1.0, series2, category3);
        dataset.addValue(5.0, series2, category4);
        
        
//        dataset.addValue(null, series3, category1);
//        dataset.addValue(null, series3, category2);
//        dataset.addValue(null, series3, category3);
//        dataset.addValue(null, series3, category4);
//        dataset.addValue(null, series4, category1);
//        dataset.addValue(null, series4, category2);
//        dataset.addValue(null, series4, category3);
//        dataset.addValue(null, series4, category4);
        return dataset;

    }

    /**
     * Creates a sample dataset.
     *
     * @return  The dataset.
     */
    private static CategoryDataset createDataset2() {

        // row keys...
        String series1 = "Series 2A";
        String series2 = "Series 2B";
        String series3 = "dummy1";
        String series4 = "dummy2";

        // column keys...
        String category1 = "Category 1";
        String category2 = "Category 2";
        String category3 = "Category 3";
        String category4 = "Category 4";

        // create the dataset...
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();

        dataset.addValue(20.0, series1, category1);
        dataset.addValue(30.0, series1, category2);
        dataset.addValue(40.0, series1, category3);
        dataset.addValue(30.0, series1, category4);

        dataset.addValue(75.0, series2, category1);
        dataset.addValue(87.0, series2, category2);
        dataset.addValue(96.0, series2, category3);
        dataset.addValue(68.0, series2, category4);
//        dataset.addValue(null, series3, category1);
//        dataset.addValue(null, series3, category2);
//        dataset.addValue(null, series3, category3);
//        dataset.addValue(null, series3, category4);
//        dataset.addValue(null, series4, category1);
//        dataset.addValue(null, series4, category2);
//        dataset.addValue(null, series4, category3);
//        dataset.addValue(null, series4, category4);

        return dataset;

    }

    /**
     * Creates a chart.
     *
     * @param dataset1  the first dataset.
     * @param dataset2  the second dataset.
     *
     * @return A chart.
     */
    private static JFreeChart createChart(CategoryDataset dataset1,
                                          CategoryDataset dataset2) {

        CategoryAxis domainAxis = new CategoryAxis("Category");
        NumberAxis rangeAxis = new NumberAxis("Value");
        GroupedStackedBarRenderer renderer1 = new GroupedStackedBarRenderer();
        renderer1.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
        KeyToGroupMap map = new KeyToGroupMap("G1");
        map.mapKeyToGroup("Series 1A", "G1");
        map.mapKeyToGroup("Series 1B", "G1");
        // define a second group, but nothing maps to it
        map.mapKeyToGroup("NOTHING", "G2");

        renderer1.setSeriesToGroupMap(map);
        CategoryPlot plot = new CategoryPlot(dataset1, domainAxis, rangeAxis,
                renderer1) {

            /**
             * Override the getLegendItems() method to handle special case.
             *
             * @return the legend items.
             */
            public LegendItemCollection getLegendItems() {

                LegendItemCollection result = new LegendItemCollection();

                // we can use all the series from renderer 1
                result.addAll(getRenderer().getLegendItems());

                CategoryDataset dset2 = getDataset(1);
                if (dset2 != null) {
                    CategoryItemRenderer renderer2 = getRenderer(1);
                    if (renderer2 != null) {
                        result.addAll(renderer2.getLegendItems());
                    }
                }

                return result;

            }

        };

        JFreeChart chart = new JFreeChart("Dual Axis Stacked Bar Chart", plot);
        plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
        plot.setDataset(1, dataset2);
        plot.mapDatasetToRangeAxis(1, 1);
        ValueAxis axis2 = new NumberAxis("Secondary");
        plot.setRangeAxis(1, axis2);
        GroupedStackedBarRenderer renderer2 = new GroupedStackedBarRenderer();
        map = new KeyToGroupMap("G1");
        map.mapKeyToGroup("Series 2A", "G2");
        map.mapKeyToGroup("Series 2B", "G2");
        plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_RIGHT);
        renderer2.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
	renderer2.setSeriesToGroupMap(map);
        plot.setRenderer(1, renderer2);
       // ChartUtilities.applyCurrentTheme(chart);
        return chart;
    }

    /**
     * Creates a panel for the demo (used by SuperDemo.java).
     *
     * @return A panel.
     */
    public static JPanel createDemoPanel() {
        JFreeChart chart = createChart(createDataset1(), createDataset2());
        return new ChartPanel(chart);
    }

    /**
     * Starting point for the demonstration application.
     *
     * @param args  ignored.
     */
    public static void main(String[] args) {
        DualAxisStackedDemo demo = new DualAxisStackedDemo(
                "JFreeChart: DualAxisDemo6.java");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        demo.setVisible(true);
    }

}

Didi-chan
Posts: 5
Joined: Fri Feb 27, 2009 1:53 pm

Re: Display 2 datasets as stacked charts using dual axis

Post by Didi-chan » Mon Mar 02, 2009 10:12 am

Isn't there a way to do it without that "null series" stuff??

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: Display 2 datasets as stacked charts using dual axis

Post by david.gilbert » Mon Mar 02, 2009 4:51 pm

Not if you need the dual axis support. I think it would be possible to create a custom bar renderer that allowed you to specify for each series which rangeAxis the value should map to...then separate out the bars (at rendering time) accordingly. But it would take a bit of work to write such a renderer.
David Gilbert
JFreeChart Project Leader

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

Locked