package umontreal.iro.lecuyer.charts;

import   java.util.Formatter;
import   java.util.Locale;
import   java.util.StringTokenizer;
import   java.util.regex.Pattern;

import   java.io.Reader;
import   java.io.StringReader;
import   java.io.IOException;

import   org.jfree.data.xy.XYSeriesCollection;
import   org.jfree.data.category.CategoryDataset;
import   org.jfree.data.io.CSV;

/**
 * Provide tools to import and export data set tables
 * to and from Gnuplot, MATLAB and Mathematica compatible
 * formats, or customized format.
 * 
 */
public class PlotFormat {
   private PlotFormat() {}

   /**
    * Parses data according to the standard GNUPlot format and stores
    *   the extracted values in the returned table. All unrecognized characters
    *    and empty lines will be cut. Deleting comments inside the input
    *    String is recommended.
    * 
    * @param data String to parse.
    * 
    *    @return Table that represent data contained in data.
    *    @exception IllegalArgumentException if each line of the input String doesn't share the same number of values
    * 
    * 
    */
   public static double[][] fromGNUPlot (String data)  {
      int maxLineNumber = 16;
      int columnNumber = 0;
      int lineNumber = 0;
      double[][] retour = new double[1][1]; //initialisation temporaire

      Pattern p = Pattern.compile("\\n\\n*");
      String[] string = p.split(data); // A chaque String correspond une ligne

      for (int j = 0; j < string.length; j++) {
         if (string[j].charAt(0) != '#' && string[j].length() != 0) {
            //On ne traite pas les lignes de commentaires ni les lignes

            p = Pattern.compile("\\s\\s*");
            String[] result = p.split(string[j]);
            double[] line = new double[result.length];

            int k = 0; // Compte le nombre de valeurs sur la ligne courante
            for (int i = 0; i < result.length; i++) {
               try {
                  line[k] = Double.valueOf(result[i]);   // les chaines de caracteres qui ne sont pas des nombres sont ignorees
                  k++;
               } catch (NumberFormatException nfe) {}
            }

            if (k != 0) { // il y a des valeurs sur la ligne
               //La premiere ligne determine combien de colonnes aura notre tableau de retour
               if (lineNumber == 0) {
                  columnNumber = k;
                  retour = new double[columnNumber][maxLineNumber]; // Allocation du tableau de retour
               } else if ( columnNumber != k ) // Toutes les lignes de la String n'ont pas le meme nombre de valeurs
                  throw new IllegalArgumentException("Each line must have the same number of values");

               if (lineNumber >= maxLineNumber) { // Cas ou notre tableau initial n'est plus assez grand
                  maxLineNumber = maxLineNumber * 2;
                  double[][] temp = new double[columnNumber][maxLineNumber];
                  for (int i = 0; i < columnNumber; i++)
                     for (int l = 0; l < retour[0].length; l++)
                        temp[i][l] = retour[i][l];
                  retour = temp;
               }

               for (int i = 0; i < columnNumber; i++)
                  retour[i][lineNumber] = line[i];
               lineNumber++;
            }
         }
      }
      // Cree un tableau aux dimensions exactes
      double[][] temp;
      if (columnNumber == 0)
         temp = null;
      else
         temp = new double[columnNumber][lineNumber];
      for (int i = 0; i < columnNumber; i++)
         for (int l = 0; l < lineNumber; l++)
            temp[i][l] = retour[i][l];
      retour = null;
      return temp;
   }


   /**
    * Parses data according to the standard CSV format
    *    and stores the extracted values in the returned table.
    * 
    * @param data String to parse.
    * 
    *    @return Table that represent data contained in data.
    *    @exception IllegalArgumentException if each line of the input String doesn't share the same number of values
    * 
    * 
    */
   public static double[][] fromCSV (String data)  {
      int maxLineNumber = 16;
      int columnNumber = 0;
      int lineNumber = 0;
      double[][] retour = new double[1][1]; //initialisation temporaire

      Pattern p = Pattern.compile("\\n\\n*");
      String[] string = p.split(data); // A chaque String correspond une ligne

      for (int j = 0; j < string.length; j++) {
         if (string[j].length() != 0) {
            //On ne traite pas les lignes vides

            p = Pattern.compile(",,*");
            String[] result = p.split(string[j]);
            double[] line = new double[result.length];

            int k = 0; // Compte le nombre de valeurs sur la ligne courante
            for (int i = 0; i < result.length; i++) {
               try {
                  line[k] = Double.valueOf(result[i]);   // les chaines de caracteres qui ne sont pas des nombres sont ignorees
                  k++;
               } catch (NumberFormatException nfe) {}
            }

            if (k != 0) { // il y a des valeurs sur la ligne
               //La premiere ligne determine combien de colonnes aura notre tableau de retour
               if (lineNumber == 0) {
                  columnNumber = k;
                  retour = new double[columnNumber][maxLineNumber]; // Allocation du tableau de retour
               } else if ( columnNumber != k ) // Toutes les lignes de la String n'ont pas le meme nombre de valeurs
                  throw new IllegalArgumentException("Each line must have the same number of values");

               if (lineNumber >= maxLineNumber) { // Cas ou notre tableau initial n'est plus assez grand
                  maxLineNumber = maxLineNumber * 2;
                  double[][] temp = new double[columnNumber][maxLineNumber];
                  for (int i = 0; i < columnNumber; i++)
                     for (int l = 0; l < retour[0].length; l++)
                        temp[i][l] = retour[i][l];
                  retour = temp;
               }

               for (int i = 0; i < columnNumber; i++)
                  retour[i][lineNumber] = line[i];
               lineNumber++;
            }
         }
      }
      // Cree un tableau aux dimensions exactes
      double[][] temp;
      if (columnNumber == 0)
         temp = null;
      else
         temp = new double[columnNumber][lineNumber];
      for (int i = 0; i < columnNumber; i++)
         for (int l = 0; l < lineNumber; l++)
            temp[i][l] = retour[i][l];
      retour = null;
      return temp;
   }


