Java tutorial
/* * Copyright (C) 2012 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.beam.visat.toolviews.stat; import com.bc.ceres.core.ProgressMonitor; import com.bc.ceres.core.SubProgressMonitor; import com.bc.ceres.swing.progress.ProgressMonitorSwingWorker; import org.esa.beam.framework.dataio.ProductReader; import org.esa.beam.framework.dataio.ProductReaderPlugIn; import org.esa.beam.framework.datamodel.*; import org.esa.beam.framework.ui.TextFieldContainer; import org.esa.beam.framework.ui.GridBagUtils; import org.esa.beam.framework.ui.UIUtils; import org.esa.beam.framework.ui.application.ToolView; import org.esa.beam.framework.ui.tool.ToolButtonFactory; import org.esa.beam.util.*; import org.esa.beam.visat.VisatApp; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.StandardXYBarPainter; import org.jfree.chart.renderer.xy.XYBarRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.xy.XIntervalSeries; import org.jfree.data.xy.XIntervalSeriesCollection; import org.jfree.ui.RectangleInsets; import javax.media.jai.Histogram; import javax.swing.*; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; import java.awt.*; import java.awt.event.*; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.HashMap; /** * A general pane within the statistics window. * * @author Norman Fomferra * @author Marco Peters * @author Daniel Knowles */ class StatisticsPanel extends PagePanel implements MultipleRoiComputePanel.ComputeMasks, StatisticsDataProvider { final VisatApp visatApp = VisatApp.getApp(); private PropertyMap configuration = null; ProgressMonitorSwingWorker swingWorker; private StatisticsCriteriaPanel statisticsCriteriaPanel; private static final String DEFAULT_STATISTICS_TEXT = "<html>No statistics computed<br>Note: requires a view window to be selected</html>"; /*I18N*/ private static final String TITLE_PREFIX = "Statistics"; private double spreadsheetHeightWeight = 0.3; private int spreadsheetMinRowsBeforeWeight = 10; boolean invertPercentile = true; boolean fixedHistDomainAllPlots = false; boolean fixedHistDomainAllPlotsInitialized = false; double[] histDomainBoundsAllPlots = { 0, 0 }; boolean fixedPercentileDomainAllPlots = true; boolean fixedPercentileDomainAllPlotsInitialized = false; double[] histRangeBoundsAllPlots = { 0, 0 }; double[] percentileDomainBoundsAllPlots = { 0, 0 }; double[] percentileRangeBoundsAllPlots = { 0, 0 }; private MultipleRoiComputePanel computePanel; private JPanel backgroundPanel; private AbstractButton hideAndShowButton; private AbstractButton exportButton; private JPanel contentPanel; private JPanel spreadsheetPanel; JScrollPane spreadsheetScrollPane; JScrollPane contentScrollPane; JPanel leftPanel; JButton runButton = new JButton("Run"); private final StatisticsPanel.PopupHandler popupHandler; private final StringBuilder resultText; private boolean init; private Histogram[] histograms; private ExportStatisticsAsCsvAction exportAsCsvAction; private PutStatisticsIntoVectorDataAction putStatisticsIntoVectorDataAction; private boolean exportButtonEnabled = false; private boolean exportButtonVisible = false; private Object[][] statsSpreadsheet; private int numStxFields = 0; private int numStxRegions = 0; private int totalRecordCount = 0; private String NO_NAN_BANDNAME = "Stx_No_NaN_temporary_band_2dw7gi4kg97kgkd9034kf"; RasterDataNode noNanBandRaster = null; private int plotMinHeight = 300; private int plotMinWidth = 300; private Product currProduct = null; private RasterDataNode currRaster = null; boolean fieldsInitialized = false; ToolView parentDialog; String helpID; private static String COLUMN_BREAK = "||"; private enum PrimaryStatisticsFields { FileRefNum("File#"), BandName("Band"), MaskName("Regional_Mask"), QualityMaskName("Quality_Mask"); PrimaryStatisticsFields(String name) { this.name = name; } private final String name; public String toString() { return name; } } private enum MetaDataFields { FileMetaDataBreak(COLUMN_BREAK), FileName("File"), FileType("File_Type"), FileWidth( "File_Width"), FileHeight("File_Height"), FileFormat("File_Format"), Sensor( "Sensor"), Resolution("Resolution"), DayNight("Day_Night"), Orbit( "Orbit"), Platform("Platform"), ProcessingVersion("Processing_Version"), Projection( "Projection"), ProjectionParameters( "Projection Parameters"), TimeMetaDataBreak( COLUMN_BREAK), StartDate("Start_Date"), StartTime( "Start_Time"), EndDate("End_Date"), EndTime( "End_Time"), TimeSeriesDate( "TimeSeries_Date"), TimeSeriesTime( "TimeSeries_Time"), BandMetaDataBreak( COLUMN_BREAK), BandName( "Band"), BandUnit( "Unit"), BandValidExpression( "Band_Valid_Expression"), BandDescription( "Band_Description"), RegionalMaskMetaDataBreak( COLUMN_BREAK), RegionalMaskName( "Regional_Mask"), RegionalMaskDescription( "Regional_Mask_Description"), RegionalMaskExpression( "Regional_Mask_Expression"), QualityMaskMetaDataBreak( COLUMN_BREAK), QualityMaskName( "Quality_Mask"), QualityMaskDescription( "Quality_Mask_Description"), QualityMaskExpression( "Quality_Mask_Expression"); MetaDataFields(String name) { this.name = name; } private final String name; public String toString() { return name; } } int stxFieldsStartIdx = -1; int stxFieldsEndIdx = -1; private HashMap<MetaDataFields, Integer> metaDataFieldsHashMap = new HashMap<MetaDataFields, Integer>(); private HashMap<PrimaryStatisticsFields, Integer> primaryStatisticsFieldsHashMap = new HashMap<PrimaryStatisticsFields, Integer>(); private TextFieldContainer spreadsheetColWidthTextfieldContainer = null; public StatisticsPanel(final ToolView parentDialog, String helpID) { super(parentDialog, helpID, TITLE_PREFIX); setMinimumSize(new Dimension(1000, 390)); resultText = new StringBuilder(); popupHandler = new PopupHandler(); if (visatApp != null) { this.configuration = visatApp.getPreferences(); } this.parentDialog = parentDialog; this.helpID = helpID; } private void initHashMaps() { metaDataFieldsHashMap = new HashMap<MetaDataFields, Integer>(); for (MetaDataFields field : MetaDataFields.values()) { metaDataFieldsHashMap.put(field, -1); } primaryStatisticsFieldsHashMap = new HashMap<PrimaryStatisticsFields, Integer>(); for (PrimaryStatisticsFields field : PrimaryStatisticsFields.values()) { primaryStatisticsFieldsHashMap.put(field, -1); } } @Override protected void initComponents() { init = true; initHashMaps(); statsSpreadsheet = null; statisticsCriteriaPanel = new StatisticsCriteriaPanel(getParentDialogContentPane()); final JPanel rightPanel = getRightPanel(); final ImageIcon collapseIcon = UIUtils.loadImageIcon("icons/PanelRight12.png"); final ImageIcon collapseRolloverIcon = ToolButtonFactory.createRolloverIcon(collapseIcon); final ImageIcon expandIcon = UIUtils.loadImageIcon("icons/PanelLeft12.png"); final ImageIcon expandRolloverIcon = ToolButtonFactory.createRolloverIcon(expandIcon); hideAndShowButton = ToolButtonFactory.createButton(collapseIcon, false); hideAndShowButton.setToolTipText("Collapse Options Panel"); hideAndShowButton.setName("switchToChartButton"); hideAndShowButton.addActionListener(new ActionListener() { public boolean rightPanelShown; @Override public void actionPerformed(ActionEvent e) { rightPanel.setVisible(rightPanelShown); if (rightPanelShown) { hideAndShowButton.setIcon(collapseIcon); hideAndShowButton.setRolloverIcon(collapseRolloverIcon); hideAndShowButton.setVisible(true); hideAndShowButton.setToolTipText("Collapse Options Panel"); } else { hideAndShowButton.setIcon(expandIcon); hideAndShowButton.setRolloverIcon(expandRolloverIcon); hideAndShowButton.setVisible(true); hideAndShowButton.setToolTipText("Expand Options Panel"); } rightPanelShown = !rightPanelShown; } }); hideAndShowButton.setVisible(true); contentPanel = new JPanel(new GridLayout(-1, 1)); contentPanel.setBackground(Color.WHITE); contentPanel.addMouseListener(popupHandler); contentScrollPane = new JScrollPane(contentPanel); contentScrollPane.setBorder(null); contentScrollPane.setBackground(Color.WHITE); spreadsheetPanel = new JPanel(new GridLayout(-1, 1)); // spreadsheetPanel.setBackground(Color.WHITE); spreadsheetPanel.addMouseListener(popupHandler); spreadsheetScrollPane = new JScrollPane(spreadsheetPanel); spreadsheetScrollPane.setBorder(null); // spreadsheetScrollPane.setBackground(Color.WHITE); spreadsheetScrollPane.setMinimumSize(new Dimension(100, 100)); spreadsheetScrollPane.setBorder(UIUtils.createGroupBorder("Statistics Spreadsheet")); spreadsheetScrollPane.setVisible(statisticsCriteriaPanel.showStatsSpreadSheet()); leftPanel = new JPanel(new GridBagLayout()); // GridBagConstraints gbcLeftPanel = new GridBagConstraints(); // GridBagUtils.addToPanel(leftPanel, contentScrollPane, gbcLeftPanel, "fill=BOTH, weightx=1.0, weighty=1.0, anchor=NORTHWEST"); // GridBagUtils.addToPanel(leftPanel, spreadsheetScrollPane, gbcLeftPanel, "fill=BOTH, weightx=1.0, weighty=0.0, anchor=NORTHWEST, gridy=1,insets.top=5"); initLeftPanel(); backgroundPanel = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); GridBagUtils.addToPanel(backgroundPanel, leftPanel, gbc, "fill=BOTH, weightx=1.0, weighty=1.0, anchor=NORTHWEST,insets.right=5"); // GridBagUtils.addToPanel(backgroundPanel, contentScrollPane, gbc, "fill=BOTH, weightx=1.0, weighty=1.0, anchor=NORTHWEST"); // GridBagUtils.addToPanel(backgroundPanel, spreadsheetScrollPane, gbc, "fill=BOTH, weightx=1.0, weighty=1.0, anchor=NORTHWEST, gridy=1"); GridBagUtils.addToPanel(backgroundPanel, rightPanel, gbc, "gridx=1,gridy=0, fill=BOTH, weightx=0.0,anchor=NORTHEAST,insets.left=5"); // GridBagUtils.addToPanel(backgroundPanel, spreadsheetScrollPane, gbcLeftPanel, "fill=HORIZONTAL, weightx=1.0, weighty=1.0, anchor=NORTHWEST, gridy=1,gridx=0,gridwidth=2,insets.top=5"); JLayeredPane layeredPane = new JLayeredPane(); layeredPane.add(backgroundPanel, new Integer(0)); layeredPane.add(hideAndShowButton, new Integer(1)); add(layeredPane); int minWidth = leftPanel.getMinimumSize().width + rightPanel.getMinimumSize().width; int minHeight = Math.max(leftPanel.getMinimumSize().height, rightPanel.getMinimumSize().height); setMinimumSize(new Dimension(minWidth, minHeight)); } private JPanel getRightPanel() { computePanel = new MultipleRoiComputePanel(this, getRaster()); final JPanel rightPanel = GridBagUtils.createPanel(); final JPanel mainPane = GridBagUtils.createPanel(); // GridBagConstraints extendedOptionsPanelConstraints = GridBagUtils.createConstraints("anchor=NORTHWEST,fill=HORIZONTAL,insets.top=2,weightx=1,insets.right=-2"); GridBagConstraints extendedOptionsPanelConstraints = GridBagUtils .createConstraints("anchor=NORTHWEST,fill=HORIZONTAL,insets.top=2,weightx=1"); GridBagUtils.addToPanel(rightPanel, computePanel, extendedOptionsPanelConstraints, "gridy=0,fill=NONE,weighty=1,weightx=1"); // GridBagUtils.addToPanel(rightPanel, statisticsCriteriaPanel.getCriteriaFormattingTabbedPane(), extendedOptionsPanelConstraints, "gridy=1,fill=BOTH,weighty=0, insets.top=10"); computePanel.getCriteriaPanel().setBorder(UIUtils.createGroupBorder("")); GridBagUtils.addToPanel(computePanel.getCriteriaPanel(), statisticsCriteriaPanel.getCriteriaPanel(), extendedOptionsPanelConstraints, "insets.top=10, insets.left=5, insets.right=5"); JButton resetToDefaultsButton = new JButton("Reset"); resetToDefaultsButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { statisticsCriteriaPanel.reset(); } }); runButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { computePanel.run(); } }); runButton.setEnabled(getRaster() != null); exportButton = getExportButton(); exportButton.setToolTipText("Export: This only exports the binning portion of the statistics"); exportButton.setVisible(exportButtonVisible); final JPanel exportAndHelpPanel = GridBagUtils.createPanel(); GridBagConstraints helpPanelConstraints = GridBagUtils .createConstraints("anchor=NORTHWEST,fill=HORIZONTAL,insets.top=2,weightx=1,ipadx=0"); GridBagUtils.addToPanel(exportAndHelpPanel, new JSeparator(), helpPanelConstraints, "fill=HORIZONTAL,gridwidth=4,insets.left=5,insets.right=5"); GridBagUtils.addToPanel(exportAndHelpPanel, exportButton, helpPanelConstraints, "gridy=1,anchor=WEST,fill=NONE, gridwidth=1"); GridBagUtils.addToPanel(exportAndHelpPanel, runButton, helpPanelConstraints, "gridx=1, gridy=1,anchor=WEST,fill=NONE"); GridBagUtils.addToPanel(exportAndHelpPanel, resetToDefaultsButton, helpPanelConstraints, "gridx=2, gridy=1,anchor=CENTER,fill=NONE"); GridBagUtils.addToPanel(exportAndHelpPanel, getHelpButton(), helpPanelConstraints, "gridx=3,gridy=1,anchor=EAST,fill=NONE"); GridBagUtils.addToPanel(rightPanel, exportAndHelpPanel, extendedOptionsPanelConstraints, "gridy=2,anchor=SOUTHWEST,fill=HORIZONTAL,weighty=0,insets.top=0"); rightPanel.setMinimumSize(rightPanel.getPreferredSize()); return rightPanel; } @Override protected void updateComponents() { if (!computePanel.isRunning()) { if (computePanel.isRunning()) { if (swingWorker != null) { swingWorker.cancel(true); } computePanel.setRunning(false); } if (!init) { initComponents(); } boolean productChanged = false; boolean rasterChanged = false; if (getProduct() != null) { Product prevProduct = currProduct; currProduct = getProduct(); if (currProduct != null && currProduct != prevProduct) { productChanged = true; fieldsInitialized = false; } } if (getRaster() != null) { RasterDataNode prevRaster = currRaster; currRaster = getRaster(); if (currRaster != null && currRaster != prevRaster) { rasterChanged = true; } } if (!fieldsInitialized || productChanged || (rasterChanged && computePanel.forceUpdate)) { statisticsCriteriaPanel.resetProduct(); statsSpreadsheet = null; final RasterDataNode raster = getRaster(); computePanel.setRaster(raster); runButton.setEnabled(raster != null); contentPanel.removeAll(); spreadsheetPanel.removeAll(); resultText.setLength(0); if (raster != null && raster.isStxSet() && raster.getStx().getResolutionLevel() == 0) { // percentThresholdsList = statisticsCriteriaPanel.getPercentThresholdsList(); // resultText.append(createText(raster.getStx(), null)); contentPanel.add(createStatPanel(raster.getStx(), null, null, 1, getRaster())); PagePanel pagePanel = new StatisticsSpreadsheetPagePanel(parentDialog, helpID, statisticsCriteriaPanel, statsSpreadsheet, this); pagePanel.initComponents(); spreadsheetPanel.add(pagePanel); // spreadsheetPanel.add(statsSpreadsheetPanel()); histograms = new Histogram[] { raster.getStx().getHistogram() }; exportAsCsvAction = new ExportStatisticsAsCsvAction(this); putStatisticsIntoVectorDataAction = new PutStatisticsIntoVectorDataAction(this); exportButton.setEnabled(exportButtonEnabled); } else { contentPanel.add(new JLabel(DEFAULT_STATISTICS_TEXT)); exportButton.setEnabled(false); } contentPanel.revalidate(); contentPanel.repaint(); spreadsheetScrollPane.setVisible(statisticsCriteriaPanel.showStatsSpreadSheet()); spreadsheetPanel.revalidate(); spreadsheetPanel.repaint(); backgroundPanel.revalidate(); backgroundPanel.repaint(); if (raster != null) { exportButton.setEnabled(false); } } } } @Override public Histogram[] getHistograms() { return histograms; } private static class ComputeResult { final Stx stx; final Mask mask; ComputeResult(Stx stx, Mask mask) { this.stx = stx; this.mask = mask; } } @Override public void compute(final Mask[] selectedRegionMasks, final Mask[] selectedQualityMasks, final Band[] selectedBands) { // computePanel.setRunning(true); // System.out.print("Run2\n"); spreadsheetPanel.removeAll(); fixedHistDomainAllPlotsInitialized = false; // todo Danny really this is trying to do isAnotherBand selected it could be renamed and inverted appropriately or maybe gotten rid of if (selectedBands != null && selectedBands.length > 0 && selectedBands[0] != null) { if (selectedBands.length == 1) { if (getRaster() != null) { String rasterName = getRaster().getName(); String selectedBandName = selectedBands[0].getName(); if (rasterName.equals(selectedBandName)) { computePanel.setUseViewBandRaster(true); } else { computePanel.setUseViewBandRaster(false); } } else { computePanel.setUseViewBandRaster(false); } } else { computePanel.setUseViewBandRaster(false); } } else { computePanel.setUseViewBandRaster(true); } fieldsInitialized = true; int numBands = 0; int numRegionMasks = 0; int numQualityMasks = 0; if (computePanel.isUseViewBandRaster()) { numBands = 1; } else { numBands = selectedBands.length; } numQualityMasks = getMasksToProcessCount(selectedQualityMasks, computePanel.isIncludeNoQuality(), computePanel.getQualityMaskGrouping()); numRegionMasks = getMasksToProcessCount(selectedRegionMasks, computePanel.isIncludeFullScene(), computePanel.getRegionalMaskGrouping()); numStxRegions = numBands * numRegionMasks * numQualityMasks; System.out.println("numStxRegions=" + numStxRegions); this.histograms = new Histogram[numStxRegions]; final String title = "Computing Statistics"; if (statisticsCriteriaPanel.getPercentThresholdsList() == null) { abortRun(); return; } statsSpreadsheet = null; // reset this if (!retrieveValidateTextFields(true)) { abortRun(); return; } // just in case: should not get here as it should have been caught earlier if (!validFields()) { JOptionPane.showMessageDialog(getParentDialogContentPane(), "Failed to compute statistics due to invalid fields", "Invalid Input", /*I18N*/ JOptionPane.ERROR_MESSAGE); computePanel.setRunning(false); return; } swingWorker = new ProgressMonitorSwingWorker(this, title) { // SwingWorker<Object, ComputeResult> swingWorker = new ProgressMonitorSwingWorker<Object, ComputeResult>(this, title) { @Override protected Object doInBackground(ProgressMonitor pm) { int numberOfProgressSteps = numStxRegions; if (statisticsCriteriaPanel.includeTotalPixels()) { numberOfProgressSteps = numberOfProgressSteps * 2; // adds additional stx calculation per each stxRegion } pm.beginTask(title, numberOfProgressSteps); Mask[] qualityMasksToProcess = null; Mask[] regionalMasksToProcess = null; try { if (statisticsCriteriaPanel.includeTotalPixels()) { addNoNanBand(getProduct()); } qualityMasksToProcess = getMasksToProcess(selectedQualityMasks, computePanel.getQualityGroupMaskNameTextfield().getText(), computePanel.isIncludeNoQuality(), computePanel.getQualityMaskGrouping()); regionalMasksToProcess = getMasksToProcess(selectedRegionMasks, computePanel.getRegionalGroupMaskNameTextfield().getText(), computePanel.isIncludeFullScene(), computePanel.getRegionalMaskGrouping()); int stxIdx = 0; totalRecordCount = 0; int recordCount = 0; if (computePanel.isUseViewBandRaster()) { RasterDataNode raster = getRaster(); recordCount = computeAllStxForRaster(raster, pm, regionalMasksToProcess, qualityMasksToProcess, stxIdx); stxIdx += recordCount; totalRecordCount += recordCount; } else { for (int rasterIdx = 0; rasterIdx < selectedBands.length; rasterIdx++) { final Band band = selectedBands[rasterIdx]; RasterDataNode raster = getProduct().getRasterDataNode(band.getName()); recordCount = computeAllStxForRaster(raster, pm, regionalMasksToProcess, qualityMasksToProcess, stxIdx); stxIdx += recordCount; totalRecordCount += recordCount; } } } finally { if (statisticsCriteriaPanel.includeTotalPixels()) { removeNoNanBand(getProduct()); } // this deletion of the mask causes code to freeze so currently is not enabled // if (comboQualityMasks != null && comboQualityMasks[0] != null) { // final ProductNodeGroup<Mask> maskGroup = getProduct().getMaskGroup(); // // String[] maskGroupNodeNames = new String[maskGroup.getNodeNames().length]; // int i=0; // for (String name : maskGroup.getNodeNames()) { // maskGroupNodeNames[i] = name; // i++; // } // // for (String name : maskGroupNodeNames) { // if (name.equals(comboQualityMasks[0].getName())) { // maskGroup.remove(maskGroup.get(name)); // } // } // //// for (String name : maskGroup.getNodeNames()) { //// if (name.equals(comboQualityMasks[0].getName())) { //// maskGroup.remove(maskGroup.get(name)); //// } //// } // } updateLeftPanel(); resultText.setLength(0); resultText.append(createText()); pm.done(); } return null; } // todo Danny Testing this // @Override // protected void process(List<ComputeResult> chunks) { // // // // for (ComputeResult result : chunks) { // // final Stx stx = result.stx; // final Mask mask = result.mask; // // if (resultText.length() > 0) { // resultText.append("\n"); // } // resultText.append(createText(stx, mask)); // // JPanel statPanel = createStatPanel(stx, mask, currRow); // contentPanel.add(statPanel); // contentPanel.revalidate(); // contentPanel.repaint(); // backgroundPanel.revalidate(); // backgroundPanel.repaint(); // currRow++; // } // // // } @Override protected void done() { computePanel.setRunning(false); try { if (totalRecordCount == 0) { JOptionPane.showMessageDialog(getParentDialogContentPane(), "No statistics computed.\nMask and/or Full Scene must be selected", /*I18N*/ "Statistics", /*I18N*/ JOptionPane.ERROR_MESSAGE); } // get(); // if (exportAsCsvAction == null) { // exportAsCsvAction = new ExportStatisticsAsCsvAction(StatisticsPanel.this); // } // exportAsCsvAction.setSelectedMasks(selectedMasks); // if (putStatisticsIntoVectorDataAction == null) { // putStatisticsIntoVectorDataAction = new PutStatisticsIntoVectorDataAction(StatisticsPanel.this); // } // putStatisticsIntoVectorDataAction.setSelectedMasks(selectedMasks); // // exportButton.setEnabled(exportButtonEnabled); computePanel.setRunning(false); } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(getParentDialogContentPane(), "Failed to compute statistics.\nAn error occurred:" + e.getMessage(), /*I18N*/ "Statistics", /*I18N*/ JOptionPane.ERROR_MESSAGE); computePanel.setRunning(false); } } }; resultText.setLength(0); contentPanel.removeAll(); // swingWorker.execute(); swingWorker.executeWithBlocking(); } // includes null mask if requested private int getMasksToProcessCount(Mask[] selectedMasks, boolean includeNull, MultipleRoiComputePanel.MaskGrouping maskGrouping) { int masksToProcessCount = 0; if (includeNull) { masksToProcessCount++; } int selectedMasksCount = getSelectMaskCount(selectedMasks); if (getSelectMaskCount(selectedMasks) > 0) { if (maskGrouping == MultipleRoiComputePanel.MaskGrouping.INDIVIDUAL) { masksToProcessCount += selectedMasksCount; } else { masksToProcessCount++; } } return masksToProcessCount; } // includes null mask if requested private Mask[] getMasksToProcess(Mask[] selectedMasks, String maskName, boolean includeNull, MultipleRoiComputePanel.MaskGrouping maskGrouping) { int masksToProcessCount = getMasksToProcessCount(selectedMasks, includeNull, maskGrouping); if (masksToProcessCount == 0) { return null; } Mask[] masksToProcess = new Mask[masksToProcessCount]; int index = 0; if (includeNull) { masksToProcess[index] = null; index++; } if (getSelectMaskCount(selectedMasks) > 0) { if (maskGrouping == MultipleRoiComputePanel.MaskGrouping.INDIVIDUAL) { for (Mask mask : selectedMasks) { if (mask != null) { masksToProcess[index] = mask; index++; } } } else { Mask logicallyCombinedMask = getLogicallyCombinedMask(selectedMasks, maskName, maskGrouping); if (logicallyCombinedMask != null) { masksToProcess[index] = logicallyCombinedMask; } } } return masksToProcess; } private int getSelectMaskCount(Mask[] selectedMasks) { int selectedMasksCount = 0; if (selectedMasks != null) { int length = selectedMasks.length; for (Mask mask : selectedMasks) { if (mask != null) { selectedMasksCount++; } } } return selectedMasksCount; } private Mask getLogicallyCombinedMask(Mask[] selectedMasks, String maskName, MultipleRoiComputePanel.MaskGrouping maskGrouping) { if (selectedMasks == null || maskName == null || maskGrouping == null || getProduct() == null) { return null; } Mask logicallyCombinedMask = null; boolean maskAlreadyExists = false; String combinedMaskExpression = combineMaskExpressions(selectedMasks, maskGrouping, maskName); if (combinedMaskExpression != null && combinedMaskExpression.length() > 0 && getProduct().getMaskGroup() != null) { final ProductNodeGroup<Mask> maskGroup = getProduct().getMaskGroup(); // determine if mask already exists and if it does overwrite it for (String name : maskGroup.getNodeNames()) { if (name != null && name.equals(maskName)) { maskAlreadyExists = true; maskGroup.get(name).getImageConfig().setValue("expression", combinedMaskExpression); logicallyCombinedMask = maskGroup.get(name); } } // if mask did not exist then create it if (!maskAlreadyExists) { logicallyCombinedMask = Mask.BandMathsType.create(maskName, "", getProduct().getSceneRasterWidth(), getProduct().getSceneRasterHeight(), combinedMaskExpression, Color.RED, 0.5); maskGroup.add(logicallyCombinedMask); } } return logicallyCombinedMask; } private int computeAllStxForRaster(RasterDataNode raster, ProgressMonitor pm, final Mask[] regionMasks, final Mask[] qualityMasks, int stxIdx) { int recordCount = 0; if (raster == null || regionMasks == null || qualityMasks == null) { return recordCount; } for (Mask regionMask : regionMasks) { for (Mask qualityMask : qualityMasks) { computeStx(raster, pm, regionMask, qualityMask, stxIdx + recordCount); recordCount++; } } return recordCount; } private int getFullPixelCount(RasterDataNode raster, ProgressMonitor pm, Mask mask) { int pixelCount = -1; final Stx stx; final ProgressMonitor subPm = SubProgressMonitor.create(pm, 1); if (mask != null) { stx = new StxFactory().withRoiMask(mask).create(raster, subPm); } else { stx = new StxFactory().create(raster, subPm); } Histogram histogram = stx.getHistogram(); pixelCount = histogram.getTotals()[0]; return pixelCount; } private String combineMaskExpressions(Mask[] masks, MultipleRoiComputePanel.MaskGrouping maskGrouping, String maskName) { if (masks == null || masks.length == 0) { return null; } ArrayList<String> expressionParts = new ArrayList<String>(); for (Mask mask : masks) { if (mask != null && mask.getName() != null && mask.getName().length() > 0 && !mask.getName().equals(maskName)) { expressionParts.add(mask.getName()); } } String[] expressionPartsArray = new String[expressionParts.size()]; expressionPartsArray = expressionParts.toArray(expressionPartsArray); if (expressionPartsArray.length > 0) { switch (maskGrouping) { case INTERSECTION: return StringUtils.join(expressionPartsArray, " && "); case UNION: return StringUtils.join(expressionPartsArray, " || "); case COMPLEMENT: for (int i = 0; i < expressionPartsArray.length; i++) { expressionPartsArray[i] = "!" + expressionPartsArray[i]; } return StringUtils.join(expressionPartsArray, " && "); default: return null; } } return null; } private Mask combineMasks(Mask[] masks, String maskName, int combinationType, Product product) { ArrayList<String> expressionParts = new ArrayList<String>(); int height = 0; int width = 0; Mask.ImageType imageType = null; for (Mask mask : masks) { if (mask != null && mask.getName() != null && mask.getName().length() > 0) { expressionParts.add(mask.getName()); if (imageType == null) { imageType = mask.getImageType(); } if (height == 0) { height = mask.getRasterHeight(); } if (width == 0) { width = mask.getRasterWidth(); } } } String expression = ""; if (expressionParts.size() > 0) { expression = StringUtils.join(expressionParts, " && "); } // Mask maskCombined = new Mask("CombinedMask", width, height, new Mask.ImageType("Maths")); if (expression != null && expression.length() > 0) { // Mask combinedMask = new Mask("CombinedMask", width, height, imageType); Mask combinedMask = Mask.BandMathsType.create(maskName, "", product.getSceneRasterWidth(), product.getSceneRasterHeight(), expression, Color.RED, 0.5); // combinedMask.updateExpression(combinedMask.getValidMaskExpression(), expression); // combinedMask.setSourceImage(VirtualBand.createVirtualSourceImage(combinedMask, expression)); // combinedMask.setValidPixelExpression(expression); return combinedMask; } else { return null; } } private Mask combineMasksByExpression(Mask mask1, Mask mask2) { ArrayList<String> expressionParts = new ArrayList<String>(); int height = 0; int width = 0; Mask.ImageType imageType = null; if (mask1 != null && mask1.getName() != null && mask1.getName().length() > 0) { expressionParts.add(mask1.getName()); imageType = mask1.getImageType(); height = mask1.getRasterHeight(); width = mask1.getRasterWidth(); } if (mask2 != null && mask2.getName() != null && mask2.getName().length() > 0) { expressionParts.add(mask2.getName()); imageType = mask2.getImageType(); height = mask2.getRasterHeight(); width = mask2.getRasterWidth(); } String expression = ""; if (expressionParts.size() > 0) { expression = StringUtils.join(expressionParts, " && "); } // Mask maskCombined = new Mask("CombinedMask", width, height, new Mask.ImageType("Maths")); if (expression != null && expression.length() > 0) { return new Mask("CombinedMask", width, height, imageType); } else { return null; } } private String getValidPixelExpressionWithQualityMask(String validPixExp, Mask qualityMask) { ArrayList<String> expressionParts = new ArrayList<String>(); if (validPixExp != null && validPixExp.length() > 0) { expressionParts.add(validPixExp); } if (qualityMask != null && qualityMask.getImageConfig() != null && qualityMask.getImageConfig().getValue("expression") != null) { // expressionParts.add(qualityMask.getName()); expressionParts.add(qualityMask.getImageConfig().getValue("expression").toString()); } if (expressionParts.size() > 0) { return StringUtils.join(expressionParts, " && "); } else { return ""; } } private void computeStx(RasterDataNode raster, ProgressMonitor pm, Mask regionMask, Mask qualityMask, int stxIdx) { final Stx stx; final ProgressMonitor subPm = SubProgressMonitor.create(pm, 1); String initialValidPixExp = raster.getValidPixelExpression(); String newValidPixExp = getValidPixelExpressionWithQualityMask(initialValidPixExp, qualityMask); // todo this triggers Errors due to node listening raster.setValidPixelExpression(newValidPixExp); if (regionMask != null) { stx = new StxFactory().withHistogramBinCount(statisticsCriteriaPanel.getNumBins()) .withLogHistogram(statisticsCriteriaPanel.isLogMode()) .withMedian(statisticsCriteriaPanel.includeMedian()) .withBinMin(statisticsCriteriaPanel.getBinMin()).withBinMax(statisticsCriteriaPanel.getBinMax()) .withBinWidth(statisticsCriteriaPanel.getBinWidth()).withRoiMask(regionMask) .create(raster, subPm); } else { stx = new StxFactory().withHistogramBinCount(statisticsCriteriaPanel.getNumBins()) .withLogHistogram(statisticsCriteriaPanel.isLogMode()) .withMedian(statisticsCriteriaPanel.includeMedian()) .withBinMin(statisticsCriteriaPanel.getBinMin()).withBinMax(statisticsCriteriaPanel.getBinMax()) .withBinWidth(statisticsCriteriaPanel.getBinWidth()).create(raster, subPm); } histograms[stxIdx] = stx.getHistogram(); // todo this triggers Errors due to node listening if (statisticsCriteriaPanel.includeTotalPixels()) { addRawTotalToStx(raster, pm, regionMask, stx); } // publish(new ComputeResult(stx1, null)); JPanel statPanel = createStatPanel(stx, regionMask, qualityMask, stxIdx, raster); contentPanel.add(statPanel); updateLeftPanel(); // todo this triggers Errors due to node listening raster.setValidPixelExpression(initialValidPixExp); } // todo Danny creates a band with no no-data in order to get full pixel count // private void addRawTotalToStx(RasterDataNode raster, ProgressMonitor pm, Mask mask, Stx stx) { // Product prod = raster.getProduct(); // final int width = prod.getSceneRasterWidth(); // final int height = prod.getSceneRasterHeight(); // // String tmp = raster.getName() + "_tmpBand"; // Band band = new Band(tmp, ProductData.TYPE_FLOAT32, width, height); // prod.addBand(band); // band.setSourceImage(VirtualBand.createVirtualSourceImage(band, "1")); // RasterDataNode fullRaster = prod.getRasterDataNode(band.getName()); // int fullPixelCount = getFullPixelCount(fullRaster, pm, mask); // prod.removeBand(band); // stx.setRawTotal(fullPixelCount); // } // todo Danny creates a band with no no-data in order to get full pixel count private void addRawTotalToStx(RasterDataNode raster, ProgressMonitor pm, Mask mask, Stx stx) { if (raster != null) { Product prod = raster.getProduct(); if (prod != null) { // addNoNanBand(prod); if (noNanBandRaster != null) { int fullPixelCount = getFullPixelCount(noNanBandRaster, pm, mask); stx.setRawTotal(fullPixelCount); // removeNoNanBand(prod); } } } } // todo Danny creates a band with no no-data in order to get full pixel count private void addNoNanBand(RasterDataNode raster) { if (raster != null) { Product prod = raster.getProduct(); if (prod != null) { final int width = prod.getSceneRasterWidth(); final int height = prod.getSceneRasterHeight(); Band band = new Band(NO_NAN_BANDNAME, ProductData.TYPE_FLOAT32, width, height); if (band != null) { prod.addBand(band); band.setSourceImage(VirtualBand.createVirtualSourceImage(band, "1")); noNanBandRaster = prod.getRasterDataNode(band.getName()); } } } } // todo Danny creates a band with no no-data in order to get full pixel count private void addNoNanBand(Product prod) { if (prod != null) { final int width = prod.getSceneRasterWidth(); final int height = prod.getSceneRasterHeight(); Band band = new Band(NO_NAN_BANDNAME, ProductData.TYPE_FLOAT32, width, height); if (band != null) { prod.addBand(band); band.setSourceImage(VirtualBand.createVirtualSourceImage(band, "1")); noNanBandRaster = prod.getRasterDataNode(band.getName()); } } } // todo Danny delete band with no no-data private void removeNoNanBand(RasterDataNode raster) { if (raster != null) { Product prod = raster.getProduct(); if (prod != null && noNanBandRaster != null) { Band band = prod.getBand(noNanBandRaster.getName()); if (band != null) { prod.removeBand(band); } } } } // todo Danny delete band with no no-data private void removeNoNanBand(Product prod) { if (prod != null && noNanBandRaster != null) { Band band = prod.getBand(noNanBandRaster.getName()); if (band != null) { prod.removeBand(band); } } } private void abortRun() { initLeftPanel(); fixedHistDomainAllPlotsInitialized = false; computePanel.setRunning(false); } private void initLeftPanel() { leftPanel.removeAll(); leftPanel.add(new JLabel(DEFAULT_STATISTICS_TEXT)); leftPanel.revalidate(); leftPanel.repaint(); // leftPanel.setBackground(Color.WHITE); fixedHistDomainAllPlotsInitialized = false; } private void updateLeftPanel() { PagePanel pagePanel = new StatisticsSpreadsheetPagePanel(parentDialog, helpID, statisticsCriteriaPanel, statsSpreadsheet, this); pagePanel.initComponents(); spreadsheetPanel.removeAll(); // JPanel statsSpeadPanel = statsSpreadsheetPanel(); // spreadsheetPanel.add(statsSpeadPanel); spreadsheetPanel.add(pagePanel); // spreadsheetPanel.setBackground(Color.WHITE); spreadsheetScrollPane.setVisible(statisticsCriteriaPanel.showStatsSpreadSheet()); spreadsheetScrollPane.setMinimumSize(new Dimension(100, 100)); leftPanel.removeAll(); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridy = 0; gbc.gridx = 0; gbc.anchor = GridBagConstraints.NORTHWEST; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.weighty = 1.0; // histogramPanel.setVisible(showHistogramPlots); if (statisticsCriteriaPanel.showPercentPlots() || statisticsCriteriaPanel.showHistogramPlots() || statisticsCriteriaPanel.showStatsList()) { if ((numStxRegions + 1) > spreadsheetMinRowsBeforeWeight) { gbc.weighty = 1.0 - spreadsheetHeightWeight; leftPanel.add(contentScrollPane, gbc); gbc.fill = GridBagConstraints.BOTH; gbc.weighty = spreadsheetHeightWeight; } else { leftPanel.add(contentScrollPane, gbc); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weighty = 0; int buffer = 50; int minHeight = spreadsheetPanel.getPreferredSize().height + buffer; spreadsheetScrollPane.setMinimumSize(new Dimension(100, minHeight)); } gbc.gridy += 1; gbc.insets.top = 10; } else { gbc.fill = GridBagConstraints.BOTH; gbc.weighty = 1.0; } if (statisticsCriteriaPanel.showStatsSpreadSheet()) { leftPanel.add(spreadsheetScrollPane, gbc); } // gbc.gridy += 1; // leftPanel.add(pagePanel, gbc); leftPanel.revalidate(); leftPanel.repaint(); contentPanel.revalidate(); contentPanel.repaint(); backgroundPanel.revalidate(); backgroundPanel.repaint(); } private JPanel createStatPanel(Stx stx, final Mask regionalMask, final Mask qualityMask, int stxIdx, RasterDataNode raster) { final Histogram histogram = stx.getHistogram(); final int row = stxIdx + 1; // account for header boolean includeFileMetaData = statisticsCriteriaPanel.isIncludeFileMetaData(); boolean includeMaskMetaData = statisticsCriteriaPanel.isIncludeMaskMetaData(); boolean includeBandMetaData = statisticsCriteriaPanel.isIncludeBandMetaData(); boolean includeBinningInfo = statisticsCriteriaPanel.isIncludeBinningInfo(); ; boolean includeTimeMetaData = statisticsCriteriaPanel.isIncludeTimeMetaData(); boolean isIncludeTimeSeriesMetaData = statisticsCriteriaPanel.isIncludeTimeSeriesMetaData(); boolean includeProjectionParameters = statisticsCriteriaPanel.isIncludeProjectionParameters(); boolean includeColumnBreaks = statisticsCriteriaPanel.isIncludeColBreaks(); // Initialize all spreadsheet table indices to -1 (default don't use value) if (stxIdx == 0 || metaDataFieldsHashMap == null || primaryStatisticsFieldsHashMap == null) { initHashMaps(); } XIntervalSeries histogramSeries = new XIntervalSeries("Histogram"); double histDomainBounds[] = { histogram.getLowValue(0), histogram.getHighValue(0) }; double histRangeBounds[] = { Double.NaN, Double.NaN }; if (!fixedHistDomainAllPlots || (fixedHistDomainAllPlots && !fixedHistDomainAllPlotsInitialized)) { if (!statisticsCriteriaPanel.isLogMode()) { if (statisticsCriteriaPanel.plotsThreshDomainSpan()) { if (statisticsCriteriaPanel.plotsThreshDomainLow() >= 0.1) { histDomainBounds[0] = histogram .getPTileThreshold((statisticsCriteriaPanel.plotsThreshDomainLow()) / 100)[0]; } if (statisticsCriteriaPanel.plotsThreshDomainHigh() <= 99.9) { histDomainBounds[1] = histogram .getPTileThreshold(statisticsCriteriaPanel.plotsThreshDomainHigh() / 100)[0]; } } else if (statisticsCriteriaPanel.plotsDomainSpan()) { if (!Double.isNaN(statisticsCriteriaPanel.plotsDomainLow())) { histDomainBounds[0] = statisticsCriteriaPanel.plotsDomainLow(); } if (!Double.isNaN(statisticsCriteriaPanel.plotsDomainHigh())) { histDomainBounds[1] = statisticsCriteriaPanel.plotsDomainHigh(); } } } else { histDomainBounds[0] = histogram.getBinLowValue(0, 0); histDomainBounds[1] = histogram.getHighValue(0); } // if (!LogMode && plotsThreshDomainSpan && plotsThreshDomainLow >= 0.1 && plotsThreshDomainHigh <= 99.9) { // histDomainBounds[0] = histogram.getPTileThreshold((plotsThreshDomainLow) / 100)[0]; // histDomainBounds[1] = histogram.getPTileThreshold(plotsThreshDomainHigh / 100)[0]; // // } else { // histDomainBounds[0] = histogram.getBinLowValue(0, 0); // histDomainBounds[1] = histogram.getHighValue(0); // } if (fixedHistDomainAllPlots && !fixedHistDomainAllPlotsInitialized) { histDomainBoundsAllPlots[0] = histDomainBounds[0]; histDomainBoundsAllPlots[1] = histDomainBounds[1]; fixedHistDomainAllPlotsInitialized = true; } } else { histDomainBounds[0] = histDomainBoundsAllPlots[0]; histDomainBounds[1] = histDomainBoundsAllPlots[1]; } int[] bins = histogram.getBins(0); for (int j = 0; j < bins.length; j++) { histogramSeries.add(histogram.getBinLowValue(0, j), histogram.getBinLowValue(0, j), j < bins.length - 1 ? histogram.getBinLowValue(0, j + 1) : histogram.getHighValue(0), bins[j]); } String logTitle = (statisticsCriteriaPanel.isLogMode()) ? "Log10 of " : ""; ChartPanel histogramPanel = createChartPanel(histogramSeries, logTitle + raster.getName() + " (" + raster.getUnit() + ")", "Frequency in #Pixels", new Color(0, 0, 127), histDomainBounds, histRangeBounds); // histogramPanel.setPreferredSize(new Dimension(300, 200)); if (statisticsCriteriaPanel.exactPlotSize()) { histogramPanel.setMinimumSize(new Dimension(statisticsCriteriaPanel.plotSizeWidth(), statisticsCriteriaPanel.plotSizeHeight())); histogramPanel.setPreferredSize(new Dimension(statisticsCriteriaPanel.plotSizeWidth(), statisticsCriteriaPanel.plotSizeHeight())); histogramPanel.setMaximumSize(new Dimension(statisticsCriteriaPanel.plotSizeWidth(), statisticsCriteriaPanel.plotSizeHeight())); } else { histogramPanel.setMinimumSize(new Dimension(plotMinWidth, plotMinHeight)); histogramPanel.setPreferredSize(new Dimension(plotMinWidth, plotMinHeight)); } XIntervalSeries percentileSeries = new XIntervalSeries("Percentile"); // if (1 == 2 && LogMode) { // percentileSeries.add(0, // 0, // 1, // Math.pow(10, histogram.getLowValue(0))); // for (int j = 1; j < 99; j++) { // percentileSeries.add(j, // j, // j + 1, // Math.pow(10, histogram.getPTileThreshold(j / 100.0)[0])); // } // percentileSeries.add(99, // 99, // 100, // Math.pow(10, histogram.getHighValue(0))); // // } else { // percentileSeries.add(0, // 0, // 0.25, // histogram.getLowValue(0)); // // for (double j = 0.25; j < 99.75; j += .25) { // percentileSeries.add(j, // j, // j + 1, // histogram.getPTileThreshold(j / 100.0)[0]); // } // percentileSeries.add(99.75, // 99.75, // 100, // histogram.getHighValue(0)); // } // // double fraction = 0; // for (int j = 0; j < bins.length; j++) { // // fraction = (1.0) * j / bins.length; // // if (fraction > 0 && fraction < 1) { // percentileSeries.add(histogram.getBinLowValue(0, j), // histogram.getBinLowValue(0, j), // j < bins.length - 1 ? histogram.getBinLowValue(0, j + 1) : histogram.getHighValue(0), // histogram.getPTileThreshold(fraction)[0]); // } // // // } // // double test = fraction; double[] percentileDomainBounds = { Double.NaN, Double.NaN }; double[] percentileRangeBounds = { Double.NaN, Double.NaN }; ChartPanel percentilePanel = null; if (invertPercentile) { double increment = .01; for (double j = 0; j < 100; j += increment) { double fraction = j / 100.0; double nextFraction = (j + increment) / 100.0; if (fraction > 0.0 && fraction < 1.0 && nextFraction > 0.0 && nextFraction < 1.0) { double thresh = histogram.getPTileThreshold(fraction)[0]; double nextThresh = histogram.getPTileThreshold(nextFraction)[0]; percentileSeries.add(thresh, thresh, nextThresh, j); } } if (!statisticsCriteriaPanel.isLogMode()) { percentileDomainBounds[0] = histDomainBounds[0]; percentileDomainBounds[1] = histDomainBounds[1]; } percentileRangeBounds[0] = 0; percentileRangeBounds[1] = 100; percentilePanel = createScatterChartPanel(percentileSeries, logTitle + raster.getName() + " (" + raster.getUnit() + ")", "Percent Threshold", new Color(0, 0, 0), percentileDomainBounds, percentileRangeBounds); } else { percentileSeries.add(0, 0, 0.25, histogram.getLowValue(0)); for (double j = 0.25; j < 99.75; j += .25) { percentileSeries.add(j, j, j + 1, histogram.getPTileThreshold(j / 100.0)[0]); } percentileSeries.add(99.75, 99.75, 100, histogram.getHighValue(0)); percentileDomainBounds[0] = 0; percentileDomainBounds[1] = 100; percentileRangeBounds[0] = histDomainBounds[0]; percentileRangeBounds[1] = histDomainBounds[1]; percentilePanel = createScatterChartPanel(percentileSeries, "Percent_Threshold", logTitle + raster.getName() + " (" + raster.getUnit() + ")", new Color(0, 0, 0), percentileDomainBounds, percentileRangeBounds); } // percentilePanel.setPreferredSize(new Dimension(300, 200)); if (statisticsCriteriaPanel.exactPlotSize()) { percentilePanel.setMinimumSize(new Dimension(statisticsCriteriaPanel.plotSizeWidth(), statisticsCriteriaPanel.plotSizeHeight())); percentilePanel.setPreferredSize(new Dimension(statisticsCriteriaPanel.plotSizeWidth(), statisticsCriteriaPanel.plotSizeHeight())); percentilePanel.setMaximumSize(new Dimension(statisticsCriteriaPanel.plotSizeWidth(), statisticsCriteriaPanel.plotSizeHeight())); } else { percentilePanel.setMinimumSize(new Dimension(plotMinWidth, plotMinHeight)); percentilePanel.setPreferredSize(new Dimension(plotMinWidth, plotMinHeight)); } int size = raster.getRasterHeight() * raster.getRasterWidth(); int validPixelCount = histogram.getTotals()[0]; int dataRows = 0; // new Object[]{"RasterSize(Pixels)", size}, // new Object[]{"SampleSize(Pixels)", histogram.getTotals()[0]}, Object[][] totalPixels = null; if (statisticsCriteriaPanel.includeTotalPixels()) { int totalPixelCount = stx.getRawTotal(); double percentFilled = (totalPixelCount > 0) ? (1.0 * validPixelCount / totalPixelCount) : 0; totalPixels = new Object[][] { new Object[] { "Regional_Pixels", stx.getRawTotal() }, new Object[] { "Valid_Pixels", validPixelCount }, new Object[] { "Fraction_Valid", percentFilled } }; } else { totalPixels = new Object[][] { new Object[] { "Valid_Pixels", validPixelCount } }; } dataRows += totalPixels.length; Object[][] firstData = new Object[][] { new Object[] { "Mean", stx.getMean() } }; dataRows += firstData.length; Object[][] minMaxData = null; if (statisticsCriteriaPanel.includeMinMax()) { minMaxData = new Object[][] { new Object[] { "Minimum", stx.getMinimum() }, new Object[] { "Maximum", stx.getMaximum() } }; dataRows += minMaxData.length; } Object[] medianObject = null; if (statisticsCriteriaPanel.includeMedian()) { medianObject = new Object[] { "Median", stx.getMedianRaster() }; dataRows++; } Object[][] secondData = new Object[][] { new Object[] { "Standard_Deviation", stx.getStandardDeviation() }, new Object[] { "Variance", getVariance(stx) }, new Object[] { "Coefficient_of_Variation", getCoefficientOfVariation(stx) } }; dataRows += secondData.length; Object[][] binningInfo = null; if (statisticsCriteriaPanel.isIncludeBinningInfo()) { binningInfo = new Object[][] { new Object[] { "Total_Bins", histogram.getNumBins()[0] }, new Object[] { "Bin_Width", getBinSize(histogram) }, new Object[] { "Bin_Min", histogram.getLowValue(0) }, new Object[] { "Bin_Max", histogram.getHighValue(0) } }; dataRows += binningInfo.length; } Object[][] histogramStats = null; if (statisticsCriteriaPanel.includeHistogramStats()) { if (statisticsCriteriaPanel.isLogMode()) { histogramStats = new Object[][] { new Object[] { "Mean(LogBinned)", Math.pow(10, histogram.getMean()[0]) }, new Object[] { "Median(LogBinned)", Math.pow(10, stx.getMedian()) }, new Object[] { "StandardDeviation(LogBinned)", Math.pow(10, histogram.getStandardDeviation()[0]) } }; } else { histogramStats = new Object[][] { new Object[] { "Mean(Binned)", histogram.getMean()[0] }, new Object[] { "Median(Binned)", stx.getMedian() }, new Object[] { "StandardDeviation(Binned)", histogram.getStandardDeviation()[0] } }; } dataRows += histogramStats.length; } Object[][] percentData = new Object[statisticsCriteriaPanel.getPercentThresholdsList().size()][]; for (int i = 0; i < statisticsCriteriaPanel.getPercentThresholdsList().size(); i++) { int value = statisticsCriteriaPanel.getPercentThresholdsList().get(i); double percent = value / 100.0; String percentString = Integer.toString(value); Object[] pTileThreshold; if (statisticsCriteriaPanel.isLogMode()) { pTileThreshold = new Object[] { percentString + "%Threshold(Log)", Math.pow(10, histogram.getPTileThreshold(percent)[0]) }; } else { pTileThreshold = new Object[] { percentString + "%Threshold", histogram.getPTileThreshold(percent)[0] }; } percentData[i] = pTileThreshold; } dataRows += percentData.length; Object[][] tableData = new Object[dataRows][]; int tableDataIdx = 0; if (totalPixels != null) { for (int i = 0; i < totalPixels.length; i++) { tableData[tableDataIdx] = totalPixels[i]; tableDataIdx++; } } if (firstData != null) { for (int i = 0; i < firstData.length; i++) { tableData[tableDataIdx] = firstData[i]; tableDataIdx++; } } if (medianObject != null) { tableData[tableDataIdx] = medianObject; tableDataIdx++; } if (minMaxData != null) { for (int i = 0; i < minMaxData.length; i++) { tableData[tableDataIdx] = minMaxData[i]; tableDataIdx++; } } if (secondData != null) { for (int i = 0; i < secondData.length; i++) { tableData[tableDataIdx] = secondData[i]; tableDataIdx++; } } if (binningInfo != null) { for (int i = 0; i < binningInfo.length; i++) { tableData[tableDataIdx] = binningInfo[i]; tableDataIdx++; } } if (histogramStats != null) { for (int i = 0; i < histogramStats.length; i++) { tableData[tableDataIdx] = histogramStats[i]; tableDataIdx++; } } if (percentData != null) { for (int i = 0; i < percentData.length; i++) { tableData[tableDataIdx] = percentData[i]; tableDataIdx++; } } numStxFields = tableData.length; int fieldIdx = 0; // Initialize indices if (stxIdx == 0) { primaryStatisticsFieldsHashMap.put(PrimaryStatisticsFields.FileRefNum, fieldIdx); fieldIdx++; primaryStatisticsFieldsHashMap.put(PrimaryStatisticsFields.BandName, fieldIdx); fieldIdx++; primaryStatisticsFieldsHashMap.put(PrimaryStatisticsFields.MaskName, fieldIdx); fieldIdx++; primaryStatisticsFieldsHashMap.put(PrimaryStatisticsFields.QualityMaskName, fieldIdx); fieldIdx++; stxFieldsStartIdx = fieldIdx; fieldIdx += numStxFields; stxFieldsEndIdx = fieldIdx - 1; if (includeBandMetaData) { if (includeColumnBreaks) { metaDataFieldsHashMap.put(MetaDataFields.BandMetaDataBreak, fieldIdx); fieldIdx++; } metaDataFieldsHashMap.put(MetaDataFields.BandName, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.BandUnit, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.BandValidExpression, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.BandDescription, fieldIdx); fieldIdx++; } if (includeMaskMetaData) { if (includeColumnBreaks) { metaDataFieldsHashMap.put(MetaDataFields.RegionalMaskMetaDataBreak, fieldIdx); fieldIdx++; } metaDataFieldsHashMap.put(MetaDataFields.RegionalMaskName, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.RegionalMaskDescription, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.RegionalMaskExpression, fieldIdx); fieldIdx++; if (includeColumnBreaks) { metaDataFieldsHashMap.put(MetaDataFields.QualityMaskMetaDataBreak, fieldIdx); fieldIdx++; } metaDataFieldsHashMap.put(MetaDataFields.QualityMaskName, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.QualityMaskDescription, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.QualityMaskExpression, fieldIdx); fieldIdx++; } if (includeTimeMetaData || isIncludeTimeSeriesMetaData) { if (includeColumnBreaks) { metaDataFieldsHashMap.put(MetaDataFields.TimeMetaDataBreak, fieldIdx); fieldIdx++; } if (includeTimeMetaData) { metaDataFieldsHashMap.put(MetaDataFields.StartDate, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.StartTime, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.EndDate, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.EndTime, fieldIdx); fieldIdx++; } if (isIncludeTimeSeriesMetaData) { metaDataFieldsHashMap.put(MetaDataFields.TimeSeriesDate, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.TimeSeriesTime, fieldIdx); fieldIdx++; } } if (includeFileMetaData) { if (includeColumnBreaks) { metaDataFieldsHashMap.put(MetaDataFields.FileMetaDataBreak, fieldIdx); fieldIdx++; } metaDataFieldsHashMap.put(MetaDataFields.FileName, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.FileType, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.FileFormat, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.FileWidth, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.FileHeight, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.Sensor, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.Platform, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.Resolution, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.DayNight, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.Orbit, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.ProcessingVersion, fieldIdx); fieldIdx++; metaDataFieldsHashMap.put(MetaDataFields.Projection, fieldIdx); fieldIdx++; } if (includeProjectionParameters) { metaDataFieldsHashMap.put(MetaDataFields.ProjectionParameters, fieldIdx); fieldIdx++; } } if (statsSpreadsheet == null) { statsSpreadsheet = new Object[numStxRegions + 2][fieldIdx]; // add 1 row to account for the header and 1 more empty row because JTable for some reason displays // only half of the last row when row count is large } String startDateString = ""; String startTimeString = ""; String endDateString = ""; String endTimeString = ""; if (includeTimeMetaData) { ProductData.UTC startDateTimeCorrected; ProductData.UTC endDateTimeCorrected; // correct time (invert start and end time if end time later than start time if (getProduct().getStartTime() != null && getProduct().getEndTime() != null) { if (getProduct().getStartTime().getMJD() <= getProduct().getEndTime().getMJD()) { startDateTimeCorrected = getProduct().getStartTime(); endDateTimeCorrected = getProduct().getEndTime(); } else { startDateTimeCorrected = getProduct().getEndTime(); endDateTimeCorrected = getProduct().getStartTime(); } if (startDateTimeCorrected != null) { String[] startDateTimeStringArray = startDateTimeCorrected.toString().split(" "); if (startDateTimeStringArray.length >= 2) { startDateString = startDateTimeStringArray[0].trim(); startTimeString = startDateTimeStringArray[1].trim(); } } if (endDateTimeCorrected != null) { String[] endDateTimeStringArray = endDateTimeCorrected.toString().split(" "); if (endDateTimeStringArray.length >= 2) { endDateString = endDateTimeStringArray[0].trim(); endTimeString = endDateTimeStringArray[1].trim(); } } } } String timeSeriesDate = ""; String timeSeriesTime = ""; if (isIncludeTimeSeriesMetaData) { String bandName = raster.getName(); String productDateTime = convertBandNameToProductTime(bandName); if (productDateTime != null) { String[] endDateTimeStringArray = productDateTime.split(" "); if (endDateTimeStringArray.length >= 2) { timeSeriesDate = endDateTimeStringArray[0].trim(); timeSeriesTime = endDateTimeStringArray[1].trim(); } } } String maskName = ""; String maskDescription = ""; String maskExpression = ""; if (regionalMask != null) { maskName = regionalMask.getName(); maskDescription = regionalMask.getDescription(); maskExpression = regionalMask.getImageConfig().getValue("expression"); } String qualityMaskName = ""; String qualityMaskDescription = ""; String qualityMaskExpression = ""; if (qualityMask != null) { qualityMaskName = qualityMask.getName(); qualityMaskDescription = qualityMask.getDescription(); qualityMaskExpression = qualityMask.getImageConfig().getValue("expression"); } addFieldToSpreadsheet(row, PrimaryStatisticsFields.FileRefNum, getProduct().getRefNo()); addFieldToSpreadsheet(row, PrimaryStatisticsFields.BandName, raster.getName()); addFieldToSpreadsheet(row, PrimaryStatisticsFields.MaskName, maskName); addFieldToSpreadsheet(row, PrimaryStatisticsFields.QualityMaskName, qualityMaskName); addFieldToSpreadsheet(row, MetaDataFields.TimeMetaDataBreak, COLUMN_BREAK); addFieldToSpreadsheet(row, MetaDataFields.StartDate, startDateString); addFieldToSpreadsheet(row, MetaDataFields.StartTime, startTimeString); addFieldToSpreadsheet(row, MetaDataFields.EndDate, endDateString); addFieldToSpreadsheet(row, MetaDataFields.EndTime, endTimeString); addFieldToSpreadsheet(row, MetaDataFields.TimeSeriesDate, timeSeriesDate); addFieldToSpreadsheet(row, MetaDataFields.TimeSeriesTime, timeSeriesTime); addFieldToSpreadsheet(row, MetaDataFields.FileMetaDataBreak, COLUMN_BREAK); addFieldToSpreadsheet(row, MetaDataFields.FileName, getProduct().getName()); addFieldToSpreadsheet(row, MetaDataFields.FileType, getProduct().getProductType()); addFieldToSpreadsheet(row, MetaDataFields.FileWidth, getProduct().getSceneRasterWidth()); addFieldToSpreadsheet(row, MetaDataFields.FileFormat, getProductFormatName(getProduct())); addFieldToSpreadsheet(row, MetaDataFields.FileHeight, getProduct().getSceneRasterHeight()); addFieldToSpreadsheet(row, MetaDataFields.Sensor, ProductUtils.getMetaData(getProduct(), ProductUtils.METADATA_POSSIBLE_SENSOR_KEYS)); addFieldToSpreadsheet(row, MetaDataFields.Platform, ProductUtils.getMetaData(getProduct(), ProductUtils.METADATA_POSSIBLE_PLATFORM_KEYS)); addFieldToSpreadsheet(row, MetaDataFields.Resolution, ProductUtils.getMetaData(getProduct(), ProductUtils.METADATA_POSSIBLE_RESOLUTION_KEYS)); addFieldToSpreadsheet(row, MetaDataFields.DayNight, ProductUtils.getMetaData(getProduct(), ProductUtils.METADATA_POSSIBLE_DAY_NIGHT_KEYS)); addFieldToSpreadsheet(row, MetaDataFields.Orbit, ProductUtils.getMetaDataOrbit(getProduct())); addFieldToSpreadsheet(row, MetaDataFields.ProcessingVersion, ProductUtils.getMetaData(getProduct(), ProductUtils.METADATA_POSSIBLE_PROCESSING_VERSION_KEYS)); // Determine projection String projection = ""; String projectionParameters = ""; GeoCoding geo = getProduct().getGeoCoding(); // determine if using class CrsGeoCoding otherwise display class if (geo != null) { if (geo instanceof CrsGeoCoding) { projection = geo.getMapCRS().getName().toString() + "(obtained from CrsGeoCoding)"; projectionParameters = geo.getMapCRS().toString().replaceAll("\n", " ").replaceAll(" ", ""); } else if (geo.toString() != null) { String projectionFromMetaData = ProductUtils.getMetaData(getProduct(), ProductUtils.METADATA_POSSIBLE_PROJECTION_KEYS); if (projectionFromMetaData != null && projectionFromMetaData.length() > 0) { projection = projectionFromMetaData + "(obtained from MetaData)"; } else { projection = "unknown (" + geo.getClass().toString() + ")"; } } } addFieldToSpreadsheet(row, MetaDataFields.Projection, projection); addFieldToSpreadsheet(row, MetaDataFields.ProjectionParameters, projectionParameters); addFieldToSpreadsheet(row, MetaDataFields.BandMetaDataBreak, COLUMN_BREAK); addFieldToSpreadsheet(row, MetaDataFields.BandName, raster.getName()); addFieldToSpreadsheet(row, MetaDataFields.BandUnit, raster.getUnit()); addFieldToSpreadsheet(row, MetaDataFields.BandValidExpression, raster.getValidPixelExpression()); addFieldToSpreadsheet(row, MetaDataFields.BandDescription, raster.getDescription()); addFieldToSpreadsheet(row, MetaDataFields.RegionalMaskMetaDataBreak, COLUMN_BREAK); addFieldToSpreadsheet(row, MetaDataFields.RegionalMaskName, maskName); addFieldToSpreadsheet(row, MetaDataFields.RegionalMaskDescription, maskDescription); addFieldToSpreadsheet(row, MetaDataFields.RegionalMaskExpression, maskExpression); addFieldToSpreadsheet(row, MetaDataFields.QualityMaskMetaDataBreak, COLUMN_BREAK); addFieldToSpreadsheet(row, MetaDataFields.QualityMaskName, qualityMaskName); addFieldToSpreadsheet(row, MetaDataFields.QualityMaskDescription, qualityMaskDescription); addFieldToSpreadsheet(row, MetaDataFields.QualityMaskExpression, qualityMaskExpression); // Add Header first time through if (row <= 1) { int k = stxFieldsStartIdx; for (int i = 0; i < tableData.length; i++) { Object value = tableData[i][0]; if (k < statsSpreadsheet[0].length && k <= stxFieldsEndIdx) { statsSpreadsheet[0][k] = value; k++; } } } // account for header as added row if (row < statsSpreadsheet.length) { int k = stxFieldsStartIdx; for (int i = 0; i < tableData.length; i++) { Object value = tableData[i][1]; if (k < statsSpreadsheet[row].length && k <= stxFieldsEndIdx) { statsSpreadsheet[row][k] = value; k++; } } } int numPlots = 0; if (statisticsCriteriaPanel.showPercentPlots()) { numPlots++; } if (statisticsCriteriaPanel.showHistogramPlots()) { numPlots++; } JPanel plotContainerPanel = null; if (numPlots > 0) { plotContainerPanel = new JPanel(new GridLayout(1, numPlots)); if (statisticsCriteriaPanel.showHistogramPlots()) { plotContainerPanel.add(histogramPanel); } if (statisticsCriteriaPanel.showPercentPlots()) { plotContainerPanel.add(percentilePanel); } } TableModel tableModel = new DefaultTableModel(tableData, new String[] { "Name", "Value" }) { @Override public Class<?> getColumnClass(int columnIndex) { return columnIndex == 0 ? String.class : Number.class; } @Override public boolean isCellEditable(int row, int column) { return false; } }; final JTable table = new JTable(tableModel); table.setDefaultRenderer(Number.class, new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { final Component label = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (value instanceof Float || value instanceof Double) { setHorizontalTextPosition(RIGHT); setText(getFormattedValue((Number) value)); } return label; } private String getFormattedValue(Number value) { if (value.doubleValue() < 0.001 && value.doubleValue() > -0.001 && value.doubleValue() != 0.0) { return new DecimalFormat("0.####E0").format(value.doubleValue()); } String format = "%." + Integer.toString(statisticsCriteriaPanel.decimalPlaces()) + "f"; return String.format(format, value.doubleValue()); } }); table.addMouseListener(popupHandler); // TEST CODE generically preferred size of each column based on longest expected entry // fails a bit because decimal formatting is not captured // stub of code commented out in case we want to make it work // meanwhile longest entry is being used SEE below // int column0Length = 0; // int column1Length = 0; // FontMetrics fm = table.getFontMetrics(table.getFont()); // for (int rowIndex = 0; rowIndex < table.getRowCount(); rowIndex++) { // String test = table.getValueAt(rowIndex,0).toString(); // int currColumn0Length = fm.stringWidth(table.getValueAt(rowIndex,0).toString()); // if (currColumn0Length > column0Length) { // column0Length = currColumn0Length; // } // // String test2 = table.getValueAt(rowIndex,1).toString(); // int currColumn1Length = fm.stringWidth(table.getValueAt(rowIndex,1).toString()); // if (currColumn1Length > column1Length) { // column1Length = currColumn1Length; // } // } // Set preferred size of each column based on longest expected entry FontMetrics fm = table.getFontMetrics(table.getFont()); TableColumn column = null; int col1PreferredWidth = -1; if (statisticsCriteriaPanel.isLogMode()) { col1PreferredWidth = fm.stringWidth("StandardDeviation(LogBinned):") + 10; } else { col1PreferredWidth = fm.stringWidth("StandardDeviation(Binned):") + 10; } // int col1PreferredWidth = fm.stringWidth("wwwwwwwwwwwwwwwwwwwwwwwwww"); int col2PreferredWidth = fm.stringWidth("1234567890") + 10; int tablePreferredWidth = col1PreferredWidth + col2PreferredWidth; for (int i = 0; i < 2; i++) { column = table.getColumnModel().getColumn(i); if (i == 0) { column.setPreferredWidth(col1PreferredWidth); column.setMaxWidth(col1PreferredWidth); } else { column.setPreferredWidth(col2PreferredWidth); } } JPanel textContainerPanel = new JPanel(new BorderLayout(2, 2)); // textContainerPanel.setBackground(Color.WHITE); textContainerPanel.add(table, BorderLayout.CENTER); textContainerPanel.addMouseListener(popupHandler); JPanel statsPane = GridBagUtils.createPanel(); GridBagConstraints gbc = GridBagUtils.createConstraints(""); gbc.gridy = 0; gbc.fill = GridBagConstraints.BOTH; gbc.anchor = GridBagConstraints.NORTHWEST; gbc.weightx = 1; gbc.weighty = 1; Dimension dim = table.getPreferredSize(); table.setPreferredSize(new Dimension(tablePreferredWidth, dim.height)); statsPane.add(table, gbc); statsPane.setPreferredSize(new Dimension(tablePreferredWidth, dim.height)); JPanel plotsPane = null; if (plotContainerPanel != null) { plotsPane = GridBagUtils.createPanel(); plotsPane.setBackground(Color.WHITE); // plotsPane.setBorder(UIUtils.createGroupBorder(" ")); /*I18N*/ GridBagConstraints gbcPlots = GridBagUtils.createConstraints(""); gbcPlots.gridy = 0; if (statisticsCriteriaPanel.exactPlotSize()) { gbcPlots.fill = GridBagConstraints.NONE; } else { gbcPlots.fill = GridBagConstraints.BOTH; } gbcPlots.anchor = GridBagConstraints.NORTHWEST; gbcPlots.weightx = 0.5; gbcPlots.weighty = 1; plotsPane.add(plotContainerPanel, gbcPlots); } JPanel mainPane = GridBagUtils.createPanel(); mainPane.setBorder(UIUtils.createGroupBorder(getSubPanelTitle(regionalMask, qualityMask, raster))); /*I18N*/ GridBagConstraints gbcMain = GridBagUtils.createConstraints(""); gbcMain.gridx = 0; gbcMain.gridy = 0; gbcMain.anchor = GridBagConstraints.NORTHWEST; if (plotsPane != null) { gbcMain.fill = GridBagConstraints.VERTICAL; gbcMain.weightx = 0; } else { gbcMain.fill = GridBagConstraints.BOTH; gbcMain.weightx = 1; } if (statisticsCriteriaPanel.showStatsList()) { gbcMain.weighty = 1; mainPane.add(statsPane, gbcMain); gbcMain.gridx++; } gbcMain.weightx = 1; gbcMain.weighty = 1; gbcMain.fill = GridBagConstraints.BOTH; if (plotsPane != null) { mainPane.add(plotsPane, gbcMain); } return mainPane; } private void addFieldToSpreadsheet(int idx, int row, String header, String entry) { if (idx > 0 && idx < statsSpreadsheet[0].length) { if (row <= 1) { statsSpreadsheet[0][idx] = header; } if (row < statsSpreadsheet[0].length) { statsSpreadsheet[row][idx] = entry; } } } private void addFieldToSpreadsheet(int row, MetaDataFields fileMetaDataField, Object entry) { int idx = metaDataFieldsHashMap.get(fileMetaDataField); if (idx > 0 && idx < statsSpreadsheet[0].length) { if (row <= 1) { statsSpreadsheet[0][idx] = fileMetaDataField.toString(); } if (row < statsSpreadsheet[0].length) { statsSpreadsheet[row][idx] = entry; } } } private void addFieldToSpreadsheet(int row, PrimaryStatisticsFields primaryStatisticsField, Object entry) { int idx = primaryStatisticsFieldsHashMap.get(primaryStatisticsField); if (idx >= 0 && idx < statsSpreadsheet[0].length) { if (row <= 1) { statsSpreadsheet[0][idx] = primaryStatisticsField.toString(); } if (row < statsSpreadsheet[0].length) { statsSpreadsheet[row][idx] = entry; } } } static double getBinSize(Histogram histogram) { return (histogram.getHighValue(0) - histogram.getLowValue(0)) / histogram.getNumBins(0); } static double getBinSizeLogMode(Histogram histogram) { return (Math.pow(10, histogram.getHighValue(0)) - Math.pow(10, histogram.getLowValue(0))) / histogram.getNumBins(0); } private String getSubPanelTitle(Mask regionalMask, Mask qualityMask, RasterDataNode raster) { StringBuilder sb = new StringBuilder(""); if (regionalMask != null && regionalMask.getName() != null) { sb.append("regional_mask=" + regionalMask.getName() + " "); } if (qualityMask != null && qualityMask.getName() != null) { sb.append("quality_mask=" + qualityMask.getName() + " "); } final String title; if (sb.length() > 0) { title = String.format("<html><b>%s (%s)</b></html>", raster.getName(), sb.toString()); } else { title = String.format("<html><b>%s</b></html>", raster.getName()); } return title; } @Override protected String getDataAsText() { return resultText.toString(); } // todo This part has not been updated by Danny private String createText(final Stx stx, final Mask mask) { if (stx.getSampleCount() == 0) { if (mask != null) { return "The ROI-Mask '" + mask.getName() + "' is empty."; } else { return "The scene contains no valid pixels."; } } RasterDataNode raster = getRaster(); boolean maskUsed = mask != null; final String unit = (StringUtils.isNotNullAndNotEmpty(raster.getUnit()) ? raster.getUnit() : "1"); final long numPixelTotal = (long) raster.getSceneRasterWidth() * (long) raster.getSceneRasterHeight(); final StringBuilder sb = new StringBuilder(1024); sb.append("Only ROI-mask pixels considered:\t"); sb.append(maskUsed ? "Yes" : "No"); sb.append("\n"); if (maskUsed) { sb.append("ROI-mask name:\t"); sb.append(mask.getName()); sb.append("\n"); } sb.append("Number of pixels total:\t"); sb.append(numPixelTotal); sb.append("\n"); sb.append("Number of considered pixels:\t"); sb.append(stx.getSampleCount()); sb.append("\n"); sb.append("Ratio of considered pixels:\t"); sb.append(100.0 * stx.getSampleCount() / numPixelTotal); sb.append("\t"); sb.append("%"); sb.append("\n"); sb.append("Minimum:\t"); sb.append(stx.getMinimum()); sb.append("\t"); sb.append(unit); sb.append("\n"); sb.append("Maximum:\t"); sb.append(stx.getMaximum()); sb.append("\t"); sb.append(unit); sb.append("\n"); sb.append("Mean:\t"); sb.append(stx.getMean()); sb.append("\t"); sb.append(unit); sb.append("\n"); sb.append("Standard deviation:\t"); sb.append(stx.getStandardDeviation()); sb.append("\t"); sb.append(unit); sb.append("\n"); sb.append("Coefficient of variation:\t"); sb.append(getCoefficientOfVariation(stx)); sb.append("\t"); sb.append(""); sb.append("\n"); sb.append("Bin Median:\t"); sb.append(stx.getMedianRaster()); sb.append("\t "); sb.append(unit); sb.append("\n"); for (int percentile = 5; percentile <= 95; percentile += 5) { sb.append("P").append(percentile).append(" threshold:\t"); sb.append(stx.getHistogram().getPTileThreshold(percentile / 100.0)[0]); sb.append("\t"); sb.append(unit); sb.append("\n"); } sb.append("Threshold max error:\t"); sb.append(getBinSize(stx.getHistogram())); sb.append("\t"); sb.append(unit); sb.append("\n"); return sb.toString(); } private String createText() { if (statsSpreadsheet == null || statsSpreadsheet.length == 0 || statsSpreadsheet[0].length == 0) { return "No Statistics Processed"; } final StringBuilder sb = new StringBuilder(); for (int rowIdx = 1; rowIdx < statsSpreadsheet.length; rowIdx++) { for (int colIdx = 0; colIdx < statsSpreadsheet[0].length; colIdx++) { Object valueObject = statsSpreadsheet[rowIdx][colIdx]; Object fieldObject = statsSpreadsheet[0][colIdx]; if (valueObject == null || fieldObject == null) { sb.append(""); } else { String field = fieldObject.toString(); sb.append(field + ": "); if (valueObject instanceof Float || valueObject instanceof Double) { String valueFormatted = getFormattedValue((Number) valueObject); sb.append(valueFormatted); } else { sb.append(valueObject.toString()); } } if (colIdx < statsSpreadsheet[0].length - 1) { sb.append("\n"); } } sb.append("\n\n"); } return sb.toString(); } private double getCoefficientOfVariation(Stx stx) { return stx.getStandardDeviation() / stx.getMean(); } private double getVariance(Stx stx) { return stx.getStandardDeviation() * stx.getStandardDeviation(); } @Override public void doLayout() { super.doLayout(); backgroundPanel.setBounds(0, 0, getWidth() - 8, getHeight() - 8); hideAndShowButton.setBounds(getWidth() - hideAndShowButton.getWidth() - 12, 6, 24, 24); } private static ChartPanel createChartPanel(XIntervalSeries percentileSeries, String xAxisLabel, String yAxisLabel, Color color, double domainBounds[], double rangeBounds[]) { XIntervalSeriesCollection percentileDataset = new XIntervalSeriesCollection(); percentileDataset.addSeries(percentileSeries); return getHistogramPlotPanel(percentileDataset, xAxisLabel, yAxisLabel, color, domainBounds, rangeBounds); } private static ChartPanel createScatterChartPanel(XIntervalSeries percentileSeries, String xAxisLabel, String yAxisLabel, Color color, double domainBounds[], double rangeBounds[]) { XIntervalSeriesCollection percentileDataset = new XIntervalSeriesCollection(); percentileDataset.addSeries(percentileSeries); return getScatterPlotPanel(percentileDataset, xAxisLabel, yAxisLabel, color, domainBounds, rangeBounds); } private static ChartPanel getHistogramPlotPanel(XIntervalSeriesCollection dataset, String xAxisLabel, String yAxisLabel, Color color, double domainBounds[], double rangeBounds[]) { JFreeChart chart = ChartFactory.createHistogram(null, xAxisLabel, yAxisLabel, dataset, PlotOrientation.VERTICAL, false, // Legend? true, // tooltips false // url ); final XYPlot xyPlot = chart.getXYPlot(); //xyPlot.setForegroundAlpha(0.85f); xyPlot.setNoDataMessage("No data"); xyPlot.setAxisOffset(new RectangleInsets(5, 5, 5, 10)); // xyPlot.setInsets(new RectangleInsets(0,0,0,0)); // todo Danny set bounds here // if (domainBounds[0] != domainBounds[1]) { // xyPlot.getDomainAxis().setLowerBound(domainBounds[0]); // xyPlot.getDomainAxis().setUpperBound(domainBounds[1]); // } // // if (rangeBounds[0] != rangeBounds[1]) { // xyPlot.getRangeAxis().setLowerBound(rangeBounds[0]); // xyPlot.getRangeAxis().setUpperBound(rangeBounds[1]); // } if (!Double.isNaN(domainBounds[0])) { xyPlot.getDomainAxis().setLowerBound(domainBounds[0]); } if (!Double.isNaN(domainBounds[1])) { xyPlot.getDomainAxis().setUpperBound(domainBounds[1]); } if (!Double.isNaN(rangeBounds[0])) { xyPlot.getRangeAxis().setLowerBound(rangeBounds[0]); } if (!Double.isNaN(rangeBounds[1])) { xyPlot.getRangeAxis().setUpperBound(rangeBounds[1]); } final XYBarRenderer renderer = (XYBarRenderer) xyPlot.getRenderer(); renderer.setDrawBarOutline(false); renderer.setShadowVisible(false); renderer.setSeriesPaint(0, color); StandardXYBarPainter painter = new StandardXYBarPainter(); renderer.setBarPainter(painter); ChartPanel chartPanel = new ChartPanel(chart); //// todo Danny testing out height/width ratio preservation // double histChartHeightWidthRatio = chartPanel.getPreferredSize().height / chartPanel.getPreferredSize().width; // double plotSizeReduction = 1; // Number preferredHeight = chartPanel.getPreferredSize().height * plotSizeReduction; // Number preferredWidth = chartPanel.getPreferredSize().width * plotSizeReduction; // // chartPanel.setPreferredSize(new Dimension(preferredWidth.intValue(), preferredHeight.intValue())); // chartPanel.setPreferredSize(new Dimension(300, 200)); // chartPanel.getPopupMenu().add(createCopyDataToClipboardMenuItem()); return chartPanel; } private static ChartPanel getScatterPlotPanel(XIntervalSeriesCollection dataset, String xAxisLabel, String yAxisLabel, Color color, double domainBounds[], double rangeBounds[]) { // JFreeChart chart = ChartFactory.createScatterPlot( JFreeChart chart = ChartFactory.createXYLineChart(null, xAxisLabel, yAxisLabel, dataset, PlotOrientation.VERTICAL, false, // Legend? true, // tooltips false // url ); final XYPlot xyPlot = chart.getXYPlot(); // xyPlot.setForegroundAlpha(0.85f); xyPlot.setBackgroundAlpha(0.0f); xyPlot.setNoDataMessage("No data"); xyPlot.setAxisOffset(new RectangleInsets(5, 5, 5, 10)); // todo Danny set bounds here // if (domainBounds[0] != domainBounds[1]) { // xyPlot.getDomainAxis().setLowerBound(domainBounds[0]); // xyPlot.getDomainAxis().setUpperBound(domainBounds[1]); // } // // if (rangeBounds[0] != rangeBounds[1]) { // xyPlot.getRangeAxis().setLowerBound(rangeBounds[0]); // xyPlot.getRangeAxis().setUpperBound(rangeBounds[1]); // } if (!Double.isNaN(domainBounds[0])) { xyPlot.getDomainAxis().setLowerBound(domainBounds[0]); } if (!Double.isNaN(domainBounds[1])) { xyPlot.getDomainAxis().setUpperBound(domainBounds[1]); } if (!Double.isNaN(rangeBounds[0])) { xyPlot.getRangeAxis().setLowerBound(rangeBounds[0]); } if (!Double.isNaN(rangeBounds[1])) { xyPlot.getRangeAxis().setUpperBound(rangeBounds[1]); } final XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) xyPlot.getRenderer(); renderer.setSeriesPaint(0, color); renderer.setUseFillPaint(true); renderer.setDrawOutlines(true); renderer.setSeriesShapesFilled(0, true); renderer.setSeriesFillPaint(0, color); ChartPanel chartPanel = new ChartPanel(chart); // chartPanel.setPreferredSize(new Dimension(300, 200)); return chartPanel; } private AbstractButton getExportButton() { final AbstractButton export = ToolButtonFactory.createButton(UIUtils.loadImageIcon("icons/Export24.gif"), false); export.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JPopupMenu viewPopup = new JPopupMenu("Export"); viewPopup.add(exportAsCsvAction); viewPopup.add(putStatisticsIntoVectorDataAction); final Rectangle buttonBounds = export.getBounds(); viewPopup.show(export, 1, buttonBounds.height + 1); } }); export.setEnabled(false); return export; } @Override public RasterDataNode getRasterDataNode() { return getRaster(); } @Override public ProductNodeGroup<VectorDataNode> getVectorDataNodeGroup() { return getRasterDataNode().getProduct().getVectorDataGroup(); } private class PopupHandler extends MouseAdapter { @Override public void mouseReleased(MouseEvent e) { if (e.getButton() == 2 || e.isPopupTrigger()) { final JPopupMenu menu = new JPopupMenu(); menu.add(createCopyDataToClipboardMenuItem()); menu.show(e.getComponent(), e.getX(), e.getY()); } } } // The fields of this class are used by the binding framework @SuppressWarnings("UnusedDeclaration") static class AccuracyModel { private int accuracy = 3; private boolean useAutoAccuracy = true; } private boolean retrieveValidateTextFields(boolean showDialog) { if (!statisticsCriteriaPanel.validatePrepare()) { return false; } return true; } private String getFormattedValue(Number value) { if (value.doubleValue() < 0.001 && value.doubleValue() > -0.001 && value.doubleValue() != 0.0) { return new DecimalFormat("0.####E0").format(value.doubleValue()); } String format = "%." + Integer.toString(statisticsCriteriaPanel.decimalPlaces()) + "f"; return String.format(format, value.doubleValue()); } private boolean validFields() { // if (!validNumBins()) { // return false; // } return true; } // todo Danny copied this from InformationPanel perhaps that could be called directly by making it public private static String getProductFormatName(final Product product) { final ProductReader productReader = product.getProductReader(); if (productReader == null) { return null; } final ProductReaderPlugIn readerPlugIn = productReader.getReaderPlugIn(); if (readerPlugIn != null) { return getProductFormatName(readerPlugIn); } return null; } // todo - make this a method in ProductReader and ProductWriter private static String getProductFormatName(final ProductReaderPlugIn readerPlugIn) { final String[] formatNames = readerPlugIn.getFormatNames(); if (formatNames != null && formatNames.length > 0) { return formatNames[0]; } return null; } private static String convertBandNameToProductTime(String bandName) { Guardian.assertNotNull("bandName", bandName); String bandNameDateTime = null; String[] bandNameDateTimeArray = bandName.split("_"); if (bandNameDateTimeArray.length >= 2) { // get last one as band name can also have underscore in it. bandNameDateTime = bandNameDateTimeArray[bandNameDateTimeArray.length - 1].trim(); } if (bandNameDateTime != null && bandNameDateTime.length() > 13) { String year = bandNameDateTime.substring(0, 4); String month = bandNameDateTime.substring(4, 6); String day = bandNameDateTime.substring(6, 8); String hour = bandNameDateTime.substring(9, 11); String min = bandNameDateTime.substring(11, 13); String sec = bandNameDateTime.substring(13); String[] monthNamesArray = new String[] { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; int monthIdx = Integer.valueOf(month); String monthStr = monthNamesArray[monthIdx - 1]; String productDate = day + "-" + monthStr + "-" + year; String productTime = hour + ":" + min + ":" + sec; return productDate + " " + productTime; } else { return null; } } }