Search code examples
javachartsjfreechart

Stacked Bar Chart having upper limit line using jfreechart


I'm trying to generate a Stacked Bar Chart having an upper limit for each and every category. The upper limit varies for each and every category and is indicated by a horizontal line.

I was able to generate the stacked bar chart but got struck with horizontal line for indicating upper limit.

Here is the sample chart.

Sample Stacked Bar Chart

Here is my code for generating stacked bar chart

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Paint;
import java.awt.Stroke;
import java.io.IOException;
import java.io.OutputStream;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItem;
import org.jfree.chart.LegendItemCollection;
import org.jfree.chart.axis.SubCategoryAxis;
import org.jfree.chart.plot.CategoryMarker;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
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.GradientPaintTransformType;
import org.jfree.ui.Layer;
import org.jfree.ui.StandardGradientPaintTransformer;

public class StackedBarServlet extends HttpServlet{
    private static final long serialVersionUID = 1L;
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

        response.setContentType("image/png");

        OutputStream outputStream = response.getOutputStream();
        final CategoryDataset dataset = createDataset();
        final JFreeChart chart = createChart(dataset);
        int width = 800;
        int height = 350;
        ChartUtilities.writeChartAsPNG(outputStream, chart, width, height);

    }
      private CategoryDataset createDataset() {
            DefaultCategoryDataset result = new DefaultCategoryDataset();

            result.addValue(20.3, "Product 1 (US)", "Jan 04");
            result.addValue(27.2, "Product 1 (US)", "Feb 04");
            result.addValue(19.7, "Product 1 (US)", "Mar 04");
            result.addValue(20.3, "Product 1 (US)", "Apr 04");
            result.addValue(27.2, "Product 1 (US)", "May 04");
            result.addValue(19.7, "Product 1 (US)", "Jun 04");
            result.addValue(20.3, "Product 1 (US)", "Jul 04");
            result.addValue(27.2, "Product 1 (US)", "Aug 04");
            result.addValue(19.7, "Product 1 (US)", "Sep 04");
            result.addValue(20.3, "Product 1 (US)", "Oct 04");
            result.addValue(27.2, "Product 1 (US)", "Nov 04");
            result.addValue(19.7, "Product 1 (US)", "Dec 04");
            result.addValue(20.3, "Product 1 (US)", "Bab 04");
            result.addValue(27.2, "Product 1 (US)", "Lal 04");
            result.addValue(19.7, "Product 1 (US)", "Sha 04");

            result.addValue(20.3, "Product 1 (UK)", "Jan 04");
            result.addValue(27.2, "Product 1 (UK)", "Feb 04");
            result.addValue(19.7, "Product 1 (UK)", "Mar 04");
            result.addValue(20.3, "Product 1 (UK)", "Apr 04");
            result.addValue(27.2, "Product 1 (UK)", "May 04");
            result.addValue(19.7, "Product 1 (UK)", "Jun 04");
            result.addValue(20.3, "Product 1 (UK)", "Jul 04");
            result.addValue(27.2, "Product 1 (UK)", "Aug 04");
            result.addValue(19.7, "Product 1 (UK)", "Sep 04");
            result.addValue(20.3, "Product 1 (UK)", "Oct 04");
            result.addValue(27.2, "Product 1 (UK)", "Nov 04");
            result.addValue(19.7, "Product 1 (UK)", "Dec 04");
            result.addValue(20.3, "Product 1 (UK)", "Bab 04");
            result.addValue(27.2, "Product 1 (UK)", "Lal 04");
            result.addValue(19.7, "Product 1 (UK)", "Sha 04");

            result.addValue(20.3, "Product 1 (IND)", "Jan 04");
            result.addValue(27.2, "Product 1 (IND)", "Feb 04");
            result.addValue(19.7, "Product 1 (IND)", "Mar 04");
            result.addValue(20.3, "Product 1 (IND)", "Apr 04");
            result.addValue(27.2, "Product 1 (IND)", "May 04");
            result.addValue(19.7, "Product 1 (IND)", "Jun 04");
            result.addValue(20.3, "Product 1 (IND)", "Jul 04");
            result.addValue(27.2, "Product 1 (IND)", "Aug 04");
            result.addValue(19.7, "Product 1 (IND)", "Sep 04");
            result.addValue(20.3, "Product 1 (IND)", "Oct 04");
            result.addValue(27.2, "Product 1 (IND)", "Nov 04");
            result.addValue(19.7, "Product 1 (IND)", "Dec 04");
            result.addValue(20.3, "Product 1 (IND)", "Bab 04");
            result.addValue(27.2, "Product 1 (IND)", "Lal 04");
            result.addValue(19.7, "Product 1 (IND)", "Sha 04");

            result.addValue(20.3, "Product 1 (EUROPE)", "Jan 04");
            result.addValue(27.2, "Product 1 (EUROPE)", "Feb 04");
            result.addValue(19.7, "Product 1 (EUROPE)", "Mar 04");
            result.addValue(20.3, "Product 1 (EUROPE)", "Apr 04");
            result.addValue(27.2, "Product 1 (EUROPE)", "May 04");
            result.addValue(19.7, "Product 1 (EUROPE)", "Jun 04");
            result.addValue(20.3, "Product 1 (EUROPE)", "Jul 04");
            result.addValue(27.2, "Product 1 (EUROPE)", "Aug 04");
            result.addValue(19.7, "Product 1 (EUROPE)", "Sep 04");
            result.addValue(20.3, "Product 1 (EUROPE)", "Oct 04");
            result.addValue(27.2, "Product 1 (EUROPE)", "Nov 04");
            result.addValue(19.7, "Product 1 (EUROPE)", "Dec 04");
            result.addValue(20.3, "Product 1 (EUROPE)", "Bab 04");
            result.addValue(27.2, "Product 1 (EUROPE)", "Lal 04");
            result.addValue(19.7, "Product 1 (EUROPE)", "Sha 04");

            return result;
        }

        private JFreeChart createChart(final CategoryDataset dataset) {

            final JFreeChart chart = ChartFactory.createStackedBarChart(
                "Stacked Bar",  // chart title
                "Category",                  // 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("Product 1 (US)", "G1");
            map.mapKeyToGroup("Product 1 (Europe)", "G1");
            map.mapKeyToGroup("Product 1 (Asia)", "G1");
            map.mapKeyToGroup("Product 1 (Middle East)", "G1");

            renderer.setSeriesToGroupMap(map); 

            renderer.setItemMargin(0.0);
            Paint p1 = new GradientPaint(
                0.0f, 0.0f, new Color(0x22, 0x22, 0xFF), 0.0f, 0.0f, new Color(0x88, 0x88, 0xFF)
            );
            renderer.setSeriesPaint(0, p1);
            renderer.setSeriesPaint(4, p1);
            renderer.setSeriesPaint(8, p1);

            Paint p2 = new GradientPaint(
                0.0f, 0.0f, new Color(0x22, 0xFF, 0x22), 0.0f, 0.0f, new Color(0x88, 0xFF, 0x88)
            );
            renderer.setSeriesPaint(1, p2); 
            renderer.setSeriesPaint(5, p2); 
            renderer.setSeriesPaint(9, p2); 

            Paint p3 = new GradientPaint(
                0.0f, 0.0f, new Color(0xFF, 0x22, 0x22), 0.0f, 0.0f, new Color(0xFF, 0x88, 0x88)
            );
            renderer.setSeriesPaint(2, p3);
            renderer.setSeriesPaint(6, p3);
            renderer.setSeriesPaint(10, p3);

            Paint p4 = new GradientPaint(
                0.0f, 0.0f, new Color(0xFF, 0xFF, 0x22), 0.0f, 0.0f, new Color(0xFF, 0xFF, 0x88)
            );
            renderer.setSeriesPaint(3, p4);
            renderer.setSeriesPaint(7, p4);
            renderer.setSeriesPaint(11, p4);
            renderer.setGradientPaintTransformer(
                new StandardGradientPaintTransformer(GradientPaintTransformType.HORIZONTAL)
            );

            SubCategoryAxis domainAxis = new SubCategoryAxis("Product");
            domainAxis.setCategoryMargin(0.15);

            CategoryPlot plot = (CategoryPlot) chart.getPlot();
            plot.setDomainAxis(domainAxis);
            plot.setRenderer(renderer);
            plot.setFixedLegendItems(createLegendItems());

            /*
             * This is used to draw a vertical line
             */
    /*        Stroke stroke = new BasicStroke(2.0f);
            ValueMarker marker = new ValueMarker(100);  // position is the value on the axis
            marker.setPaint(Color.black);
            marker.setStroke(stroke);

            CategoryPlot plot1 = chart.getCategoryPlot();
            plot1.addRangeMarker(marker,Layer.FOREGROUND); */

            return chart;

        }

        private LegendItemCollection createLegendItems() {
            LegendItemCollection result = new LegendItemCollection();
            LegendItem item1 = new LegendItem("US", new Color(0x22, 0x22, 0xFF));
            LegendItem item2 = new LegendItem("Europe", new Color(0x22, 0xFF, 0x22));
            LegendItem item3 = new LegendItem("Asia", new Color(0xFF, 0x22, 0x22));
            LegendItem item4 = new LegendItem("Middle East", new Color(0xFF, 0xFF, 0x22));
            result.add(item1);
            result.add(item2);
            result.add(item3);
            result.add(item4);
            return result;
        }
}

When I used addRangeMarker, it gives me a continuous horizontal line. But in my case, I need multiple horizonatal lines for each and every category seperately.

Here is the sample image with addRangeMarker.

enter image description here

Thanks in advance.


Solution

  • You need to create a second dataset containing the values that you want to display with the horizontal black lines. Add that dataset to your plot along with a LevelRenderer.