   /**
    * Parses data according to a user defined format and stores the
    *  extracted values in the returned table. betweenValues sets
    *   characters between values on the same line and endLine sets
    *   characters which separates each line of the input data set. Usually, this
    *   parameter contains the classic end of line character %n.
    *    This method uses regular expressions, so it is possible to use regular
    *   characters as defined in the standard java API, specially in the class
    *   {@link Pattern} (package java.util.regex).
    * 
    * @param betweenValues String which separates values on the same line.
    * 
    *    @param endLine String which separates lines.
    * 
    *    @param data String to parse.
    * 
    *    @return Table that represent data contained in data.
    *    @exception IllegalArgumentException if each line of the input String doesn't share the same number of values
    * 
    */
   public static double[][] fromCustomizedFormat (String betweenValues,
                                           String endLine, String data)  {
      int maxLineNumber = 16;
      int columnNumber = 0;
      int lineNumber = 0;
      double[][] retour = new double[1][1]; //initialisation temporaire

      Pattern p = Pattern.compile("(" + endLine + ")(" + endLine + ")*");
      String[] string = p.split(data); // A chaque String correspond une ligne

      for (int j = 0; j < string.length; j++) {
         if (string[j].length() != 0) {
            //On ne traite pas les lignes vides

            p = Pattern.compile("(" + betweenValues + ")(" + betweenValues + ")*");
            String[] result = p.split(string[j]);
            double[] line = new double[result.length];

            int k = 0; // Compte le nombre de valeurs sur la ligne courante
            for (int i = 0; i < result.length; i++) {
               try {
                  line[k] = Double.valueOf(result[i]);   // les chaines de caracteres qui ne sont pas des nombres sont ignorees
                  k++;
               } catch (NumberFormatException nfe) {}
            }

            if (k != 0) { // il y a des valeurs sur la ligne
               //La premiere ligne determine combien de colonnes aura notre tableau de retour
               if (lineNumber == 0) {
                  columnNumber = k;
                  retour = new double[columnNumber][maxLineNumber]; // Allocation du tableau de retour
               } else if ( columnNumber != k ) // Toutes les lignes de la String n'ont pas le meme nombre de valeurs
                  throw new IllegalArgumentException("Each line must have the same number of values");

               if (lineNumber >= maxLineNumber) { // Cas ou notre tableau initial n'est plus assez grand
                  maxLineNumber = maxLineNumber * 2;
                  double[][] temp = new double[columnNumber][maxLineNumber];
                  for (int i = 0; i < columnNumber; i++)
                     for (int l = 0; l < retour[0].length; l++)
                        temp[i][l] = retour[i][l];
                  retour = temp;
               }

               for (int i = 0; i < columnNumber; i++)
                  retour[i][lineNumber] = line[i];
               lineNumber++;
            }
         }
      }
      // Cree un tableau aux dimensions exactes
      double[][] temp;
      if (columnNumber == 0)
         temp = null;
      else
         temp = new double[columnNumber][lineNumber];
      for (int i = 0; i < columnNumber; i++)
         for (int l = 0; l < lineNumber; l++)
            temp[i][l] = retour[i][l];
      retour = null;
      return temp;
   }


   /**
    * Stores data tables data into a String,
    *    with format understandable by GNUPlot.
    * 
    * @param data data tables.
    * 
    *    @return String that represent data tables in GNUPlot format.
    * 
    */
   public static String toGNUPlot (double[]... data)  {
      checkData(data);
      Formatter formatter = new Formatter(Locale.US);

      for (int i = 0; i < data[0].length; i++) {
         for (int j = 0; j < data.length; j++) {
            formatter.format("%20f", data[j][i]);
         }
         formatter.format("%n");
      }
      formatter.format("%n%n");
      return formatter.toString();
   }


   /**
    * Stores series collection data into a String,
    *    with format understandable by GNUPlot.
    * 
    * @param data data tables.
    * 
    *    @return String that represent data tables in GNUPlot format.
    * 
    */
   public static String toGNUPlot (XYSeriesCollection data)  {
      return toGNUPlot(toTable(data));
   }


