【问题标题】:JFreeChart scaling of Boxplots with several Categories具有多个类别的箱线图的 JFreeChart 缩放
【发布时间】:2023-04-03 21:57:01
【问题描述】:

我目前正在开发一个基于 java 的项目,使用 JFreeChart 来显示箱线图。

我的问题是如何显示包含大约 20 个类别和 5 个以上系列的 CategoryDataset 箱线图的图表。

目前,如果未设置 ChartPanel 的首选大小,则图例、标签和注释是可读的,但箱线图太小。或者设置 ChartPanel 的大小,使箱线图具有可接受的大小,但随后图例、标签和注释被水平拉伸。

我的问题是,如何在不缩放图表的图例、轴标签和注释的情况下正确缩放箱线图?是否可以在不缩放图表的所有元素的情况下缩放绘图?

代码示例

import java.awt.Color;
import java.awt.Dimension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.JFrame;
import javax.swing.JScrollPane;

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.renderer.category.BoxAndWhiskerRenderer;
import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset;


public class StretchedBoxAndWhiskerExample{

DefaultBoxAndWhiskerCategoryDataset dataset;
JFreeChart chart;
ChartPanel chartPanel;
JFrame frame;
JScrollPane scrollPane;

public StretchedBoxAndWhiskerExample() {
    createCategoryBoxplot();

    frame = new JFrame();
    scrollPane = new JScrollPane(chartPanel);
    scrollPane.setPreferredSize(new Dimension(800,700));
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    frame.add(scrollPane);
    frame.pack();
    frame.setVisible(true);
}

private void createCategoryBoxplot(){   
    dataset = createCategoryDataset();
    CategoryAxis xAxis = new CategoryAxis("");
    NumberAxis yAxis = new NumberAxis("Score");

    BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();
    CategoryPlot plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
    createJFreeChart(plot,"Test");

    // Design
    renderer.setFillBox(false);
    renderer.setMeanVisible(false);

    chart.setBackgroundPaint(Color.white); 
    plot.setBackgroundPaint(Color.lightGray); 
    plot.setDomainGridlinePaint(Color.white); 
    plot.setDomainGridlinesVisible(true); 
    plot.setRangeGridlinePaint(Color.white);
    plot.getRangeAxis().setRange(-10.5, 10.5);


    chartPanel = new ChartPanel(chart);
    chartPanel.setPreferredSize(new Dimension(3250,600));
}

private DefaultBoxAndWhiskerCategoryDataset createCategoryDataset() {

    dataset = new DefaultBoxAndWhiskerCategoryDataset();
    ArrayList<Double> values = createSampleData();
    ArrayList<String> categories = createSampleCategories();
    for (int i=0;i<=5;i++){
        for (String category : categories){
            dataset.add(values,i,category);
        }
    }
    return dataset;
}


private ArrayList<String> createSampleCategories() {
    ArrayList<String> tmp = new ArrayList<String>();
    for (int i=0;i<=20;i++){
        tmp.add("Category"+i);
    }
    return tmp;
}

private ArrayList<Double> createSampleData() {
    ArrayList<Double> tmp = new ArrayList<Double>();
    for (int i=0;i<10;i++){
        tmp.add(5.0);
        tmp.add(7.0);
        tmp.add(2.0);
        tmp.add(4.0);
    }
    return tmp;
}

private void createJFreeChart(CategoryPlot plot, String title){
    chart = new JFreeChart(title, plot);
}

public static void main(String[] args) throws IOException { 
    StretchedBoxAndWhiskerExample demo = new StretchedBoxAndWhiskerExample();

}
}

