Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jplot/DataFile.java


1   /*
2    * JPLOT  -- Java Plotting Interface for any programme or
3    *           as an independent GUI
4    * 
5    * Copyright (C) 1999 Jan van der Lee
6    *
7    * This program is free software; you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation; either version 2
10   * of the License, or (at your option) any later version.
11   *
12   * This program is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   * 
17   * You should have received a copy of the GNU General Public License
18   * along with this program; if not, write to the Free Software
19   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
20   * 02111-1307, USA.
21   *
22   * Send bugs, suggestions or queries to <jplot@cig.ensmp.fr>
23   * The latest releases are found at 
24   * http://www.cig.ensmp.fr/~vanderlee/jplot.html
25   *
26   * Initally developed for use by the Centre d'Informatique Geologique 
27   * Ecole des Mines de Paris, Fontainebleau, France.
28   */
29  
30  package jplot;
31  
32  import java.io.*;
33  import java.util.*;
34  
35  /**
36   * This class contains all the info specific for one datafile.
37   * The PlotPanel provides the columns to-be-plotted for
38   * a specific file, with a line-style class for each column.
39   * This class keeps track of this information.
40   */
41  public class DataFile {
42    private File file;
43    private Vector items;
44    private Vector columns;
45    //private Vector columnNames;
46    private int xColumn;
47    private Vector styles;
48    private String abbreviatedFilename;
49    private String filenameWithoutPath;
50    private final int maxLen=45;
51    private int index;
52    private int graphType;
53  
54    private GraphPars gp;
55    
56    /**
57     * Builds the class from a filename. As soon as the datafile is
58     * build, read the header of the file and make a list of all the
59     * available columns.
60     * @param file file for this set
61     * @param index index, kind of identifier of this instance, 
62     * @param labels vector to store the labels defined in the datafile
63     * corresponding to the index of the tabbedPanes.
64     */
65    DataFile(File file, int index, GraphPars gp) {
66      this.file = file;
67      this.index = index;
68      this.gp = gp;
69      columns = new Vector();
70      styles = new Vector();
71      items = new Vector();
72      graphType = gp.GRAPHTYPE_2D;
73      int len = file.toString().length();
74      if (len > maxLen) {
75        abbreviatedFilename = "..." + file.toString().substring(len-maxLen,len);
76      }
77      else abbreviatedFilename = file.toString();
78      int i = abbreviatedFilename.lastIndexOf(JPlot.FS,0);
79      len = abbreviatedFilename.length();
80      if (i > -1) filenameWithoutPath = abbreviatedFilename.substring(i,len);
81      else filenameWithoutPath = abbreviatedFilename;
82      loadColumnNames(gp.getLabels());
83    }
84  
85    /**
86     * Reads the datafile for data. The data is put in a specific purpose
87     * DataArray object, which contains x- and y values. Note that all
88     * blank lines or lines starting with '#' are skipped. One exception:
89     * lines starting with '# column 1:' etc. are supposed to provide
90     * the name of the column, hence '# column 1: nodes' means that column
91     * 1 has the name 'nodes', which will be used by this program in order
92     * to easily select columns.
93     *
94     * If the list of column names existed already, and if the new list
95     * of names is identical, return true. Else delete the current
96     * selection and return false.
97     *
98     * @param labels vector to store the labels defined in the datafile
99     * @return true if the current selection can be maintained, false otherwise.
100    */
101   public boolean loadColumnNames(Vector labels) {
102     boolean res = false;
103     Vector newItems = new Vector();
104 
105     // mark the labels eventually present and given by a dataset
106     // with CHECK : if they are found in the new dataset, we rename
107     // their type to 'DATA' which allows us to keep the settings
108     // such as font, color etc.
109     Vector newLabels = new Vector();
110     for (Enumeration e=labels.elements(); e.hasMoreElements();) {
111       GraphLabel g = (GraphLabel) e.nextElement();
112       if (g.equals(GraphLabel.DATA) && g.getFile() == file) {
113   g.setID(GraphLabel.CHECK);
114       }
115       newLabels.add(g);
116     }
117 
118     try {
119       BufferedReader in = new BufferedReader(new FileReader(file));
120       String s;
121       int k = 1;
122       while ((s=in.readLine()) != null) {
123   s = s.trim();
124   if (s.length() == 0) continue;
125   StringTokenizer st = new StringTokenizer(s," \t,:");
126   String token = st.nextToken();
127   if (token.startsWith("#")) {
128     if (!st.hasMoreTokens()) continue;
129     String nextToken = st.nextToken();
130     if (st.hasMoreTokens()) {
131       if (nextToken.startsWith("graph")) {
132         token = st.nextToken();
133         if (token.startsWith("piper")) graphType = gp.GRAPHTYPE_PIPER;
134         else if (token.startsWith("multi")) {
135 
136     // it's a multidata plot. We'll disable the
137     // legend by default for this type of graphs:
138     graphType = gp.GRAPHTYPE_MULTI;
139     gp.setDrawLegend(false);
140         }
141         else graphType = gp.GRAPHTYPE_2D;
142         continue;
143       }
144       else if (nextToken.equals("column") || 
145          nextToken.equals("row")) {
146         st.nextToken();  // eat column number, e.g. '2:'
147         token = st.nextToken();
148         while (st.hasMoreTokens()) token += " " + st.nextToken();
149         newItems.addElement(token);
150         continue;
151       }
152 
153       else if (nextToken.equals("dataset")) {
154         st.nextToken();  // eat column number, e.g. '2:'
155         token = getLabel(st);
156         newItems.addElement(token);
157         continue;
158       }
159 
160       // get the x-label from the dataset, if any
161       else if (nextToken.startsWith("xlabel") && st.hasMoreTokens()) {
162         GraphLabel gl = 
163     new GraphLabel(GraphLabel.XLABEL,getLabel(st));
164         addLabel(gl,newLabels);
165         continue;
166       }
167 
168       // get the y-label from the dataset, if any
169       else if (nextToken.startsWith("ylabel") && st.hasMoreTokens()) {
170         GraphLabel gl = 
171     new GraphLabel(GraphLabel.YLABEL,getLabel(st));
172         gl.setRotation(Math.PI*1.5);
173         addLabel(gl,newLabels);
174         continue;
175       }
176 
177       // random labels:
178       else if (nextToken.startsWith("label") && st.hasMoreTokens()) {
179         GraphLabel gl = 
180     new GraphLabel(GraphLabel.DATA,getLabel(st));
181         gl.setFile(file);
182         if (st.hasMoreTokens()) {
183     double xx,yy;
184     xx = Double.parseDouble(st.nextToken());
185     if (st.hasMoreTokens()) {
186       yy = Double.parseDouble(st.nextToken());
187       gl.setDataLocation(xx,yy);
188       if (st.hasMoreTokens()) {
189         gl.setDataRotation(Math.PI*Double.parseDouble(st.nextToken())/180.0);
190       }
191     }
192     else gl.setRotation(Math.PI*xx/180);
193         }
194         addLabel(gl,newLabels);
195         continue;
196       }
197       else continue;
198     }
199   }
200   else if (newItems.size() == 0) {
201     newItems.addElement("column " + Integer.toString(k++));
202     while (st.hasMoreTokens()) {
203       token = st.nextToken();
204       if (token.startsWith("*")) break;
205       newItems.addElement("column " + Integer.toString(k++));
206     }
207     break;
208   }
209       }
210       in.close();
211     }
212     catch (Exception e) {
213       Utils.oops(null,"Something's wrong with file '" + getName() + "'!");
214       return false;
215     }
216 
217     if (items.size() > 0) {
218       if (items.size() == newItems.size()) {
219   res = true;
220   Enumeration e1 = items.elements();
221   Enumeration e2 = newItems.elements();
222   while (e1.hasMoreElements()) {
223     if (!((String)e1.nextElement()).equals((String)e2.nextElement())) {
224       res = false;
225       break;
226     }
227   }
228       }
229       else res = false;
230     }
231     items = newItems;
232     if (!res) {
233       if (columns.size() > 0) columns.removeAllElements();
234       if (styles.size() > 0) styles.removeAllElements();
235     }
236     if (items.size() == 2) gp.setDrawLegend(false);
237 
238     // if labels read, delete all labels which were marked 
239     // 'CHECK' and not found in the current dataset:
240     if (labels.size() > 0) labels.removeAllElements();
241     if (newLabels.size() > 0) {
242       for (Enumeration e=newLabels.elements(); e.hasMoreElements();) {
243   GraphLabel g = (GraphLabel) e.nextElement();
244   if (!g.equals(GraphLabel.CHECK)) labels.add(g);
245       }
246       newLabels.removeAllElements();
247       newLabels = null;
248     }
249     return res;
250   }  
251 
252   private String getLabel(StringTokenizer st) {
253     String token = st.nextToken();
254     if (token.startsWith("\"")) {  // is a label between " and "
255       while (!token.endsWith("\"")) token += " " + st.nextToken();
256       token = token.substring(1,token.length()-1);
257     }
258     return token;
259   }
260 
261   /*
262    * Add a label to the vector of labels.
263    * The rule is, for the moment: if the user reloads the
264    * datafile (and hence passes through this procedure), the
265    * label is declared. But if the label already exists (with,
266    * perhaps, another color, font or position), than we keep
267    * this label instead BUT we use the position as defined 
268    * here in the data set.
269    */
270   private void addLabel(GraphLabel gl, Vector newLabels) {
271     boolean labelFound = false;
272     for (Enumeration e=newLabels.elements(); e.hasMoreElements();) {
273       GraphLabel g = (GraphLabel) e.nextElement();
274       if (gl.equals(g.getText()) && (g.equals(GraphLabel.CHECK))) {
275   g.setUsePosition(false);
276   g.setDataLocation(gl.getXPos(),gl.getYPos());
277   g.setID(gl.getID());
278   labelFound = true;
279   break;
280       }
281     }
282     if (!labelFound) newLabels.add(gl);
283   }
284 
285 
286   /**
287    * @return the number of items present in the item vector.
288    */
289   public int getNumberOfItems() {
290     return items.size();
291   }
292 
293   /**
294    * @return the item corresponding to index i.
295    */
296   public String getItem(int i) {
297     return (String) items.get(i);
298   }
299 
300   /**
301    * Adds an item to the vector.
302    * @param item name of the item added.
303    */
304   public void addItem(String item) {
305     items.add(item);
306   }
307 
308   /*
309    * remove a column at a specified index:
310    */
311   private void delCol(Integer index) {
312     int k=0;
313     for (Enumeration e=columns.elements(); e.hasMoreElements(); k++) {
314       Integer i = (Integer) e.nextElement();
315       if (i.equals(index)) break;
316     }
317     if (k < columns.size()) {
318       columns.remove(k);
319       styles.remove(k);
320     }
321   }
322   
323   /**
324    * adds a column to the vector of columns.
325    * The column is added <strong>even</strong> if the column
326    * index is already selected (hence selecting several times the
327    * same column is allowed). This is useful if the user wants
328    * to plot the same data several times but in a different way.
329    * (histogram + lines, for example).
330    * @param columnIndex index of the column
331    * @param lp parameters used to draw the line
332    */
333   public void addColumn(int columnIndex, LinePars lp) {
334     Integer index = new Integer(columnIndex);
335     columns.add(index);
336     styles.add(lp);
337   }
338 
339   /**
340    * sets the index of the column used for the X-axis
341    * @param columnIndex index of the column
342    */
343   public void setXColumn(int columnIndex) {
344     xColumn = columnIndex;
345   }
346 
347   /**
348    * returns the index of the column used for the X-axis
349    * @return index of the column
350    */
351   public int getXColumn() {
352     return xColumn;
353   }
354 
355   /**
356    * returns the index of the column used for the Y-axis
357    * @param i index of the column item
358    * @return index of the column
359    */
360   public int getYColumn(int i) {
361     return ((Integer)columns.get(i)).intValue();
362   }
363 
364   /**
365    * returns the linestyle of one of the vector items.
366    * @param index index of the column
367    */
368   public LinePars getLinePars(int index) {
369     if (styles.size() == 0) return new LinePars();
370     if (index < styles.size()) return (LinePars)styles.get(index);
371     return (LinePars)styles.get(0);
372   }
373 
374   /**
375    * sets the linestyle of one of the vector items.
376    * @param index index of the column
377    * @param lp linepars instance (can't be null!)
378    */
379   public void setLinePars(int index, LinePars lp) {
380     styles.set(index,lp);
381   }
382 
383   /**
384    * sets the linestyle of all the vector items.
385    * @param lp linepars instance
386    */
387   public void setLinePars(LinePars lp) {
388     if (styles.size() > 0) {
389       styles.removeAllElements();
390     }
391     for (int k=0; k<columns.size(); k++) {
392       lp = new LinePars(lp);
393       if (lp.slideColor) lp.nextColor(columns.size());
394       styles.add(lp);
395     }
396   }
397 
398   public String getLegend(int index) {
399     return getLinePars(index).getName();
400   }
401 
402   /**
403    * remove a column from the vector of columns.
404    * @param columnIndex index of the column
405    */
406   public void removeColumn(int columnIndex) {
407     if (columnIndex < columns.size()) {
408       columns.remove(columnIndex);
409       styles.remove(columnIndex);
410     }
411   }
412 
413   /**
414    * Return the number of columns (selected items)
415    * @return number of Y-columns
416    */
417   public int getNumberOfColumns() {
418     return columns.size();
419   }
420 
421   /**
422    * Return the file
423    * @return file
424    */
425   public File getFile() {
426     return file;
427   }
428 
429   /**
430    * Return the abbreviated filename.
431    * This name is different from the file itselves if it exceeds a
432    * a certain number of characters (about 45). Otherwise, the name
433    * is too long to fit in decent textboxes...
434    * @return an abbreviated version of the filename, if the latter is too long.
435    */
436   public String getAbbreviatedFilename() {
437     return abbreviatedFilename;
438   }
439 
440   /**
441    * Return the filename with the preceeding path stripped off.
442    * @return an abbreviated version of the filename, without an eventual path.
443    */
444   public String getFilenameWithoutPath() {
445     return filenameWithoutPath;
446   }
447 
448   /**
449    * Return the filename as such.
450    * @return the filename.
451    */
452   public String getName() {
453     return file.toString();
454   }
455 
456   /**
457    * Checks whether the argument is a column selected for output.
458    * @param index index which is sought for.
459    */
460   public int isSelected(int index) {
461     int k = 0;
462     for (Enumeration e=columns.elements(); e.hasMoreElements(); k++) {
463       if (((Integer)e.nextElement()).intValue() == index) {
464   //System.out.print("... " + index + " is found ...");
465   return k;
466       }
467     }
468     return -1;
469   }
470 
471   /**
472    * Returns the name of one of the columns present here.
473    * @return name of column with index i
474    */
475   public String getColumnName(int i) {
476     int index = ((Integer)columns.get(i)).intValue();
477     return (String)items.get(index);
478   }
479 
480   /**
481    * Sets the current datafile index to another value.
482    * @param i new index
483    */
484   public void setIndex(int i) {
485     index = i;
486   }
487 
488   /**
489    * @return the graphstyle of the current dataset
490    */
491   public int getGraphType() {
492     return graphType;
493   }
494 
495   /**
496    * Reads the current file and returns the data arrays.
497    * @param data arrays of X,Y data
498    * @param dataArrays vector with data-arrays of type DataArray
499    * @param type graph type (2D, piper, multiplot...)
500    * @return false if some weird error might occur during parsing.
501    */
502   public boolean getDataArrays(Vector dataArrays, int type) {
503     int nCol = getNumberOfColumns();
504     int nIts = getNumberOfItems();
505     double x=0.0;
506     int nY = (type == GraphPars.GRAPHTYPE_PIPER)? nIts : nCol;
507     double[] y = new double [nY];
508     boolean newDataSet = true;
509     boolean isFirstLabel = true;
510     String s;
511 
512     // used by the multiplot graph style:
513     int currentDataset = 0;
514 
515     try {
516       BufferedReader in = new BufferedReader(new FileReader(getFile()));
517 
518       // more than nY items, in case of the user selecting several
519       // times the same item... NullPointerException if he/she selects
520       // more than 2*nY items :-(
521       DataArray[] data = new DataArray [2*nY];
522       int k=0;
523 
524       // read a line from the file. Ignore all comments and blank lines:
525       while ((s=in.readLine()) != null) {
526   s = s.trim();
527   if (s.length() == 0) continue;
528   else if (s.startsWith("#")) continue;
529   StringTokenizer st = new StringTokenizer(s," \t,");
530   if (st.countTokens() < 2) continue;
531 
532   // if the current graph-type is a standard (X,Y1,Y2 etc) graph:
533   if (type == GraphPars.GRAPHTYPE_2D) {
534 
535     // start new dataset here
536     if (newDataSet) {
537       if (JPlot.debug) System.out.println("starting a new dataset with " + nCol + " columns...");
538       for (int i=0; i<nCol; i++) {
539         data[i] = new DataArray(101,getLinePars(i));
540       }
541       newDataSet = false;
542     }
543     boolean liftPen = false;
544     for (int i=0; st.hasMoreTokens(); i++) {
545       String t = st.nextToken();
546       if (t.startsWith("*")) liftPen = true;
547       if (i == getXColumn()) x = Double.parseDouble(t);
548       for (k=0; k<nCol; k++) {
549         if (getYColumn(k) == i) y[k] = Double.parseDouble(t);
550       }
551     }
552     for (int i=0; i<nCol; i++) data[i].addPoint(x,y[i],liftPen);
553   }
554   else {
555 
556     // not a standard graph. Can be a piper diagram or some kind
557     // of multiplot graph. The file format of these special graphs
558     // is kind of rigid, refer to the docs for info.
559     if (type == GraphPars.GRAPHTYPE_PIPER) {
560 
561       // it's a piper diagram. Very rigid format:
562       data[0] = new DataArray(3,getLinePars(k++));
563       if (st.countTokens() < 4) {
564         Utils.oops(null,"Incorrect format of Piper diagram datafile '" + getAbbreviatedFilename() + "'!");
565         return false;
566       }
567       else {
568         data[0].addPoint(Double.parseDouble(st.nextToken()),
569              Double.parseDouble(st.nextToken()));
570         data[0].addPoint(Double.parseDouble(st.nextToken()),
571              Double.parseDouble(st.nextToken()));
572         
573         // if there's one more point, it must be the TDS:
574         if (st.hasMoreTokens()) {
575     data[0].addPoint(Double.parseDouble(st.nextToken()),0.0);
576         }
577         dataArrays.add(data[0]);
578       }
579     }
580     else {
581 
582       // It's a multiplot type of graph.
583       // Note that the multiplot graph can use only two columns (x,y),
584       // all eventually following columns are silently ignored
585       if (newDataSet) {
586         data[0] = new DataArray(10,getLinePars(k));
587         newDataSet = false;
588       }
589       data[0].addPoint(Double.parseDouble(st.nextToken()),
590            Double.parseDouble(st.nextToken()));
591       while (st.hasMoreTokens()) {
592         if (st.nextToken().equals("**")) {
593     for (int i=0; i<nCol; i++) {
594       if (getYColumn(i) == currentDataset) {
595         k++;
596         dataArrays.add(data[0]);
597       }
598     }
599     currentDataset++;
600     newDataSet = true;
601     break;
602         }
603       }
604     }
605   }
606       }
607       if (type == GraphPars.GRAPHTYPE_2D) {
608   for (int i=0; i<nCol; i++) dataArrays.add(data[i]);
609       }
610       in.close();
611     }
612     catch (Exception exception) {
613       Utils.oops(null,"Something's wrong with file '" + 
614      getAbbreviatedFilename() + 
615      "'.\nCheck the file's format and its content.");
616       return false;
617     }
618     return true;
619   }
620 }