001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
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
029package edu.wisc.ssec.mcidasv.data;
030
031import java.awt.BorderLayout;
032import java.awt.Color;
033import java.awt.Component;
034import java.awt.Container;
035import java.awt.Dimension;
036import java.awt.FlowLayout;
037import java.awt.GridLayout;
038import java.awt.event.ActionEvent;
039import java.awt.event.ActionListener;
040import java.awt.event.WindowEvent;
041import java.awt.event.WindowAdapter;
042import java.awt.geom.Rectangle2D;
043import java.net.URL;
044import java.rmi.RemoteException;
045import java.util.ArrayList;
046import java.util.List;
047import java.io.PrintWriter;
048import java.io.File;
049
050import javax.swing.JFrame;
051import javax.swing.ButtonGroup;
052import javax.swing.ImageIcon;
053import javax.swing.JComponent;
054import javax.swing.JPanel;
055import javax.swing.JRadioButton;
056import javax.swing.JToggleButton;
057import javax.swing.JButton;
058import javax.swing.JScrollPane;
059import javax.swing.JTable;
060import javax.swing.JFileChooser;
061import javax.swing.filechooser.FileFilter;
062import javax.swing.filechooser.FileNameExtensionFilter;
063import javax.swing.table.AbstractTableModel;
064import javax.swing.table.TableCellRenderer;
065import javax.swing.border.CompoundBorder;
066import javax.swing.border.EmptyBorder;
067import javax.swing.border.LineBorder;
068
069import org.slf4j.Logger;
070import org.slf4j.LoggerFactory;
071
072import visad.AxisScale;
073import visad.BaseColorControl;
074import visad.CellImpl;
075import visad.CoordinateSystem;
076import visad.Data;
077import visad.DelaunayCustom;
078import visad.DisplayEvent;
079import visad.DisplayListener;
080import visad.Real;
081import visad.FieldImpl;
082import visad.FlatField;
083import visad.FunctionType;
084import visad.Gridded2DSet;
085import visad.Gridded3DSet;
086import visad.Integer1DSet;
087import visad.Linear2DSet;
088import visad.LinearLatLonSet;
089import visad.RealTupleType;
090import visad.MathType;
091import visad.RealType;
092import visad.SampledSet;
093import visad.ScalarMap;
094import visad.Set;
095import visad.SetType;
096import visad.UnionSet;
097import visad.VisADException;
098import visad.data.mcidas.BaseMapAdapter;
099import visad.georef.MapProjection;
100import visad.georef.TrivialMapProjection;
101import visad.python.JPythonMethods;
102
103import edu.wisc.ssec.mcidasv.data.hydra.Statistics;
104
105public 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      public static 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}