FastScatterPlot 不显示数据

问题描述 投票:0回答:1

我正在尝试构建一个图表应用程序作为大学项目,使用 JFreeChart 构建图表,使用 Swing 构建 UI。经过一些调试后,文件解析器正在正确读取数据,正在构建图表并向用户显示包含图表的面板。但是图表不包含数据。这是构建散点图的代码:

import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.FastScatterPlot;


public class ScatterPlot extends Chart{

    

    public ScatterPlot(String title, float[][] data) {
            
        this.data = data;
        //CSVParser.printArrayToConsole(this.data[1]);
        NumberAxis domainAxis = new NumberAxis("X");
        domainAxis.setAutoRangeIncludesZero(false);
        NumberAxis rangeAxis = new NumberAxis("Y");
        rangeAxis.setAutoRangeIncludesZero(true);
        FastScatterPlot plot = new FastScatterPlot(this.data, domainAxis, rangeAxis);
        JFreeChart chart = new JFreeChart("Fast Scatter Plot", plot);
        ChartUtils.applyCurrentTheme(chart);

        panel = new ChartPanel(chart);
        panel.setPreferredSize(new java.awt.Dimension(500, 270));
        panel.setMinimumDrawHeight(10);
        panel.setMaximumDrawHeight(2000);
        panel.setMinimumDrawWidth(20);
        panel.setMaximumDrawWidth(2000);

    }
}

这是继承自的 Chart 类:

import org.jfree.chart.ChartPanel;
import javax.swing.JPanel;
import org.jfree.chart.plot.FastScatterPlot;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.JFreeChart;


public class Chart {
    
    float[][] data;
    ChartPanel panel;
    
    public Chart(){
        initChartPanel();
    }
    
    private void initChartPanel(){
        float[][] tempData = {{0}, {0}};
        FastScatterPlot plot = new FastScatterPlot(tempData, new NumberAxis(""), new NumberAxis(""));
        JFreeChart chart = new JFreeChart("If you're seeing this, something went wrong.", plot);
        panel = new ChartPanel(chart);
    }
    
}

这是我用于此输出的数据集(从 CSV 文件读取):

0,1,2,3,4,5,6,7,8,9,10,11
4.2,4,3.7,3.4,3.2,2.9,2.6,2.4,2.1,1.8,1.5,1.2

这是运行此代码的输出:

Scatter plot with no data

我已经尝试过:

  • 手动设置范围
  • 禁用设置自动范围
  • 添加缩放功能以查看点是否太小而看不到(不是)
  • 使用其他人编写的 FastScatterPlot 类的扩展调整点的大小

作为旁注,ScatterPlot 类是由我的一位队友编写的,我非常确定他不是自己编写的,而是从教程中复制并粘贴的。我们同意由我构建 UI,由他负责图表构建方面的工作。我做了一些修改以适应我所拥有的,但这就是说我对 JFreeChart 不太熟悉,我相信他也不是,所以我不能向他寻求帮助。

如有任何帮助,我们将不胜感激。


编辑:ChartPanel 已添加到该类中的 MainFrame,这里是能够运行获取该输出的路径所需的所有类。

package javacharts;
import java.awt.*;

public class JavaCharts {
    
    static GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();

    public static void main(String[] args) { 
        MainFrame mainFrame = new MainFrame();
        device.setFullScreenWindow(mainFrame);
    }
    
}
package javacharts;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.atomic.*;

public class MainFrame extends JFrame{
    JPanel mainPanel;
    JLabel title, choiceLabel;
    JButton[] buttons;
    JLabel[] buttonLabels;
    GridBagConstraints constraints;
    //These values need ot be atomic or []
    //because the compiler complains about it being referenced from a lambda as an int
    AtomicInteger graphType; 
    AtomicInteger inputType;
    
