package com.isti.traceview.transformations.spectra; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; //import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import javax.swing.BoxLayout; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.WindowConstants; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.title.TextTitle; import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import com.isti.traceview.TraceView; import com.isti.traceview.common.TimeInterval; import com.isti.traceview.common.TraceViewChartPanel; import com.isti.traceview.data.Response; import com.isti.traceview.gui.GraphUtil; import com.isti.traceview.processing.IstiUtilsMath; import com.isti.traceview.processing.Spectra; import com.isti.xmax.XMAX; /** * Dialog to view Spectra results. Also performs smoothing. * * @author Max Kokoulin */ class ViewSpectra extends JDialog implements PropertyChangeListener, ItemListener { private static final long serialVersionUID = 1L; // private static final Logger logger = Logger.getLogger(ViewSpectra.class); // private static SimpleDateFormat df = new SimpleDateFormat("yyyy,DDD"); private JOptionPane optionPane; private JCheckBox SmoothCB; private JCheckBox LogScaleCB; private JPanel selectionP; private JLabel convolveL; private JPanel optionPanel; private JComboBox<Object> convolveCB; private JCheckBox deconvolveCB; private JCheckBox showDiffCB; private List<Spectra> data = null; private XYPlot plot = null; private TimeInterval timeInterval = null; private TraceViewChartPanel chartPanel = null; private NumberAxis origRangeAxis = null; ViewSpectra(Frame owner, List<Spectra> data, TimeInterval timeInterval) { super(owner, "Spectra", true); this.data = data; this.timeInterval = timeInterval; Object[] options = { "Close", "Print", "Export GRAPH" }; // Create the JOptionPane. optionPane = new JOptionPane(createChartPanel(filterData(data)), JOptionPane.PLAIN_MESSAGE, JOptionPane.CLOSED_OPTION, null, options, options[0]); // Make this dialog display it. setContentPane(optionPane); optionPane.addPropertyChangeListener(this); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent we) { /* * Instead of directly closing the window, we're going to change * the JOptionPane's value property. */ optionPane.setValue("Close"); } }); pack(); setLocationRelativeTo(owner); setVisible(true); } @Override public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if (isVisible() && (e.getSource() == optionPane) && (prop.equals(JOptionPane.VALUE_PROPERTY))) { Object value = optionPane.getValue(); optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE); // If you were going to check something // before closing the window, you'd do // it here. if (value.equals("Close")) { setVisible(false); dispose(); } else if (value.equals("Print")) { chartPanel.createChartPrintJob(); } else if (value.equals("Export GRAPH")) { File exportFile = GraphUtil.saveGraphics(chartPanel, XMAX.getConfiguration().getUserDir("GRAPH")); if (exportFile != null) { XMAX.getConfiguration().setUserDir("GRAPH", exportFile.getParent()); } } } } /** Listens to the check box. */ @Override public void itemStateChanged(ItemEvent e) { if (e.getSource().equals(getSmoothCB())) { } else if (e.getSource().equals(getDeconvolveCB())) { getConvolveCB().setEnabled(e.getStateChange() == ItemEvent.SELECTED); } else if (e.getSource().equals(getConvolveCB())) { } else if (e.getSource().equals(getLogScaleCB())) { if(getLogScaleCB().isSelected()) { LogarithmicAxis rangeAxis = new LogarithmicAxis("Spectra"); rangeAxis.setAllowNegativesFlag(true); rangeAxis.setAutoRange(true); plot.setRangeAxis(rangeAxis); } else { plot.setRangeAxis(origRangeAxis); } } else if (e.getSource().equals(getShowDiffCB())) { if (getShowDiffCB().isSelected()) { // Component[] ca = selectionP.getComponents(); int countSelected = 0; for (int i = 1; i < selectionP.getComponentCount(); i++) { JCheckBox cb = (JCheckBox) selectionP.getComponent(i); if (cb.isSelected()) { countSelected++; } } if (countSelected == 2) { } else { getShowDiffCB().setSelected(false); JOptionPane.showMessageDialog(this, "You should select 2 channels to show difference", "Warning", JOptionPane.WARNING_MESSAGE); } } else { } } plot.setDataset(filterData(data)); } private JPanel createChartPanel(XYDataset dataset) { JPanel ret = new JPanel(); BoxLayout retLayout = new BoxLayout(ret, javax.swing.BoxLayout.Y_AXIS); ret.setLayout(retLayout); JFreeChart chart = ChartFactory.createXYLineChart(null, // title "Period, s", // x-axis label "Spectra", // y-axis label dataset, // data PlotOrientation.VERTICAL, // orientation true, // create legend? true, // generate tooltips? false // generate URLs? ); chart.setBackgroundPaint(Color.white); TextTitle title = new TextTitle("Start time: " + TimeInterval.formatDate(timeInterval.getStartTime(), TimeInterval.DateFormatType.DATE_FORMAT_NORMAL) + ", Duration: " + timeInterval.convert(), ret.getFont()); chart.setTitle(title); plot = chart.getXYPlot(); NumberAxis domainAxis = new LogarithmicAxis("Period, s"); plot.setDomainAxis(domainAxis); NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setAutoRange(true); rangeAxis.setAutoRangeIncludesZero(false); origRangeAxis = (NumberAxis) plot.getRangeAxis(); plot.setBackgroundPaint(Color.lightGray); plot.setDomainGridlinePaint(Color.white); plot.setRangeGridlinePaint(Color.white); plot.setDomainCrosshairVisible(true); plot.setRangeCrosshairVisible(true); chartPanel = new TraceViewChartPanel(chart, true); ret.add(chartPanel); ret.add(getOptionP()); if (dataset.getSeriesCount() > 1) { ret.add(getSelectionP()); } return ret; } private XYDataset filterData(List<Spectra> ds) { XYSeriesCollection ret = new XYSeriesCollection(); for (Spectra spectra : ds) { ret.addSeries(spectra.getSpectraSeries(getDeconvolveCB().isSelected(), getConvolveCB().getSelectedItem().toString())); } if (getSmoothCB().isSelected()) { ret = IstiUtilsMath.varismooth(ret); } if (getShowDiffCB().isSelected()) { XYSeries[] series = new XYSeries[2]; //determine the total number of selected channel checkboxes int totalSelectedChannels = 0; for(int i = 1; i < selectionP.getComponentCount(); i++) { JCheckBox cb = (JCheckBox) selectionP.getComponent(i); if (cb.isSelected()) { totalSelectedChannels++; } } if(totalSelectedChannels == 2) { int seriesFound = 0; int i = 1; // skip show difference button while (i < selectionP.getComponentCount()) { JCheckBox cb = (JCheckBox) selectionP.getComponent(i); if (cb.isSelected()) { series[seriesFound] = ret.getSeries(i - 1); seriesFound++; } i++; } double mean1 = getSeriesMean(series[0]); double mean2 = getSeriesMean(series[1]); XYSeries subtract = null; if (mean1 > mean2) { subtract = subtractSeries(series[0], series[1]); } else { subtract = subtractSeries(series[1], series[0]); } ret = new XYSeriesCollection(); ret.addSeries(subtract); } else { getShowDiffCB().setSelected(false); } } return ret; } /** * TODO: This method is too vague. Not sure what it does. Analysis and * refactoring required. * * @param series * the XYZSeries * @param arg * a double * @return either a Double.NaN or a computed value. */ private double getValue(XYSeries series, double arg) { for (int i = 0; i < series.getItemCount(); i++) { if (arg < series.getX(i).doubleValue()) { return series.getY(i - 1).doubleValue() + ((series.getY(i).doubleValue() - series.getY(i - 1).doubleValue()) * (arg - series.getX(i - 1).doubleValue()) / (series.getX(i).doubleValue() - series.getX(i - 1).doubleValue())); } } return Double.NaN; } /** * @param ser * the series * @return Series mean */ private double getSeriesMean(XYSeries ser) { double ret = 0; for (int i = 0; i < ser.getItemCount(); i++) { ret = ret + ser.getY(i).doubleValue(); } return ret / ser.getItemCount(); } private XYSeries subtractSeries(XYSeries series1, XYSeries series2) { XYSeries ret = new XYSeries(series1.getKey() + "-" + series2.getKey()); for (int i = 0; i < series1.getItemCount(); i++) { double val = getValue(series2, series1.getX(i).doubleValue()); if (val != Double.NaN) { ret.add(series1.getX(i), series1.getY(i).doubleValue() - val); } } return ret; } private JCheckBox getLogScaleCB() { if (LogScaleCB == null) { LogScaleCB = new JCheckBox(); LogScaleCB.setText("Log Scale"); LogScaleCB.addItemListener(this); } return LogScaleCB; } private JCheckBox getSmoothCB() { if (SmoothCB == null) { SmoothCB = new JCheckBox(); SmoothCB.setText("Smooth"); SmoothCB.addItemListener(this); } return SmoothCB; } private JCheckBox getShowDiffCB() { if (showDiffCB == null) { showDiffCB = new JCheckBox(); showDiffCB.setText("Show difference"); showDiffCB.setPreferredSize(new java.awt.Dimension(246, 20)); showDiffCB.addItemListener(this); } return showDiffCB; } private JCheckBox getDeconvolveCB() { if (deconvolveCB == null) { deconvolveCB = new JCheckBox(); deconvolveCB.setText("Deconvolve"); deconvolveCB.addItemListener(this); } return deconvolveCB; } private JComboBox<Object> getConvolveCB() { if (convolveCB == null) { List<String> options = new ArrayList<String>(); options.add("None"); for (Response resp : TraceView.getDataModule().getLoadedResponses()) { options.add(resp.getLocalFileName()); } ComboBoxModel<Object> convolveCBModel = new DefaultComboBoxModel<Object>(options.toArray()); convolveCB = new JComboBox<Object>(); convolveCB.setModel(convolveCBModel); convolveCB.setPreferredSize(new java.awt.Dimension(128, 22)); convolveCB.setEnabled(false); convolveCB.addItemListener(this); } return convolveCB; } private JPanel getOptionP() { if (optionPanel == null) { optionPanel = new JPanel(); optionPanel.setMaximumSize(new java.awt.Dimension(32767, 32)); optionPanel.add(getLogScaleCB()); optionPanel.add(getSmoothCB()); optionPanel.add(getDeconvolveCB()); optionPanel.add(getConvolveL()); optionPanel.add(getConvolveCB()); } return optionPanel; } private JLabel getConvolveL() { if (convolveL == null) { convolveL = new JLabel(); convolveL.setText("Convolve:"); } return convolveL; } private JPanel getSelectionP() { if (selectionP == null) { selectionP = new JPanel(); FlowLayout selectionPLayout = new FlowLayout(); selectionP.setLayout(selectionPLayout); selectionP.setMaximumSize(new java.awt.Dimension(32767, 32)); selectionP.add(getShowDiffCB()); for (Spectra spectra : data) { JCheckBox seriesCB = new JCheckBox(spectra.getName(), false); seriesCB.addItemListener(this); selectionP.add(seriesCB); } } return selectionP; } }