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 }