Search code examples
javaswingjfreechart

How to create stacked interval charts with JFreeChart?


Objective is to build an interval bar chart indicating, for each category, a range of acceptable values (between 0 - 100%).

As for each category, I would like to indicate 2 intervals (i.e. a center interval that is green and a surrounding interval that is grey), I think that it is not feasible with a IntervalBarRenderer and I have thus been using a StackedBarRenderer (with transparent layers at the extreme left & right of each bar).

Would this be the right approach?

Also, if this is the right approach, it seems that the bar intervals that are transparent (at the extreme left and right of each bar), do not show their outline: is their any way to have an outline for a transparent paint?

Please see below for the main code and a screenshot of current results.

Many thanks for any help or hint !

Thomas Current result - not satisfactory

private JFreeChart createChart(LeaksChartSeriesVO data){
    JFreeChart chart = ChartFactory.createStackedBarChart(
            "Leak meters", //Title
            "Leaks", //Domain axis (X) label
            "%", //Range axis (Y) label
            data.bars,
            PlotOrientation.HORIZONTAL, 
            true, //Legend?
            true, //Tooltip?
            false); //Urls?
    CategoryPlot plot = (CategoryPlot) chart.getPlot();

    //Sets X axis sub-legends
    SubCategoryAxis subCat = new SubCategoryAxis("Leak meters");

    //Adds second dataset
    plot.setDataset(1, data.dots);

    //Defines level renderer
    LevelRenderer renderer1 = new LevelRenderer();
    renderer1.setSeriesPaint(0, Color.black);
    plot.setRenderer(1, renderer1);

    //Sets Y axis as %
    ((StackedBarRenderer) plot.getRenderer()).setRenderAsPercentages(true);

    //Sets colors
    ((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(0, new Color(0, 0, 0, 0)); //Transparent for start
    ((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(1, Color.gray); //Grey low
    ((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(2, Color.green); //Green
    ((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(3, Color.gray); //Grey high
    ((StackedBarRenderer) plot.getRenderer()).setSeriesPaint(4, new Color(0, 0, 0, 0)); //Transparent for end
    ((StackedBarRenderer) plot.getRenderer()).setDrawBarOutline(true);
    ((StackedBarRenderer) plot.getRenderer()).setBaseOutlinePaint(Color.black);

    //Setup which items not to see in legend
    ((StackedBarRenderer) plot.getRenderer()).setSeriesVisibleInLegend(0, false);
    ((StackedBarRenderer) plot.getRenderer()).setSeriesVisibleInLegend(3, false);
    ((StackedBarRenderer) plot.getRenderer()).setSeriesVisibleInLegend(4, false);

    //Sets renderer & axis
    plot.setDomainAxis(subCat);

    //Changes plot render sequence so that bars are in the background and shapes in front
    chart.getCategoryPlot().setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);

    //Sets margins between bars
    chart.getCategoryPlot().getDomainAxis().setCategoryMargin(0.5f);

    return chart;
}


Solution

  • This is the default behaviour of the GradientBarPainter which is used to draw the bars: when the bar is transparent, it doesn't draw the outline.

    You can instead use the StandardBarPainter which will draw the outline.

    Just add:

    StackedBarRenderer renderer = (StackedBarRenderer) plot.getRenderer();
    renderer.setBarPainter(new StandardBarPainter());
    

    Another solution is to keep the GradientBarPainter but use an almost transparent color for the bar:

    setSeriesPaint(0, new Color(0, 0, 0, 1));