   /**
    * Stores data tables data into a String
    *    with format CSV (comma-separated value tabular data).
    *    The output string could be imported from a file to a matrix
    *    into Mathematica with Mathematica's function Import["fileName", "CSV"],
    *    or into MATLAB with MATLAB's function csvread('fileName').
    * 
    * @param data data tables.
    * 
    *    @return String that represent data tables in CSV format.
    * 
    */
   public static String toCSV (double[]...data)  {
      checkData(data);
      Formatter formatter = new Formatter(Locale.US);

      for (int i = 0; i < data[0].length; i++) {
         for (int j = 0; j < data.length - 1; j++) {
            formatter.format("%-20f, ", data[j][i]);
         }
         formatter.format("%-20f%n", data[data.length-1][i]);      //le dernier
      }
      formatter.format("%n");

      return formatter.toString();
   }


   /**
    * Stores series collection data into a String
    *    with format CSV (comma-separated value tabular data).
    * 
    * @param data data tables.
    * 
    *    @return String that represent data tables in CSV format.
    * 
    */
   public static String toCSV (XYSeriesCollection data)  {
      return toCSV(toTable(data));
   }


   /**
    * Stores data tables data into a String with customized format.
    * heading sets the head of the returned String, footer
    * sets its end, betweenValues sets characters between values on the same
    *  line and finally endLine sets characters which separates each line of
    *  the input data set. Normally, this parameter contains the classic end of line
    *   character `%n'.
    * 
    * @param heading head of the returned String.
    * 
    *    @param footer end of the returned String.
    * 
    *    @param betweenValues String which separates values on the same line.
    * 
    *    @param endLine String which separates lines.
    * 
    *    @param data data tables.
    * 
    *    @return String that represent data tables in customized format.
    * 
    */
   public static String toCustomizedFormat (String heading, String footer,
                                   String betweenValues, String endLine,
                                   int precision, double[]...data)  {
      checkData(data);
      Formatter formatter = new Formatter(Locale.US);
      String myString = "%20."+ precision +"f";

      formatter.format("%s", heading);
      for (int i = 0; i < data[0].length; i++) {
         for (int j = 0; j < data.length - 1; j++) {
            formatter.format(myString+"%s", data[j][i], betweenValues);
         }
         formatter.format(myString+"%s", data[data.length-1][i], endLine);      //le dernier de la ligne
      }
      formatter.format("%s", footer);
      return formatter.toString();
   }


   /**
    * Stores data tables data into a String
    *    with customized format from an XYSeriesCollection variable.
    * 
    * @param heading head of the returned String.
    * 
    *    @param footer end of the returned String.
    * 
    *    @param betweenValues String which separates values on the same line.
    * 
    *    @param endLine String which separates lines.
    * 
    *    @param data data tables.
    * 
    *    @return String that represent data tables in customized format.
    * 
    */
   public static String toCustomizedFormat (String heading, String footer,
                                   String betweenValues, String endLine,
                                   int precision, XYSeriesCollection data)  {
      return toCustomizedFormat (heading, footer, betweenValues, endLine,
                       precision, toTable(data));
   }


   /* *
    * Converts a XYSeriesCollection object into a double[][].
    */
   private static double[][] toTable (XYSeriesCollection data) {
      double[][] transform = new double[data.getSeriesCount()*2][];

      for(int i = 0; idata.
    *
    * @exception  IllegalArgumentException   If the input tables doesn't have the same length.
    */
   private static void checkData(double[]...data) {
      for(int i = 0; i < data.length-1; i++) {
         if(data[i].length != data[i+1].length)
            throw new IllegalArgumentException("Data tables " + i + " and " + (i+1) + " must share the same length");
      }
   }

/* //Inutile si on exporte en CSV
   private static String mathematicaFormatPoint (double x, double y) {
      // Writes the pair (x, y) in returned string, in a format understood
      // by Mathematica
      StringBuffer sb = new StringBuffer();
      String S;

      sb.append ("   { ");
      if ((x != 0.0) && (x < 0.1 || x > 1.0)) {
         S = PrintfFormat.E (16, 7, x);
         int exppos = S.indexOf ('E');
         if (exppos != -1)
            S = S.substring (0, exppos) + "*10^(" +
                             S.substring (exppos+1) + ")";
      }
      else
         S = PrintfFormat.g (16, 8, x);

      sb.append (S + ",     ");

      if (y != 0.0 && (y < 0.1 || y > 1.0)) {
         S = PrintfFormat.E (16, 7, y);
         int exppos = S.indexOf ('E');
         if (exppos != -1)
            S = S.substring (0, exppos) + "*10^(" +
                             S.substring (exppos+1) + ")";
      }
      else
        S = PrintfFormat.g (16, 8, y);

      sb.append (S + " }");
      return sb.toString();
   }*/


}

 

Ads help maintain this website.