    public MainFrame(){
        graphType = new AtomicInteger();
        inputType = new AtomicInteger();
        this.setLayout(new BorderLayout());
        mainPanel = new JPanel();
        mainPanel.setLayout(new GridBagLayout());
        constraints = new GridBagConstraints();
        
        //declare big labels
        title = new JLabel("Welcome to Java Charts", SwingConstants.CENTER);
        title.setFont(title.getFont().deriveFont(48.0f));
        
        choiceLabel = new JLabel("", SwingConstants.CENTER);
        choiceLabel.setFont(choiceLabel.getFont().deriveFont(30.0f));
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.gridx = 0;
        constraints.gridy = 0;
        constraints.gridwidth = 3;
        mainPanel.add(choiceLabel, constraints);
        
        //declare buttons, used for both graph type and input type
        buttons = new JButton[3];
        buttons[0] = new JButton();
        buttons[1] = new JButton();
        buttons[2] = new JButton();
        
        //declare button labels
        buttonLabels = new JLabel[3];
        buttonLabels[0] = new JLabel("Scatter Plot", SwingConstants.CENTER);
        buttonLabels[0].setFont(buttonLabels[0].getFont().deriveFont(18.0f));
        buttonLabels[1] = new JLabel("Box Plot", SwingConstants.CENTER);
        buttonLabels[1].setFont(buttonLabels[1].getFont().deriveFont(18.0f));
        buttonLabels[2] = new JLabel("Ogive", SwingConstants.CENTER);
        buttonLabels[2].setFont(buttonLabels[2].getFont().deriveFont(18.0f));
        
        
        //add buttons to mainPanel
        constraints.gridy = 1;
        constraints.gridwidth = 1;
        constraints.insets = new Insets(15, 10, 0, 10);
        mainPanel.add(buttons[0], constraints);
        
        constraints.gridx = 1;
        mainPanel.add(buttons[1], constraints);
        
        constraints.gridx = 2;
        mainPanel.add(buttons[2], constraints);
        
        //add button labels to main panel
        constraints.gridy = 2;
        constraints.gridx = 0;
        constraints.insets.top = 0;
        mainPanel.add(buttonLabels[0], constraints);
        
        constraints.gridx = 1;
        mainPanel.add(buttonLabels[1], constraints);
        
        constraints.gridx = 2;
        mainPanel.add(buttonLabels[2], constraints);
        
        this.add(title, BorderLayout.NORTH);
        this.add(mainPanel, BorderLayout.CENTER);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setUndecorated(true);
        this.pack();
        this.setVisible(true);
        buildChartSelectionMenu();
    }
    
    public void buildChartSelectionMenu(){
        choiceLabel.setText("Which type of graph would you like to build?");
        
        //change icons of buttons
        //IMPORTANT: change images to the actual outputted graphs at the end
        ImageIcon icon1 = new ImageIcon(getClass().getResource("..\\images\\scatter_plot.jpeg"));
        buttons[0].setIcon(icon1);
        ImageIcon icon2 = new ImageIcon(getClass().getResource("..\\images\\box_plot.jpeg"));
        buttons[1].setIcon(icon2);
        ImageIcon icon3 = new ImageIcon(getClass().getResource("..\\images\\ogive.jpeg"));
        buttons[2].setIcon(icon3);
        
        //add action listeners to buttons
        for(AtomicInteger i = new AtomicInteger(0); i.get() < buttons.length; i.incrementAndGet()){
            int chartT = i.get();
            buttons[i.get()].addActionListener((ActionEvent e) -> {
                graphType.set(chartT);
                buildInputSelectionMenu();
            });
        }
        
        //change button labels
        buttonLabels[0].setText("Scatter Plot");
        buttonLabels[1].setText("Box Plot");
        buttonLabels[2].setText("Ogive");
    }
    
    public void buildInputSelectionMenu(){
        //remove all action listeners from buttons
        for(int i = 0; i < buttons.length; ++i){
            buttons[i].removeActionListener(buttons[i].getActionListeners()[0]);
        }
        
        //change icons of buttons
        ImageIcon icon1 = new ImageIcon(getClass().getResource("../images/excel.jpeg"));
        buttons[0].setIcon(icon1);
        ImageIcon icon2 = new ImageIcon(getClass().getResource("../images/csv.jpeg"));
        buttons[1].setIcon(icon2);
        ImageIcon icon3 = new ImageIcon(getClass().getResource("../images/mouse_cursor.jpeg"));
        buttons[2].setIcon(icon3);
        
        //change labels
        choiceLabel.setText("How would you like to build this graph?");
        buttonLabels[0].setText("Excel file");
        buttonLabels[1].setText("CSV file");
        buttonLabels[2].setText("Input data manually");
        
        //add new action listeners to buttons
        for(AtomicInteger i = new AtomicInteger(0); i.get() < buttons.length; i.incrementAndGet()){
            int inputT = i.get();
            buttons[i.get()].addActionListener((ActionEvent e) -> {
                inputType.set(inputT);
                try{
                    ChartBuilder chartBuilder = new ChartBuilder(graphType.get(), inputType.get());
                    //System.out.println("Hello from mainfram");
                    getContentPane().removeAll();
                    super.add(chartBuilder.chart.panel);
                } catch(Exception ex){
                    buildChartSelectionMenu();
                    ex.printStackTrace();
                }
            });
        }
    }
}
package javacharts;
import java.io.*;
import javax.swing.JOptionPane;

