How to add label values and error bars to a JFreeChart line chart?

眉间皱痕 提交于 2019-12-29 01:51:22

问题


I'm using JFreeChart to create line charts that are exported as images and embedded into automatically generated documents. For instance one simple line chart would look like this:

The code I'm using to display the values would be:

LineAndShapeRenderer renderer = new LineAndShapeRenderer(true, false);
chart.getCategoryPlot().setRenderer(renderer);
renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", NumberFormat.getNumberInstance()));
renderer.setBaseItemLabelsVisible(true);

I'd also like to add error bars to display the standard deviation of each point, this can be done by using a StatisticalLineAndShapeRenderer (and of course adding the error values to the data set), so that the chode above now becomes this:

StatisticalLineAndShapeRenderer renderer = new StatisticalLineAndShapeRenderer(true, false);
chart.getCategoryPlot().setRenderer(renderer);
renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", NumberFormat.getNumberInstance()));
renderer.setBaseItemLabelsVisible(true);

With this code the chart is generated with the error bars, but the labels have disappeared. As it can be seen in this image:

I've tried to find an online example featuring both error bars and labels but I've failed to do so. Why are the labels disappearing when using the Statustical Renderer, is there any way around this?

EDIT: Added minimal and self contained example.

DefaultStatisticalCategoryDataset dataset = new DefaultStatisticalCategoryDataset();
dataset.add(1, 0.1, "serie", "A");
dataset.add(2, 0.4, "serie", "B");
dataset.add(2, 0.2, "serie", "C");

JFreeChart chart = ChartFactory.createLineChart("Chart", null, null, dataset, PlotOrientation.VERTICAL, false, true, true);
LineAndShapeRenderer renderer = new LineAndShapeRenderer(true, false);
chart.getCategoryPlot().setRenderer(renderer);
renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", NumberFormat.getNumberInstance()));
renderer.setBaseItemLabelsVisible(true);

JFreeChart chartErrorBars = ChartFactory.createLineChart("ErrorBars", null, null, dataset, PlotOrientation.VERTICAL, false, true, true);
StatisticalLineAndShapeRenderer statisticalRenderer = new StatisticalLineAndShapeRenderer(true, false);
chartErrorBars.getCategoryPlot().setRenderer(statisticalRenderer);
statisticalRenderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", NumberFormat.getNumberInstance()));
statisticalRenderer.setBaseItemLabelsVisible(true);

int width = 1500;
int height = 400;

try {
    FileOutputStream fos = new FileOutputStream(new File("chart.png"));
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ChartUtilities.writeChartAsPNG(baos, chart, width, height);
    baos.writeTo(fos);
    baos.close();
    fos.close();

    fos = new FileOutputStream(new File("chartErrorBars.png"));
    baos = new ByteArrayOutputStream();
    ChartUtilities.writeChartAsPNG(baos, chartErrorBars, width, height);
    baos.writeTo(fos);
    baos.close();
    fos.close();

} catch (IOException e) {
    e.printStackTrace();
}

And the two images generated by that code.


回答1:


StatisticalLineAndShapeRenderer displays labels when the parent LineAndShapeRenderer method getItemShapeVisible() returns true. In the example below, I've eschewed the chart factory and used the explicit StatisticalLineAndShapeRenderer constructor that enables both shapes and lines.

StatisticalLineAndShapeRenderer renderer
        = new StatisticalLineAndShapeRenderer(true, true);

Is there any specific reason to avoid the ChartFactory?

While repurposing the ChartFactory is expedient, it's reminiscent of ordering chicken on toast, hold the chicken, to get toast. More critically, the discarded LineAndShapeRenderer takes with it the requested tooltip and URL generators, perhaps puzzling a future maintainer.

Any way to keep the shapes disabled?

As you suggest, an empty Shape is effective, e.g.

renderer.setSeriesShape(0, new Rectangle2D.Double(0, 0, 0, 0));

import java.awt.Dimension;
import java.awt.EventQueue;
import java.text.NumberFormat;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.StatisticalLineAndShapeRenderer;
import org.jfree.data.statistics.DefaultStatisticalCategoryDataset;

/**
 * @see https://stackoverflow.com/a/38080778/230513
 */
public class Test {

    private void display() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultStatisticalCategoryDataset dataset
            = new DefaultStatisticalCategoryDataset();
        dataset.add(1, 0.1, "series", "A");
        dataset.add(2, 0.4, "series", "B");
        dataset.add(2, 0.2, "series", "C");

        CategoryAxis domain = new CategoryAxis();
        ValueAxis range = new NumberAxis();
        StatisticalLineAndShapeRenderer renderer
            = new StatisticalLineAndShapeRenderer(true, true);
        CategoryPlot plot = new CategoryPlot(dataset, domain, range, renderer);
        JFreeChart chart = new JFreeChart(
            "ErrorBars", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
        renderer.setBaseItemLabelGenerator(
            new StandardCategoryItemLabelGenerator("{2}",
                NumberFormat.getNumberInstance()));
        renderer.setBaseItemLabelsVisible(true);
        renderer.setSeriesShape(0, new Rectangle2D.Double(0, 0, 0, 0));
        new StandardChartTheme("JFree").apply(chart);
        f.add(new ChartPanel(chart) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(600, 300);
            }
        });

        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Test()::display);
    }
}


来源:https://stackoverflow.com/questions/38056237/how-to-add-label-values-and-error-bars-to-a-jfreechart-line-chart

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!