Search code examples
javacsvjfreechartopencsv

Adding values to JFreeChart XYDataset from csv file using opencsv


I am trying to read in a .csv file but I am stuck on how once I've read each line on the csv file and how to add it to the XYDataset.

My algorithm is as follows: read in .csv file -> read each line -> add to dataset -> create chart -> output as frame

data.csv has 4 columns: Time, X, Y, Z

How do I add each point (time,x), (time,y), (time,z) to the dataset?

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

import com.opencsv.CSVReader;

public class Test extends ApplicationFrame
{
    XYDataset dataset;
    JFreeChart chart;
    final ChartPanel chartPanel;
    final int chartWidth = 560;
    final int chartHeight = 367;
    CSVReader reader;
    String[] readNextLine;
    XYSeries series;

   public Test(String applicationTitle) throws IOException 
   {
      super(applicationTitle); 
      dataset = createDataset(); 
      chart = createChart(dataset);   
      chartPanel = new ChartPanel(chart);  
      chartPanel.setPreferredSize(new java.awt.Dimension(chartHeight, chartWidth));  
   }

   public XYDataset createDataset() throws NumberFormatException, IOException
   {
       dataset = new XYSeriesCollection(); 
       try
       {
           reader = new CSVReader(new FileReader("data.csv")); 
           while((readNextLine = reader.readNext()) != null) 
           {
              if (readNextLine != null)
              {
                  //add values to dataset
              }
           }
     } 
     catch (FileNotFoundException e)
     {
         System.out.println("File not found!");
     }
     return dataset;
   }

 public JFreeChart createChart(XYDataset dataset) throws      NumberFormatException, IOException
 {
    chart = ChartFactory.createXYLineChart(
    "Acceleration vs Time",     //chart title 
    "Time",                     //domain axis label
    "Acceleration",             //range axis label
    createDataset(),            //data
    PlotOrientation.VERTICAL,   //the plot orientation
    true,                       //legend
    true,                       //tooltips
    false);                     //urls

return chart;
}

public static void main(String[] args) throws IOException
{
    final Test demo = new Test("Test XY Line chart");
    demo.pack();
    RefineryUtilities.centerFrameOnScreen(demo);
    demo.setVisible(true);
}
}

The first 10 lines of my dataset look like this:

time    x   y   z
0.003   -0.13   0.83    0.6
0.009   -0.12   0.83    0.61
0.012   -0.12   0.82    0.6
0.018   -0.13   0.81    0.61
0.021   -0.13   0.8 0.61
0.025   -0.12   0.8 0.61
0.033   -0.12   0.79    0.6
0.034   -0.11   0.79    0.6
0.039   -0.11   0.79    0.58
0.044   -0.11   0.77    0.57

