001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
005     * Space Science and Engineering Center (SSEC)
006     * University of Wisconsin - Madison
007     * 1225 W. Dayton Street, Madison, WI 53706, USA
008     * https://www.ssec.wisc.edu/mcidas
009     * 
010     * All Rights Reserved
011     * 
012     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013     * some McIDAS-V source code is based on IDV and VisAD source code.  
014     * 
015     * McIDAS-V is free software; you can redistribute it and/or modify
016     * it under the terms of the GNU Lesser Public License as published by
017     * the Free Software Foundation; either version 3 of the License, or
018     * (at your option) any later version.
019     * 
020     * McIDAS-V is distributed in the hope that it will be useful,
021     * but WITHOUT ANY WARRANTY; without even the implied warranty of
022     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023     * GNU Lesser Public License for more details.
024     * 
025     * You should have received a copy of the GNU Lesser Public License
026     * along with this program.  If not, see http://www.gnu.org/licenses.
027     */
028    
029    package edu.wisc.ssec.mcidasv.data;
030    
031    import java.awt.BorderLayout;
032    import java.awt.Color;
033    import java.awt.Component;
034    import java.awt.Container;
035    import java.awt.Dimension;
036    import java.awt.FlowLayout;
037    import java.awt.GridLayout;
038    import java.awt.event.ActionEvent;
039    import java.awt.event.ActionListener;
040    import java.awt.event.WindowEvent;
041    import java.awt.event.WindowAdapter;
042    import java.awt.geom.Rectangle2D;
043    import java.net.URL;
044    import java.rmi.RemoteException;
045    import java.util.ArrayList;
046    import java.util.List;
047    import java.io.PrintWriter;
048    import java.io.File;
049    
050    import javax.swing.JFrame;
051    import javax.swing.ButtonGroup;
052    import javax.swing.ImageIcon;
053    import javax.swing.JComponent;
054    import javax.swing.JPanel;
055    import javax.swing.JRadioButton;
056    import javax.swing.JToggleButton;
057    import javax.swing.JButton;
058    import javax.swing.JScrollPane;
059    import javax.swing.JTable;
060    import javax.swing.JFileChooser;
061    import javax.swing.filechooser.FileFilter;
062    import javax.swing.filechooser.FileNameExtensionFilter;
063    import javax.swing.table.AbstractTableModel;
064    import javax.swing.table.TableCellRenderer;
065    import javax.swing.border.CompoundBorder;
066    import javax.swing.border.EmptyBorder;
067    import javax.swing.border.LineBorder;
068    
069    import org.slf4j.Logger;
070    import org.slf4j.LoggerFactory;
071    
072    import visad.AxisScale;
073    import visad.BaseColorControl;
074    import visad.CellImpl;
075    import visad.CoordinateSystem;
076    import visad.Data;
077    import visad.DelaunayCustom;
078    import visad.DisplayEvent;
079    import visad.DisplayListener;
080    import visad.Real;
081    import visad.FieldImpl;
082    import visad.FlatField;
083    import visad.FunctionType;
084    import visad.Gridded2DSet;
085    import visad.Gridded3DSet;
086    import visad.Integer1DSet;
087    import visad.Linear2DSet;
088    import visad.LinearLatLonSet;
089    import visad.RealTupleType;
090    import visad.MathType;
091    import visad.RealType;
092    import visad.SampledSet;
093    import visad.ScalarMap;
094    import visad.Set;
095    import visad.SetType;
096    import visad.UnionSet;
097    import visad.VisADException;
098    import visad.data.mcidas.BaseMapAdapter;
099    import visad.georef.MapProjection;
100    import visad.georef.TrivialMapProjection;
101    import visad.python.JPythonMethods;
102    
103    import edu.wisc.ssec.mcidasv.data.hydra.Statistics;
104    
105    public class StatsTable extends AbstractTableModel {
106    
107        String [][] data;
108        JTable table;
109        JFrame statsWindow;
110        double total_area = 0.0;
111        int numCols;
112        boolean isShowing = false;
113        Color[] coltab = {new Color(0xf0f0f0), new Color(0xffd0ff), 
114                          new Color(0xd0ffd0), new Color(0xc0d0ff)};
115    
116        final int maxCols = 9;
117        String[] colNames = {"Stats Parameter","Whole Field X","Whole Field Y",
118          "Magenta X","Magenta Y", "Green X","Green Y","Blue X","Blue Y"};
119    
120        final int maxRows = 13;
121        final String[] rowNames = {"Maximum","Minimum",
122          "Number of points","Mean","Median","Variance","Kurtosis",
123          "Std Dev","Correlation","Difference Maximum",
124          "Difference Minimum","Difference Mean","Area [km^2]"};
125    
126        boolean saveStats = true;
127    
128    
129        public StatsTable() {
130          this(true);
131        }
132    
133        public StatsTable(boolean saveStats) { super();
134          this.saveStats = saveStats;
135    
136          data = new String[maxRows][maxCols];
137          numCols = 1;
138    
139          for (int i=0; i<maxRows; i++) {
140            data[i][0] = rowNames[i];
141            for (int j=1; j<maxCols; j++) {
142              data[i][j] = "  ";
143            }
144          }
145    
146    
147          table = new JTable(this) {
148            public Component prepareRenderer(
149              TableCellRenderer renderer, int row, int col) {
150                Component comp = super.prepareRenderer(renderer, row, col);
151                Color c = Color.white;
152                if (col == 0) c = coltab[0];
153                if (col == 3 || col == 4) c = coltab[1];
154                if (col == 5 || col == 6) c = coltab[2];
155                if (col == 7 || col == 8) c = coltab[3];
156                comp.setBackground(c);
157                return comp;
158              }
159    
160          };
161          table.setFillsViewportHeight(true);
162          table.setPreferredScrollableViewportSize(new Dimension(620,220));
163          table.setRowSelectionAllowed(true);
164          table.setColumnSelectionAllowed(false);
165    
166          JButton saveStatsButt = new JButton("Save As CSV");
167          JScrollPane sp = new JScrollPane(table);
168          statsWindow = new JFrame("Scatter Statistics");
169          statsWindow.setLayout(new BorderLayout());
170          statsWindow.getContentPane().add(sp,BorderLayout.NORTH);
171          JPanel bpan = new JPanel(new FlowLayout());
172          bpan.add(saveStatsButt);
173          if (saveStats) {
174            statsWindow.getContentPane().add(bpan,BorderLayout.SOUTH);
175          }
176          statsWindow.setSize(650,340);
177          statsWindow.pack();
178          statsWindow.addWindowListener(new WindowAdapter() {
179            public void windowClosing(WindowEvent e) {
180              isShowing = false;
181            }
182          });
183    
184          saveStatsButt.addActionListener(new ActionListener() {
185              public void actionPerformed(final ActionEvent e) {
186                JFileChooser chzr = new JFileChooser();
187                  FileFilter filt = new FileNameExtensionFilter("csv","txt");
188                  chzr.addChoosableFileFilter(filt);
189                  int rv = chzr.showSaveDialog(statsWindow);
190                  if (rv == JFileChooser.APPROVE_OPTION) {
191                    try {
192                      File fpw = chzr.getSelectedFile();
193                      statsWindow.setTitle("Scatter Statistics saved to "+fpw.toString());
194                      PrintWriter pw = new PrintWriter(fpw);
195                      String line = "";
196                      for (int k=0; k<colNames.length; k++) {
197                        if (k != 0) line = line + ",";
198                        line = line + colNames[k];
199                      }
200                      pw.println(line);
201    
202                      for (int i=0; i<data.length; i++) {
203                        line = "";
204                        for (int j=0; j<data[i].length; j++) {
205                          if (j != 0) line = line+",";
206                          line = line+data[i][j];
207                        }
208                        pw.println(line);
209                      }
210                      pw.flush();
211                      pw.close();
212                    } catch (Exception epw) {
213                      statsWindow.setTitle("Scatter Statistics: File not saved");
214                    }  
215    
216                  }
217    
218              }
219            });
220    
221            isShowing = false;
222            statsWindow.setVisible(false);
223          }
224    
225          public void setIsShowing() {
226            isShowing = true;
227          }
228    
229          public void resetValues(int col) {
230            for (int i=0; i<maxRows; i++) {
231              int c = 2*col + 3;
232              data[i][c] = " ";
233              data[i][c+1] = " ";
234            }
235            fireTableStructureChanged();
236          }
237    
238          public void setNames(String xn, String yn) {
239            colNames[1] = colNames[3] = colNames[5] = colNames[7] =xn;
240            colNames[2] = colNames[4] = colNames[6] = colNames[8] =yn;
241          }
242    
243          // fx, fy are Fields, col = 0,1,2,3 (all, red, green, blue)
244          public void setFields(FlatField fx, FlatField fy, int col) {
245            statsWindow.setTitle("Scatter Statistics");
246            try {
247              Statistics sx = new Statistics(fx);
248              Statistics sy = new Statistics(fy);
249              Statistics diff = new Statistics((FlatField)fx.subtract(fy));
250    
251              int c = 2*col + 1;
252              data[0][c] = fmtMe(((Real)sx.max()).getValue());
253              data[0][c+1] = fmtMe(((Real)sy.max()).getValue());
254    
255              data[1][c] = fmtMe(((Real)sx.min()).getValue());
256              data[1][c+1] = fmtMe(((Real)sy.min()).getValue());
257    
258              data[2][c] = String.format("%d",sx.numPoints());
259              data[2][c+1] = String.format("%d",sy.numPoints());
260    
261              data[3][c] = fmtMe(((Real)sx.mean()).getValue());
262              data[3][c+1] = fmtMe(((Real)sy.mean()).getValue());
263    
264              data[4][c] = fmtMe(((Real)sx.median()).getValue());
265              data[4][c+1] = fmtMe(((Real)sy.median()).getValue());
266    
267              data[5][c] = fmtMe(((Real)sx.variance()).getValue());
268              data[5][c+1] = fmtMe(((Real)sy.variance()).getValue());
269    
270              data[6][c] = fmtMe(((Real)sx.kurtosis()).getValue());
271              data[6][c+1] = fmtMe(((Real)sy.kurtosis()).getValue());
272    
273              data[7][c] = fmtMe(((Real)sx.standardDeviation()).getValue());
274              data[7][c+1] = fmtMe(((Real)sy.standardDeviation()).getValue());
275    
276              data[8][c] = fmtMe(((Real)sx.correlation(fy)).getValue());
277              data[8][c+1] = " ";
278    
279              data[9][c] = fmtMe(((Real)diff.max()).getValue());
280              data[9][c+1] = " ";
281    
282              data[10][c] = fmtMe(((Real)diff.min()).getValue());
283              data[10][c+1] = " ";
284    
285              data[11][c] = fmtMe(((Real)diff.mean()).getValue());
286              data[11][c+1] = " ";
287    
288              if (c == 1) {
289                data[12][c] = " ";
290              } else {
291                data[12][c] = fmtMe(total_area);
292              }
293              data[12][c+1] = " ";
294    
295              if (c+2 > numCols) numCols = c+2;
296              fireTableStructureChanged();
297    
298            } catch (VisADException exc) {
299              System.out.println(exc.getMessage());
300            } catch (Exception exc) {
301              exc.printStackTrace();
302            }
303    
304            if (isShowing) statsWindow.setVisible(true);
305          }
306    
307          private String fmtMe(double val) {
308    
309            if (Math.abs(val) == 0.0) {
310              return "0.00";
311    
312            } else if (Math.abs(val) > 9999.9 || Math.abs(val) < .0010) {
313              return String.format("%.6e", val);
314    
315            } else if (Math.abs(val) < 1.0) {
316              return String.format("%.5f", val);
317    
318            } else if (Math.abs(val) < 10.0) {
319              return String.format("%.3f", val);
320    
321            } else {
322              return String.format("%.2f", val);
323            }
324          }
325    
326          public void setPoints(float[][] markScatter, int len, int indx, double area) {
327            try {
328              total_area = area;
329              Integer1DSet sdset = new Integer1DSet(len);
330              FlatField scattX = new FlatField(
331                new FunctionType(RealType.Generic, RealType.Generic), sdset);
332    
333              float[][] scattValsX = new float[1][len];
334              System.arraycopy(markScatter[0],0,scattValsX[0],0,len);
335              scattX.setSamples(scattValsX, false);
336    
337              FlatField scattY = new FlatField(
338                new FunctionType(RealType.Generic, RealType.Generic), sdset);
339              float[][] scattValsY = new float[1][len];
340              System.arraycopy(markScatter[1],0,scattValsY[0],0,len);
341              scattY.setSamples(scattValsY, false);
342    
343              setFields(scattX, scattY, indx);
344    
345            } catch (Exception esd) {
346              esd.printStackTrace();
347            }
348          }
349    
350          public int getRowCount() {
351            return maxRows;
352          }
353          public int getColumnCount() {
354            return numCols;
355          }
356          public String getValueAt(int row, int col) {
357            return data[row][col];
358          }
359          public String getColumnName(int col) {
360            return colNames[col];
361          }
362    }