public class ChartBuilder {
    int chartType;
    int inputType;
    File fileIn;
    InputHandler inputHandler;
    Chart chart;
    //JFreeChart chart;
    
    public ChartBuilder(int chartType, int inputType)throws FileNotFoundException{
        //System.out.println(inputType);
        
        float[][] data = new float[2][];
        
        switch(inputType){
            case 0:
                break;
            case 1:
                inputHandler = new CSVParser();
                if(inputHandler.file == null){
                    JOptionPane.showMessageDialog(null, "File is null",
                    "Error in ChartBuilder", 
                    JOptionPane.ERROR_MESSAGE);
                    break;
                }
                
                data = inputHandler.parseData();
                if(data == null){
                    JOptionPane.showMessageDialog(null, "CSVParser.parseData() failed to return valid array",
                    "Error in CSVParser", 
                    JOptionPane.ERROR_MESSAGE);
                    break;
                }
                if(data[0] == null){
                    JOptionPane.showMessageDialog(null, "CSVParser.convertToFloarArray() failed to return valid array",
                    "Error in CSVParser", 
                    JOptionPane.ERROR_MESSAGE);
                    break;
                }
                break;
            case 2:
                break;
        }
        
        switch(chartType){
            case 0:
                chart = new ScatterPlot("title", data);
                break;
            case 1:
                break;
            case 2:
                break;
        }
    }
}
package javacharts;
import java.io.*;
import javax.swing.JOptionPane;

public class CSVParser extends InputHandler{
    
    final public String EXTENSION = ".csv";
    
    public CSVParser() throws FileNotFoundException{
        try{
            JOptionPane.showMessageDialog(null, "Make sure your CSV file contains only numerical data (no titles/labels)",
                "Attention", 
                JOptionPane.WARNING_MESSAGE);
            file = openFile();
        } catch(Exception e){
            JOptionPane.showMessageDialog(null, "Failed to open file",
                "Error in CSVParser", 
                JOptionPane.ERROR_MESSAGE);
            file = null;
        }
        
        boolean validFile = false;
        try{
            validFile = isValidFile(EXTENSION);
        } catch(Exception e){
            validFile = false;
        }
        
        if(!validFile){
            JOptionPane.showMessageDialog(null, "Please select a CSV file",
                "Invalid file type", 
                JOptionPane.ERROR_MESSAGE);
            file = null;
        }
    }
    
    @Override
    public float[][] parseData() throws FileNotFoundException{
        float[][] data = new float[2][];
        BufferedReader fileReader = new BufferedReader(new FileReader(file));
        try{
            final String DELIMITER = ",";
            
            String line;
            int i = 0;
            while((line = fileReader.readLine()) != null){
                String[] lineData = line.split(DELIMITER);
                //printArrayToConsole(lineData);
                data[i] = convertToFloatArray(lineData);
                //printArrayToConsole(data[i]);
                ++i;
            }
        } catch(Exception e){
            JOptionPane.showMessageDialog(null, "Failed to read file",
                    "Error in CSVParser", 
                    JOptionPane.ERROR_MESSAGE);
            System.out.println(e);
            return null;
        }
        
        return data;
    }
    
    public float[] convertToFloatArray(String[] arrIn){
        float[] arrOut = new float[arrIn.length];
        
        try{
            for(int i = 0; i < arrIn.length; ++i){
                arrOut[i] = Float.parseFloat(arrIn[i]);
            }
        } catch(Exception e){
            JOptionPane.showMessageDialog(null, "Failed to convert all values to floats",
                    "Error in CSVParser", 
                    JOptionPane.ERROR_MESSAGE);
            System.out.println(e);
            return null;
        }
        return arrOut;
    }
    
