Using Multiple Renderers in JFreechart
Asked Answered
C

1

1

I have data that I'd like to represent as a box and whiskers graph, and have set up a category plot to do so. However, in addition, I'd like to add a line chart that shows an accumulation of the averages for each data point.

Right now my code is something like this

DefaultBoxAndWhiskerCategoryDataset dataSet = new DefaultBoxAndWhiskerCategoryDataset();
int i = 0;
for (List<Integer> categoryList : categoryLists) {
    dataSet.add(categoryList, i, "BoxAndWhiskers");
    i++;
}
BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();

double sum = 0;
i = 0;
DefaultCategoryDataset averageDataSet = new DefaultCategoryDataset();
for (double average : averages) {
    sum += average;
    averageDataSet.add(sum, i, "Average");
    i++;
}
LineAndShapeRenderer lineAndShapeRenderer = new LineAndShapeRenderer();


CategoryAxis xAxis = new CategoryAxis("Type");
NumberAxis yAxis = new NumberAxis("Value");
CategoryPlot plot = new CategoryPlot(dataSet, xAxis, yAxis, renderer);

plot.setDataset(1, averageDataSet);
plot.setRenderer(1, lineAndShapeRenderer);

JFreeChart chart = new JFreeChart(
    "Box-and-Whisker",
    new Font("SansSerif", Font.BOLD, 14),
    plot,
    true
);

BufferedImage outputImage = chart.createBufferedImage(800, 600);

ImageIO.write(outputImage, "png", new File("output.png"));

However, when I look at my output.png, I only see the box and whiskers render (no lineandshape graph).

Is there something else I need to do to use both renderers and datasets in my output image? Additionally, is there a better approach to getting a cumuluative line for the averages in my box and whiskers graph?

Common answered 5/7, 2016 at 13:46 Comment(6)
What happens when you plot averageDataSet by itself?Diella
after looking at the output again, it appears as the a vertical set of dots is appearing in the center of my graph. The two data sets will have the same key, so I guess i'm trying to figure out how to lay the points on top of the box and whiskers points properlyCommon
Try comparing the rowKey and columnKey in the two dataset add() invocations.Diella
The rows for both datasets were the same, but the column is different. If I want them to overlay correctly, do they both need to be the same ?Common
As I recall, each rowKey is a series and each columnKey is an element in the series, for example.Diella
I'm using two datasets and two renderers though, would that make a difference?Common
D
2

I'm trying to figure out how to lay the points on top of the box and whiskers points properly.

As shown here for CategoryDataset, each rowKey is a series and each columnKey is an element in the series. In the example below, the "Mean" row of catData includes an entry for each columnKey in boxData. Use setDatasetRenderingOrder() to specify DatasetRenderingOrder.

image

import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.Arrays;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DatasetRenderingOrder;
import org.jfree.chart.renderer.category.BoxAndWhiskerRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset;

/**
 * @see https://mcmap.net/q/1778762/-using-multiple-renderers-in-jfreechart
 */
public class Test {

    private void display() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        DefaultBoxAndWhiskerCategoryDataset boxData = new DefaultBoxAndWhiskerCategoryDataset();
        boxData.add(Arrays.asList(30, 36, 46, 55, 65, 76, 81, 80, 71, 59, 44, 34), "Planet", "Endor");
        boxData.add(Arrays.asList(22, 25, 34, 44, 54, 63, 69, 67, 59, 48, 38, 28), "Planet", "Hoth");
        BoxAndWhiskerRenderer boxRenderer = new BoxAndWhiskerRenderer();
        DefaultCategoryDataset catData = new DefaultCategoryDataset();
        catData.addValue(boxData.getMeanValue(0, 0), "Mean", boxData.getColumnKey(0));
        catData.addValue(boxData.getMeanValue(0, 1), "Mean", boxData.getColumnKey(1));
        LineAndShapeRenderer lineRenderer = new LineAndShapeRenderer();
        CategoryAxis xAxis = new CategoryAxis("Type");
        NumberAxis yAxis = new NumberAxis("Value");
        yAxis.setAutoRangeIncludesZero(false);
        CategoryPlot plot = new CategoryPlot(boxData, xAxis, yAxis, boxRenderer);
        plot.setDataset(1, catData);
        plot.setRenderer(1, lineRenderer);
        plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
        JFreeChart chart = new JFreeChart("Test", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
        f.add(new ChartPanel(chart){
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(320, 480);
            }
        });
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Test()::display);
    }
}
Diella answered 7/7, 2016 at 10:3 Comment(2)
Thanks! Having code helped me visualize what you were saying :)Common
If you're curious, my problem was that i had the row and column switched around in my line graph, as i assumed they would be the same. Thanks again!!Common

© 2022 - 2024 — McMap. All rights reserved.