【问题讨论】:

    标签: java charts scaling jfreechart boxplot


    【解决方案1】:

    设置包含ChartPanel的首选大小,而不是图表,如herehere所示。

    附录:我认为您无法将图表添加到滚动窗格中。相反,创建一个类似于SlidingCategoryDataset 的类来实现BoxAndWhiskerCategoryDataset。向控制第一个显示索引的框架添加滚动条。

    附录:一种不那么雄心勃勃的方法是简单地使用一些合适的控件对数据集的一部分进行分页,如下例所示。

    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import javax.swing.AbstractAction;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    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.renderer.category.BoxAndWhiskerRenderer;
    import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset;
    
    /** @see https://stackoverflow.com/questions/6844759 */
    public class BoxAndWhiskerDemo {
    
        private static final int COLS = 20;
        private static final int VISIBLE = 4;
        private static final int ROWS = 5;
        private static final int VALUES = 10;
        private static final Random rnd = new Random();
        private List<String> columns;
        private List<List<List<Double>>> data;
        private DefaultBoxAndWhiskerCategoryDataset dataset;
        private CategoryPlot plot;
        private ChartPanel chartPanel;
        private JPanel controlPanel;
        private int start = 0;
    
        public BoxAndWhiskerDemo() {
            createData();
            createDataset(start);
            createChartPanel();
            createControlPanel();
        }
    
        private void createData() {
            columns = new ArrayList<String>(COLS);
            data = new ArrayList<List<List<Double>>>();
            for (int i = 0; i < COLS; i++) {
                String name = "Category" + String.valueOf(i + 1);
                columns.add(name);
                List<List<Double>> list = new ArrayList<List<Double>>();
                for (int j = 0; j < ROWS; j++) {
                    list.add(createValues());
                }
                data.add(list);
            }
        }
    
        private List<Double> createValues() {
            List<Double> list = new ArrayList<Double>();
            for (int i = 0; i < VALUES; i++) {
                list.add(rnd.nextGaussian());
            }
            return list;
        }
    
        private void createDataset(int start) {
            dataset = new DefaultBoxAndWhiskerCategoryDataset();
            for (int i = start; i < start + VISIBLE; i++) {
                List<List<Double>> list = data.get(i);
                int row = 0;
                for (List<Double> values : list) {
                    String category = columns.get(i);
                    dataset.add(values, "s" + row++, category);
                }
            }
        }
    
        private void createChartPanel() {
            CategoryAxis xAxis = new CategoryAxis("Category");
            NumberAxis yAxis = new NumberAxis("Value");
            BoxAndWhiskerRenderer renderer = new BoxAndWhiskerRenderer();
            plot = new CategoryPlot(dataset, xAxis, yAxis, renderer);
            JFreeChart chart = new JFreeChart("BoxAndWhiskerDemo", plot);
            chartPanel = new ChartPanel(chart);
        }
    
        private void createControlPanel() {
            controlPanel = new JPanel();
            controlPanel.add(new JButton(new AbstractAction("\u22b2Prev") {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    start -= VISIBLE;
                    if (start < 0) {
                        start = 0;
                        return;
                    }
                    createDataset(start);
                    plot.setDataset(dataset);
                }
            }));
            controlPanel.add(new JButton(new AbstractAction("Next\u22b3") {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    start += VISIBLE;
                    if (start > COLS - VISIBLE) {
                        start = COLS - VISIBLE;
                        return;
                    }
                    createDataset(start);
                    plot.setDataset(dataset);
                }
            }));
        }
    
        public ChartPanel getChartPanel() {
            return chartPanel;
        }
    
        public JPanel getControlPanel() {
            return controlPanel;
        }
    
        public static void main(String[] args) throws IOException {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    BoxAndWhiskerDemo demo = new BoxAndWhiskerDemo();
                    frame.add(demo.getChartPanel(), BorderLayout.CENTER);
                    frame.add(demo.getControlPanel(), BorderLayout.SOUTH);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    }
    

    【讨论】:

    • Sorry "Currently if the preferred size of the Chart ..." 错误,应该是"Currently if the preferred size of the ChartPanel ..."
    • 问题是完整的图表,包括它的图例、标签等,被缩放到 ChartPanel 的大小。如果我将图表导出到 PNG,则只有包含箱形图的“内部”部分会被缩放,并且轴、图例等会很好地显示
    • 上面引用的两个例子都没有显示你描述的效果;请发布重现问题的sscce
    • 这个解决方案对我的项目来说应该足够了。非常感谢!
    猜你喜欢
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    • 2018-07-20
    相关资源
    最近更新 更多