    public void printArrayToConsole(String[] arr){
        System.out.println("String array");
        for(int i = 0; i < arr.length; ++i){
            System.out.println(arr[i]);
        }
    }
    
    public static void printArrayToConsole(float[] arr){
        System.out.println("Float Array");
        for(int i = 0; i < arr.length; ++i){
            System.out.println(arr[i]);
        }
    }
}
package javacharts;
import java.io.*;
import javax.swing.JFileChooser;
import javax.swing.JFrame;

public abstract class InputHandler {
    float[][] data = new float[2][];
    File file;
    String filePath;
    
    
    public File openFile(){
        JFrame frame = new JFrame();
        JFileChooser chooser = new JFileChooser();
        int retVal = chooser.showOpenDialog(frame);
        if(retVal == JFileChooser.APPROVE_OPTION){
            this.filePath = chooser.getSelectedFile().getAbsolutePath();
            return chooser.getSelectedFile();
        } else{
            return null;
        }
    }
    
    public boolean isValidFile(String extension){
        return filePath.endsWith(extension) ? true : false;
    }
    
    abstract public float[][] parseData() throws FileNotFoundException;
}

显然我还有一些工作要做,因为我还没有构建其他 2 个 InputHandler 或实现其他 2 种图表类型,但到目前为止我所做的只是通过应该从 CSV 文件创建散点图的路径.

我希望代码不要太多,但这就是重现我的输出所需要的。


编辑 2:我通过更改整个 ScatterPlot 类以使用 XYDataset 和 ChartFactory.createScatterPlot() 方法而不是使用 FastScatterPlot 来使其工作。这就是该类现在的样子:

import org.jfree.chart.JFreeChart;
import org.jfree.chart.ChartFactory;
import org.jfree.data.xy.XYDataset;  
import org.jfree.data.xy.XYSeries;  
import org.jfree.data.xy.XYSeriesCollection;  



public class ScatterPlot extends Chart{

    

    public ScatterPlot(String[] labels, float[][] data) {
            
            super(labels, data);
            XYDataset dataset = createDataset();

            JFreeChart chart = ChartFactory.createScatterPlot(
                    labels[0], labels[1], labels[2],
                    dataset
            );

            setChartPanel(chart);
    }
        
        private XYDataset createDataset() {  
            XYSeriesCollection dataset = new XYSeriesCollection();  
            
            XYSeries series = new XYSeries("Series 1");
            
            for(int i = 0; i < data[0].length; ++i){
                series.add(data[0][i], data[1][i]);
            }
            
            dataset.addSeries(series);
            return dataset;
        }
}

java swing charts scatter-plot jfreechart
1个回答
0
投票

仅关注图表的显示,下面的示例使用setData()提供的

FastScatterPlot
方法
原位
更新图表。按 Update 按钮会调用
setData()
,并且收听图表会自行更新作为响应。您的
actionPerformed()
可以请求文件、解析其数据并根据需要更新绘图。


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
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.NumberAxis;
import org.jfree.chart.plot.FastScatterPlot;

/**
 * @see http://stackoverflow.com/questions/8531844
 */
public class FastScatterPlotDemo {

    private static final int N = 10 * 1_000;
    private static final Random rnd = new Random();

    private void display() {
        var f = new JFrame("Fast Scatter Plot");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        var domainAxis = new NumberAxis("X");
        domainAxis.setAutoRangeIncludesZero(false);
        NumberAxis rangeAxis = new NumberAxis("Y");
        var plot = new FastScatterPlot(createData(), domainAxis, rangeAxis);
        var chart = new JFreeChart(f.getTitle(), plot);
        var panel = new ChartPanel(chart, true) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(16 * 32, 10 * 32);
            }
        };
        f.add(panel);
        var buttonPanel = new JPanel();
        buttonPanel.add(new JButton(new AbstractAction("Update") {
            @Override
            public void actionPerformed(ActionEvent e) {
                plot.setData(createData());
            }
        }));
        f.add(buttonPanel, BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private float[][] createData() {
        float[][] data = new float[2][N];
        for (int i = 0; i < data[0].length; i++) {
            data[0][i] = (float) i;
            data[1][i] = (float) rnd.nextGaussian() * N;
        }
        return data;
    }

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

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.