Search code examples
javaswingjfreechart

Labels with LayeredBarRenderer


Consider a smaller version of this example:

public class LayeredBarChartDemo2 extends ApplicationFrame {

    public LayeredBarChartDemo2(final String title) {
        super(title);
        final double[][] data = new double[][] { { 55, 60 }, { 25.0, 13.0 } };

        final CategoryDataset dataset = DatasetUtils.createCategoryDataset("Series ", "Factor ", data);

        // create the chart...
        final CategoryAxis categoryAxis = new CategoryAxis("Category");
        final ValueAxis valueAxis = new NumberAxis("Score (%)");

        final CategoryPlot plot = new CategoryPlot(dataset, categoryAxis, valueAxis, new LayeredBarRenderer());
        final JFreeChart chart = new JFreeChart("Layered Bar Chart Demo 2", JFreeChart.DEFAULT_TITLE_FONT, plot, true);

        final LayeredBarRenderer renderer = (LayeredBarRenderer) plot.getRenderer();

        // add the chart to a panel...
        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);

    }

    public static void main(final String[] args) {
        final LayeredBarChartDemo2 demo = new LayeredBarChartDemo2("Layered Bar Chart Demo 2");
        demo.pack();
        demo.setVisible(true);
    }
}

It produces:

result

I want to add labels on it, and make it look like this:

want

I have tried what works for other renderers:

renderer.setDefaultItemLabelsVisible(true);

Or:

renderer.setSeriesItemLabelsVisible(0, true);
renderer.setSeriesItemLabelsVisible(1, true);

I also tried to declare a CategoryItemLabelGenerator explicitly:

renderer.setDefaultItemLabelGenerator(new CategoryItemLabelGenerator() {

    @Override
    public String generateRowLabel(CategoryDataset dataset, int row) {
        return "sasa";
    }

    @Override
    public String generateLabel(CategoryDataset dataset, int row, int column) {
        return "lalal";
    }

    @Override
    public String generateColumnLabel(CategoryDataset dataset, int column) {
        return "ababa";
    }
});

(I also tried using setSeriesItemLabelGenerator(series, CategoryLabelGenerator) too).

I changed the font & the paint in case they are there but I just do not see them.

I use JFreeChart 1.5.0.

Is there a way to add the labels?


Solution

  • The apparent bug identified here by @George Z. hinges on an incorrect value calculated by the LayeredBarRenderer implementation of drawVerticalItem() when it calls drawItemLabel() as shown here. The predicate transX1 > transX2 should be inverted.

    As a workaround when using v1.5, it's possible to specify a negative ItemLabelPosition, as shown the variation below.

    ItemLabelPosition position = new ItemLabelPosition(
        ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER);
    renderer.setDefaultNegativeItemLabelPosition(position);
    

    PlotOrientation.VERTICAL: PlotOrientation.VERTICAL

    As the implementation of drawHorizontalItem() appears correct, a positive ItemLabelPosition works as expected.

    ItemLabelPosition position = new ItemLabelPosition(
        ItemLabelAnchor.OUTSIDE3, TextAnchor.CENTER_LEFT);
    renderer.setDefaultPositiveItemLabelPosition(position);
    

    PlotOrientation.HORIZONTAL: PlotOrientation.HORIZONTAL

    In addition, a StandardCategoryToolTipGenerator works as expected. You can customize the DEFAULT_TOOL_TIP_FORMAT_STRING as shown here and here.

    renderer.setDefaultToolTipGenerator(new StandardCategoryToolTipGenerator());
    

    Code:

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import org.jfree.chart.ChartPanel;
    import org.jfree.chart.ChartUtils;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.axis.CategoryAxis;
    import org.jfree.chart.axis.NumberAxis;
    import org.jfree.chart.axis.ValueAxis;
    import org.jfree.chart.labels.ItemLabelAnchor;
    import org.jfree.chart.labels.ItemLabelPosition;
    import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
    import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
    import org.jfree.chart.plot.CategoryPlot;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.chart.renderer.category.LayeredBarRenderer;
    import org.jfree.data.category.CategoryDataset;
    import org.jfree.data.general.DatasetUtils;
    import org.jfree.chart.ui.ApplicationFrame;
    import org.jfree.chart.ui.TextAnchor;
    
    /** @see https://stackoverflow.com/a/63464855/230513 */
    public class LayeredBarChartDemo2 extends ApplicationFrame {
        
        private static final String TITLE = "Layered Bar Chart Demo 2";
        
        public LayeredBarChartDemo2(final String title) {
            super(title);
            final double[][] data = new double[][]{{55, 60}, {25, 13}};
            final CategoryDataset dataset = DatasetUtils.createCategoryDataset("Series ", "Factor ", data);
            final CategoryAxis categoryAxis = new CategoryAxis("Category");
            final ValueAxis valueAxis = new NumberAxis("Score (%)");
            final LayeredBarRenderer renderer = new LayeredBarRenderer();
            renderer.setDefaultToolTipGenerator(new StandardCategoryToolTipGenerator());
            renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            renderer.setDefaultItemLabelsVisible(true);
            ItemLabelPosition position = new ItemLabelPosition(
                ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER);
            renderer.setDefaultNegativeItemLabelPosition(position);
            final CategoryPlot plot = new CategoryPlot(dataset, categoryAxis, valueAxis, renderer);
            plot.setOrientation(PlotOrientation.VERTICAL);
            final JFreeChart chart = new JFreeChart(TITLE, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
            ChartUtils.applyCurrentTheme(chart);
            add(new ChartPanel(chart) {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(640, 480);
                }
            });
        }
        
        public static void main(final String[] args) {
            EventQueue.invokeLater(() -> {
                final LayeredBarChartDemo2 demo = new LayeredBarChartDemo2(TITLE);
                demo.pack();
                demo.setLocationRelativeTo(null);
                demo.setVisible(true);
            });
        }
    }