Solution

  • Where your comment is - you need to first go through the elements of readNextLine where each element of the String[] will contain the value from your file for a given row (assuming your file is correctly formatted as you said). So - you need to turn these into variables. You haven't specified what format these are in, or what data type Time,X, Y and Z are.

    Given that you're looking at an XY chart and your axes are labelled Time and acceleration - I'm going to guess that they're all Floating Point numbers, with Time in decimal seconds and the other variables as accelerations in the various axes. NOTE - if this assumption is wrong - you might need to use a different converter such as Integer.valueOf(), but the principle is the same.

    before your while loop, set up the series that you want to add to. You'll add to them row by row within the while loop

    final XYSeries seriesX = new XYSeries("X");
    final XYSeries seriesY = new XYSeries("Y");
    final XYSeries seriesZ = new XYSeries("Z");
    

    within the while loop where your comment is

    //add values to dataset
    double Time = Double.valueOf(readNextLine[0]);
    double X = Double.valueOf(readNextLine[1]);
    double Y = Double.valueOf(readNextLine[2]);    
    double Z = Double.valueOf(readNextLine[3]);
    seriesX.add(Time, X);
    seriesY.add(Time, Y);
    seriesZ.add(Time, Z);
    

    and after the while loop add the 3 series to the collection before you return it:

    dataset.addSeries(seriesX);
    dataset.addSeries(seriesY);
    dataset.addSeries(seriesZ);
    

    Lastly - two comments

    1. Your logic is a little weird around dataset creation. In your constructor, you create the dataset and pass it to createChart(). This is quite standard. But you then call createDataset() inline within the call to ChartFactory.createXYLineChart(, thus rendering the first creation of data pointless and doing it all again. It will work, but is wasteful and might be masking something else that you're intending the code to do.

    2. The if check in createDataset() is redundant - you're already in a while loop based on a condition which means it will always be true.

      if (readNextLine != null)
      {
      

    EDIT - added full working version to clear confusion in several comments

    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartPanel;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.data.xy.XYDataset;
    import org.jfree.data.xy.XYSeries;
    import org.jfree.data.xy.XYSeriesCollection;
    import org.jfree.ui.ApplicationFrame;
    import org.jfree.ui.RefineryUtilities;
    
    import au.com.bytecode.opencsv.CSVReader;
    
    public class Test extends ApplicationFrame {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        XYSeriesCollection dataset;
        JFreeChart chart;
        final ChartPanel chartPanel;
        final int chartWidth = 560;
        final int chartHeight = 367;
        CSVReader reader;
        String[] readNextLine;
        XYSeries series;
    
        public Test(String applicationTitle) throws IOException {
            super(applicationTitle);
            dataset = createDataset();
            chart = createChart(dataset);
            chartPanel = new ChartPanel(chart);
            chartPanel.setPreferredSize(new java.awt.Dimension(chartHeight,
                    chartWidth));
            this.add(chartPanel);
        }
    
        public XYSeriesCollection createDataset() throws NumberFormatException,
                IOException {
            dataset = new XYSeriesCollection();
            try {
                reader = new CSVReader(new FileReader("res\\data.csv"),'\t');
                // Read the header and chuck it away
                readNextLine = reader.readNext();
    
                // Set up series
                final XYSeries seriesX = new XYSeries("X");
                final XYSeries seriesY = new XYSeries("Y");
                final XYSeries seriesZ = new XYSeries("Z");
    
                while ((readNextLine = reader.readNext()) != null) {
                    // add values to dataset
                    double Time = Double.valueOf(readNextLine[0]);
                    double X = Double.valueOf(readNextLine[1]);
                    double Y = Double.valueOf(readNextLine[2]);
                    double Z = Double.valueOf(readNextLine[3]);
                    seriesX.add(Time, X);
                    seriesY.add(Time, Y);
                    seriesZ.add(Time, Z);
                }
    
                System.out.println(seriesX.getMaxX() + "; " + seriesX.getMaxY());
    
                dataset.addSeries(seriesX);
                dataset.addSeries(seriesY);
                dataset.addSeries(seriesZ);
            } catch (FileNotFoundException e) {
                System.out.println("File not found!");
            }
            return dataset;
        }
    
        public JFreeChart createChart(XYDataset dataset)
                throws NumberFormatException, IOException {
            chart = ChartFactory.createXYLineChart("Acceleration vs Time", // chart
                                                                            // title
                    "Time", // domain axis label
                    "Acceleration", // range axis label
                    dataset, // data
                    PlotOrientation.VERTICAL, // the plot orientation
                    true, // legend
                    true, // tooltips
                    false); // urls
    
            return chart;
        }
    
        public static void main(String[] args) throws IOException {
            System.out.println("In here, to create a Test");
            final Test demo = new Test("Test XY Line chart");
            System.out.println("Created, pakcking");
            demo.pack();
            RefineryUtilities.centerFrameOnScreen(demo);
            demo.setVisible(true);
        }
    }
    

    Output with OP supplied first 10 data points

    acceleration graph output of program