package pl.edu.fuw.fid.signalanalysis.dtf; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import org.apache.commons.math.linear.Array2DRowRealMatrix; import org.apache.commons.math.linear.RealMatrix; import org.jfree.data.xy.XYSeries; import org.signalml.app.view.montage.visualreference.VisualReferenceModel; import org.signalml.domain.montage.Montage; /** * Tabbed display of the results from the DTF method. * Consists of three tabs:<ul> * <li>model order selection,</li> * <li>charts of the transfer functions,</li> * <li>visualization of the spatial connectivity.</li> * </ul> * * @author ptr@mimuw.edu.pl */ public class DtfTabbedPane extends JTabbedPane { private final ArModel[] models; private final int spectrumSize; private final XYSeries[][] series; private final DtfArrowsDisplay arrowsDisplay; private int order = 0; private boolean normalized = true; private Double freqMin, freqMax; private void refreshData() { if (order > 0) { ArModel theModel = models[order-1]; int C = theModel.getChannelCount(); ArModelData[][] data = theModel.computeSpectralData(spectrumSize, normalized); for (int i=0; i<C; ++i) for (int j=0; j<C; ++j) { ArModelData single = data[j][i]; // display is transposed series[i][j].clear(); for (int f=0; f<single.length; ++f) { series[i][j].add(single.freqcs[f], single.values[f], f==single.length-1); } } RealMatrix transfer = null; if (freqMin != null && freqMax != null && freqMin <= freqMax) { transfer = new Array2DRowRealMatrix(C, C); RealMatrix counts = new Array2DRowRealMatrix(C, C); for (int i=0; i<C; ++i) for (int j=0; j<C; ++j) { ArModelData single = data[j][i]; // display is transposed for (int f=0; f<single.length; ++f) { if (freqMin <= single.freqcs[f] && single.freqcs[f] <= freqMax) { transfer.addToEntry(i, j, single.values[f]); counts.addToEntry(i, j, 1.0); } } } for (int i=0; i<C; ++i) for (int j=0; j<C; ++j) { double count = counts.getEntry(i, j); if (count > 0) { transfer.setEntry(i, j, transfer.getEntry(i, j) / count); } } } arrowsDisplay.setTransferData(transfer); } } public DtfTabbedPane(XYSeriesWithLegend[] criteria, String[] channels, ArModel[] models, int spectrumSize, Montage sources) { final int C = channels.length; this.models = models; this.spectrumSize = spectrumSize; this.series = new XYSeries[C][C]; for (int i=0; i<C; ++i) { for (int j=0; j<C; ++j) { String label = (i == j) ? "spectrum of "+channels[i] : channels[j]+"→"+channels[i]; // display is transposed series[i][j] = new XYSeries(label); series[i][j].setDescription(label); } } this.freqMin = 0.0; this.freqMax = 0.5 * models[0].getSamplingFrequency(); int maxOrder = models.length + 1; final DtfOrderCriteriaPanel criteriaPanel = DtfOrderCriteriaPanel.create(maxOrder, criteria); final DtfNormRadioPanel normPanel = new DtfNormRadioPanel(); final DtfPlotsPanel plotsPanel = new DtfPlotsPanel(series); final JButton copyModelDataButton = new JButton("copy model coefficients to clipboard"); final JPanel copyModelDataPanel = new JPanel(new BorderLayout()); copyModelDataButton.setEnabled(false); copyModelDataButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int order = DtfTabbedPane.this.order; String output = DtfTabbedPane.this.models[order-1].exportCoefficients(); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(output), null); } }); copyModelDataPanel.add(copyModelDataButton, BorderLayout.EAST); VisualReferenceModel visualModel = new VisualReferenceModel(); visualModel.setMontage(sources); arrowsDisplay = new DtfArrowsDisplay(visualModel); final JScrollPane arrowsPane = new JScrollPane(arrowsDisplay, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); arrowsPane.setPreferredSize(new Dimension(740, 440)); arrowsDisplay.setViewport(arrowsPane.getViewport()); DtfFrequencyRangePanel frequencyPanel = new DtfFrequencyRangePanel(freqMin, freqMax); final JPanel orderPanel = new JPanel(new BorderLayout()); orderPanel.add(copyModelDataPanel, BorderLayout.NORTH); orderPanel.add(criteriaPanel, BorderLayout.CENTER); final JPanel mainPanel = new JPanel(new BorderLayout()); mainPanel.add(normPanel, BorderLayout.NORTH); mainPanel.add(plotsPanel, BorderLayout.CENTER); final JPanel visualPanel = new JPanel(new BorderLayout()); visualPanel.add(frequencyPanel, BorderLayout.NORTH); visualPanel.add(arrowsPane, BorderLayout.CENTER); criteriaPanel.setListener(new DtfOrderSelectionListener() { @Override public void modelOrderSelected(int order) { boolean first = (DtfTabbedPane.this.order == 0); DtfTabbedPane.this.order = order; refreshData(); plotsPanel.rescaleCharts(); if (first) { plotsPanel.showAllCharts(); copyModelDataButton.setEnabled(true); } } }); normPanel.setListener(new DtfNormSelectionListener() { @Override public void normalizedChanged(boolean normalized) { DtfTabbedPane.this.normalized = normalized; refreshData(); plotsPanel.rescaleCharts(); } }); frequencyPanel.setListener(new DtfFrequencyRangeListener() { @Override public void frequencyRangeChanged(Double freqMin, Double freqMax) { DtfTabbedPane.this.freqMin = freqMin; DtfTabbedPane.this.freqMax = freqMax; refreshData(); } }); add("Model order", orderPanel); add("Transfer functions", mainPanel); add("Transfer graph", visualPanel); } }