diff --git a/view-simulation-results/pom.xml b/view-simulation-results/pom.xml
index 9b27f8b..d01e897 100644
--- a/view-simulation-results/pom.xml
+++ b/view-simulation-results/pom.xml
@@ -11,7 +11,7 @@
view-simulation-results
- 1.0-SNAPSHOT
+ 2.0
VCell View Simulation Results
Virtual Cell ImageJ plugin to retrieve VCell simulation results for analysis within ImageJ
@@ -159,39 +159,36 @@
4.1.1
-
-
- org.jsoup
- jsoup
- 1.16.1
-
-
org.scijava
scijava-log-slf4j
- 1.0.6
+
org.slf4j
slf4j-api
-
+
org.slf4j
slf4j-simple
-
com.google.code.gson
gson
- 2.10.1
+
software.amazon.awssdk
s3
+
+ com.opencsv
+ opencsv
+
+
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java b/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java
index b2695e0..09ef90e 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java
@@ -11,8 +11,7 @@
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.vcell.N5.UI.MainPanel;
-import org.vcell.N5.UI.N5ExportTable;
-import org.vcell.N5.retrieving.LoadingFactory;
+import org.vcell.N5.retrieving.LoadingManager;
import org.vcell.N5.retrieving.SimResultsLoader;
import java.io.*;
@@ -34,13 +33,14 @@ public class N5ImageHandler implements Command {
public static MainPanel exportTable;
public static String exportedMetaDataPath = System.getProperty("user.home") + "/.vcell/exportMetaData.json";
private static ExportDataRepresentation.FormatExportDataRepresentation exampleJSONData;
- public static LoadingFactory loadingFactory;
+ public static LoadingManager loadingManager;
@Override
public void run() {
initializeLogService();
- loadingFactory = new LoadingFactory();
+ loadingManager = new LoadingManager();
exportTable = new MainPanel();
+ MainPanel.controlButtonsPanel.setStateToInitializing(true);
setExampleJSONData();
// N5ImageHandler.logService.setLevel(LogService.DEBUG);
Thread thread = new Thread(() -> {
@@ -48,6 +48,8 @@ public void run() {
// So create one upon initialization, while the user is focused on the GUI
// and by the time they open an Image it's already loaded.
SimResultsLoader.s3ClientBuilder = AmazonS3ClientBuilder.standard();
+ MainPanel.controlButtonsPanel.setStateToInitializing(false);
+ MainPanel.n5ExportTable.valueChanged(null);
});
thread.start();
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/AdvancedFeatures.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/AdvancedFeatures.java
new file mode 100644
index 0000000..62c6152
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/AdvancedFeatures.java
@@ -0,0 +1,35 @@
+package org.vcell.N5.UI;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.EtchedBorder;
+import java.awt.*;
+
+public class AdvancedFeatures extends JPanel {
+ public final JButton openInMemory;
+ public final JButton copyLink;
+ public final JButton useN5Link;
+
+
+ public AdvancedFeatures(){
+ Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
+
+
+ openInMemory = new JButton("Open In Memory");
+ JPanel checkBoxPanel = new JPanel();
+// checkBoxPanel.add(openInMemory);
+
+ JPanel buttonPanel = new JPanel();
+ copyLink = new JButton("Copy Link");
+ useN5Link = new JButton("Use N5 Link");
+ buttonPanel.add(copyLink);
+ buttonPanel.add(useN5Link);
+ buttonPanel.add(openInMemory);
+
+// setLayout(new BorderLayout());
+// add(buttonPanel, BorderLayout.NORTH);
+// add(checkBoxPanel, BorderLayout.SOUTH);
+ add(buttonPanel);
+ this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Advanced Features "));
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/ControlButtonsPanel.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/ControlButtonsPanel.java
index 9eb0579..ebbc9fb 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/UI/ControlButtonsPanel.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/ControlButtonsPanel.java
@@ -1,6 +1,7 @@
package org.vcell.N5.UI;
import org.vcell.N5.N5ImageHandler;
+import org.vcell.N5.retrieving.SimResultsLoader;
import javax.swing.*;
import javax.swing.border.Border;
@@ -8,60 +9,57 @@
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.time.LocalDateTime;
-import java.util.Enumeration;
public class ControlButtonsPanel extends JPanel implements ActionListener {
private static JButton openOrCancel;
+ private final String openButtonText = "Open Virtual Stack";
+ private final String cancelButtonText = "Cancel";
+
+ private final JButton dataReduction;
+ private final String runScriptButtonText = "Run Measurement Script";
+ private final String cancelScriptButtonText = "Cancel Measurement Script";
// private final JButton openLocal = new JButton("Open N5 Local");
- private final JButton copyLink;
- private final JButton useN5Link;
private final JButton questionMark;
- private final JButton openInMemory;
- private final JCheckBox includeExampleExports;
- private final JCheckBox todayInterval;
- private final JCheckBox monthInterval;
- private final JCheckBox yearlyInterval;
- private final JCheckBox anyInterval;
- private final JPanel timeFilter;
+
+ public final JCheckBox includeExampleExports;
+ public final JCheckBox displayAdvancedFeatures;
private N5ExportTable n5ExportTable;
private RemoteFileSelection remoteFileSelection;
+ public final AdvancedFeatures advancedFeatures = new AdvancedFeatures();
+ private PanelState panelState = PanelState.NOTHING_OR_LOADING_IMAGE;
public ControlButtonsPanel(){
- openOrCancel = new JButton("Open");
- copyLink = new JButton("Copy Link");
- useN5Link = new JButton("Use N5 Link");
- questionMark = new JButton("?");
- questionMark.setPreferredSize(new Dimension(20, 20));
- openInMemory = new JButton("Open In Memory");
- openInMemory.setSelected(false);
includeExampleExports = new JCheckBox("Show Example Exports");
includeExampleExports.setSelected(!N5ImageHandler.exportedDataExists());
+ displayAdvancedFeatures = new JCheckBox("Advanced Features");
+
+ openOrCancel = new JButton("Open Virtual Stack");
+ dataReduction = new JButton(runScriptButtonText);
+ questionMark = new JButton("?");
+ questionMark.setPreferredSize(new Dimension(20, 20));
+
GridBagConstraints gridBagConstraints = new GridBagConstraints();
JPanel topRow = new JPanel(new GridBagLayout());
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
topRow.add(openOrCancel, gridBagConstraints);
- gridBagConstraints.gridwidth = 1;
gridBagConstraints.gridx = 1;
- gridBagConstraints.gridy = 0;
- topRow.add(openInMemory, gridBagConstraints);
- gridBagConstraints.gridx = 2;
+ topRow.add(dataReduction, gridBagConstraints);
+
+
JPanel bottomRow = new JPanel(new GridBagLayout());
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- bottomRow.add(copyLink, gridBagConstraints);
+ bottomRow.add(includeExampleExports);
gridBagConstraints.gridx = 1;
- bottomRow.add(useN5Link, gridBagConstraints);
+ bottomRow.add(displayAdvancedFeatures, gridBagConstraints);
+ gridBagConstraints.gridx = 2;
bottomRow.add(questionMark);
-
JPanel userButtonsPanel = new JPanel(new GridBagLayout());
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
@@ -71,58 +69,32 @@ public ControlButtonsPanel(){
// buttonsPanel.add(questionMark);
-
- todayInterval = new JCheckBox("Past 24 Hours");
- monthInterval = new JCheckBox("Past Month");
- yearlyInterval = new JCheckBox("Past Year");
- anyInterval = new JCheckBox("Any Time");
- anyInterval.setSelected(true);
-
- ButtonGroup buttonGroup = new ButtonGroup();
- buttonGroup.add(todayInterval);
- buttonGroup.add(monthInterval);
- buttonGroup.add(yearlyInterval);
- buttonGroup.add(anyInterval);
-
- JPanel filters = new JPanel();
- filters.setLayout(new BorderLayout());
- timeFilter = new JPanel(new GridBagLayout());
- timeFilter.add(anyInterval);
- timeFilter.add(todayInterval);
- timeFilter.add(monthInterval);
- timeFilter.add(yearlyInterval);
-// timeFilter.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Time "));
- filters.add(timeFilter, BorderLayout.NORTH);
- filters.add(includeExampleExports, BorderLayout.SOUTH);
- Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
- filters.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Filters "));
-
-
int paneWidth = 800;
- this.setPreferredSize(new Dimension(paneWidth, 100));
+ this.setPreferredSize(new Dimension(paneWidth, 110));
this.setLayout(new BorderLayout());
// topBar.add(openLocal);
+ Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
this.add(userButtonsPanel, BorderLayout.EAST);
- this.add(filters, BorderLayout.WEST);
this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " User Options "));
+ advancedFeatures.setVisible(false);
+ add(advancedFeatures, BorderLayout.WEST);
+
openOrCancel.addActionListener(this);
- copyLink.addActionListener(this);
+ advancedFeatures.copyLink.addActionListener(this);
questionMark.addActionListener(this);
- useN5Link.addActionListener(this);
- includeExampleExports.addActionListener(this);
+ advancedFeatures.useN5Link.addActionListener(this);
// openLocal.addActionListener(this);
- openInMemory.addActionListener(this);
+ includeExampleExports.addActionListener(this);
+ displayAdvancedFeatures.addActionListener(this);
+ dataReduction.addActionListener(this);
+ advancedFeatures.openInMemory.addActionListener(this);
- Enumeration b = buttonGroup.getElements();
- while (b.hasMoreElements()){
- b.nextElement().addActionListener(this);
- }
openOrCancel.setEnabled(false);
- copyLink.setEnabled(false);
- openInMemory.setEnabled(false);
+ dataReduction.setEnabled(false);
+ advancedFeatures.copyLink.setEnabled(false);
}
public void initialize(N5ExportTable n5ExportTable, RemoteFileSelection remoteFileSelection){
@@ -132,72 +104,112 @@ public void initialize(N5ExportTable n5ExportTable, RemoteFileSelection remoteFi
@Override
public void actionPerformed(ActionEvent e) {
- if(e.getSource().equals(openOrCancel) || e.getSource().equals(openInMemory)){
- if (openOrCancel.getText().equals("Cancel")){
- n5ExportTable.removeFromLoadingRows();
+ boolean inMemory = e.getSource().equals(advancedFeatures.openInMemory);
+ if(e.getSource().equals(openOrCancel) || inMemory){
+ panelState = PanelState.NOTHING_OR_LOADING_IMAGE;
+ if (openOrCancel.getText().equals(cancelButtonText)){
+ n5ExportTable.stopSelectedImageFromLoading();
+ updateButtonsToMatchState(false);
} else {
- n5ExportTable.openSelectedRows(e.getSource().equals(openInMemory));
+ n5ExportTable.openSelectedRows(inMemory, false, SimResultsLoader.OpenTag.VIEW);
+ updateButtonsToMatchState(true);
+ }
+ } else if (e.getSource().equals(dataReduction)) {
+ if (dataReduction.getText().equals(cancelScriptButtonText)){
+ panelState = PanelState.NOTHING_OR_LOADING_IMAGE;
+ N5ImageHandler.loadingManager.stopAllImagesAndAnalysis();
+ } else{
+ panelState = PanelState.PERFORMING_ANALYSIS;
+ setButtonsToCancelReduction();
+ n5ExportTable.openSelectedRows(false, true, SimResultsLoader.OpenTag.DATA_REDUCTION);
}
- } else if (e.getSource().equals(copyLink)) {
+ updateButtonsToMatchState();
+ } else if (e.getSource().equals(advancedFeatures.copyLink)) {
n5ExportTable.copySelectedRowLink();
} else if (e.getSource().equals(questionMark)) {
new HelpExplanation().displayHelpMenu();
- } else if (e.getSource().equals(useN5Link)) {
+ } else if (e.getSource().equals(advancedFeatures.useN5Link)) {
remoteFileSelection.setVisible(true);
} else if (e.getSource().equals(includeExampleExports)){
- if(includeExampleExports.isSelected()){
- n5ExportTable.updateExampleExportsToTable();
- return;
- }
- n5ExportTable.updateTableData();
- } else if (e.getSource().equals(anyInterval) || e.getSource().equals(todayInterval)
- || e.getSource().equals(monthInterval) || e.getSource().equals(yearlyInterval)) {
- if(includeExampleExports.isSelected()){
- n5ExportTable.updateExampleExportsToTable();
- return;
- }
n5ExportTable.updateTableData();
+ } else if (e.getSource().equals(displayAdvancedFeatures)) {
+ advancedFeatures.setVisible(displayAdvancedFeatures.isSelected());
}
}
- public LocalDateTime oldestTimeAllowed(){
- LocalDateTime pastTime = LocalDateTime.now();
- if (todayInterval.isSelected()){
- pastTime = pastTime.minusDays(1);
- } else if (monthInterval.isSelected()) {
- pastTime = pastTime.minusMonths(1);
- } else if (yearlyInterval.isSelected()) {
- pastTime = pastTime.minusYears(1);
- } else {
- pastTime = pastTime.minusYears(10); //Max date back is 10 years
+ public void updateButtonsToMatchState(){
+ updateButtonsToMatchState(false);
+ }
+
+ public void updateButtonsToMatchState(boolean rowIsLoadingImage){
+ updateButtonsToMatchState(rowIsLoadingImage, panelState);
+ }
+
+ public void setStateToInitializing(boolean isInitializing){
+ panelState = isInitializing ? PanelState.INITIALIZING : PanelState.NOTHING_OR_LOADING_IMAGE;
+ }
+
+ public void updateButtonsToMatchState(boolean rowIsLoadingImage, PanelState newPanelState){
+ switch (newPanelState){
+ case NOTHING_OR_LOADING_IMAGE:
+ if (rowIsLoadingImage){
+ allowCancel();
+ } else {
+ enableAllButtons(true);
+ }
+ break;
+ case PERFORMING_ANALYSIS:
+ setButtonsToCancelReduction();
+ break;
+ case INITIALIZING:
+ enableAllButtons(false);
+ break;
}
- return pastTime;
+ panelState = newPanelState;
+ }
+
+ public void setButtonsToCancelReduction(){
+ openOrCancel.setText(openButtonText);
+ openOrCancel.setEnabled(false);
+ advancedFeatures.useN5Link.setEnabled(false);
+ advancedFeatures.openInMemory.setEnabled(false);
+
+ advancedFeatures.copyLink.setEnabled(true);
+ dataReduction.setText(cancelScriptButtonText);
}
- public void allowCancel(boolean allow){
+ private void allowCancel(){
openOrCancel.setEnabled(true);
- copyLink.setEnabled(true);
- openInMemory.setEnabled(!allow);
- useN5Link.setEnabled(true);
+ advancedFeatures.copyLink.setEnabled(true);
+ advancedFeatures.useN5Link.setEnabled(true);
remoteFileSelection.submitS3Info.setEnabled(true);
- if (allow){
- openOrCancel.setText("Cancel");
- } else {
- openOrCancel.setText("Open");
- }
+ dataReduction.setEnabled(false);
+ advancedFeatures.openInMemory.setEnabled(false);
+ openOrCancel.setText(cancelButtonText);
}
- public void enableRowContextDependentButtons(boolean enable){
- openOrCancel.setEnabled(enable);
- copyLink.setEnabled(enable);
- openInMemory.setEnabled(enable);
+ public void disableAllContextDependentButtons(){
+ openOrCancel.setEnabled(false);
+ advancedFeatures.copyLink.setEnabled(false);
+ dataReduction.setEnabled(false);
+ advancedFeatures.openInMemory.setEnabled(false);
}
- public void enableCriticalButtons(boolean enable){
- useN5Link.setEnabled(enable);
+ public void enableAllButtons(boolean enable){
+ openOrCancel.setText(openButtonText);
+ dataReduction.setText(runScriptButtonText);
+
+ advancedFeatures.useN5Link.setEnabled(enable);
openOrCancel.setEnabled(enable);
- copyLink.setEnabled(enable);
+ advancedFeatures.copyLink.setEnabled(enable);
remoteFileSelection.submitS3Info.setEnabled(enable);
- openInMemory.setEnabled(enable);
+ dataReduction.setEnabled(enable);
+ advancedFeatures.openInMemory.setEnabled(enable);
+ }
+
+ public enum PanelState {
+ PERFORMING_ANALYSIS,
+ NOTHING_OR_LOADING_IMAGE,
+ INITIALIZING
}
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/Filters/SearchBar.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/Filters/SearchBar.java
new file mode 100644
index 0000000..cc0db5d
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/Filters/SearchBar.java
@@ -0,0 +1,37 @@
+package org.vcell.N5.UI.Filters;
+
+import org.vcell.N5.UI.MainPanel;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+public class SearchBar extends JPanel implements KeyListener {
+ public static final JTextField searchTextField = new JTextField();
+
+ public SearchBar(){
+ this.add(new JLabel("Search: "));
+ searchTextField.setPreferredSize(new Dimension(600, 20));
+ searchTextField.addKeyListener(this);
+ this.add(searchTextField);
+// this.setPreferredSize(new Dimension(600, 20));
+ }
+
+ @Override
+ public void keyTyped(KeyEvent e) {
+
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if (e.getSource().equals(searchTextField)){
+ MainPanel.n5ExportTable.updateTableData(searchTextField.getText());
+ }
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/Filters/TimeFilter.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/Filters/TimeFilter.java
new file mode 100644
index 0000000..6a29fd7
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/Filters/TimeFilter.java
@@ -0,0 +1,81 @@
+package org.vcell.N5.UI.Filters;
+
+import org.vcell.N5.UI.MainPanel;
+import org.vcell.N5.UI.N5ExportTable;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.EtchedBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.time.LocalDateTime;
+import java.util.Enumeration;
+
+
+public class TimeFilter extends JPanel implements ActionListener {
+ private final JCheckBox todayInterval;
+ private final JCheckBox monthInterval;
+ private final JCheckBox yearlyInterval;
+ private final JCheckBox anyInterval;
+ private final JPanel timeFilter;
+
+ private final N5ExportTable n5ExportTable;
+
+
+ public TimeFilter(){
+ n5ExportTable = MainPanel.n5ExportTable;
+
+ todayInterval = new JCheckBox("Past 24 Hours");
+ monthInterval = new JCheckBox("Past Month");
+ yearlyInterval = new JCheckBox("Past Year");
+ anyInterval = new JCheckBox("Any Time");
+ anyInterval.setSelected(true);
+
+ ButtonGroup buttonGroup = new ButtonGroup();
+ buttonGroup.add(todayInterval);
+ buttonGroup.add(monthInterval);
+ buttonGroup.add(yearlyInterval);
+ buttonGroup.add(anyInterval);
+
+ this.setLayout(new BorderLayout());
+ timeFilter = new JPanel(new GridBagLayout());
+ timeFilter.add(anyInterval);
+ timeFilter.add(todayInterval);
+ timeFilter.add(monthInterval);
+ timeFilter.add(yearlyInterval);
+// timeFilter.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Time "));
+ this.add(timeFilter, BorderLayout.NORTH);
+
+ Enumeration b = buttonGroup.getElements();
+ while (b.hasMoreElements()){
+ b.nextElement().addActionListener(this);
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource().equals(anyInterval) || e.getSource().equals(todayInterval)
+ || e.getSource().equals(monthInterval) || e.getSource().equals(yearlyInterval)) {
+ if(MainPanel.controlButtonsPanel.includeExampleExports.isSelected()){
+ n5ExportTable.updateTableData();
+ return;
+ }
+ n5ExportTable.updateTableData();
+ }
+ }
+
+ public LocalDateTime oldestTimeAllowed(){
+ LocalDateTime pastTime = LocalDateTime.now();
+ if (todayInterval.isSelected()){
+ pastTime = pastTime.minusDays(1);
+ } else if (monthInterval.isSelected()) {
+ pastTime = pastTime.minusMonths(1);
+ } else if (yearlyInterval.isSelected()) {
+ pastTime = pastTime.minusYears(1);
+ } else {
+ pastTime = pastTime.minusYears(10); //Max date back is 10 years
+ }
+ return pastTime;
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/HintTextField.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/HintTextField.java
new file mode 100644
index 0000000..4fa9cff
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/HintTextField.java
@@ -0,0 +1,43 @@
+package org.vcell.N5.UI;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+
+public class HintTextField extends JTextField {
+ Font gainFont = new Font("Tahoma", Font.PLAIN, 11);
+ Font lostFont = new Font("Tahoma", Font.ITALIC, 11);
+ public HintTextField(final String hint) {
+ setText(hint);
+ setFont(lostFont);
+ setForeground(Color.GRAY);
+
+ this.addFocusListener(new FocusAdapter() {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (getText().equals(hint)) {
+ setText("");
+ setFont(gainFont);
+ } else {
+ setText(getText());
+ setFont(gainFont);
+ }
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (getText().equals(hint)|| getText().isEmpty()) {
+ setText(hint);
+ setFont(lostFont);
+ setForeground(Color.GRAY);
+ } else {
+ setText(getText());
+ setFont(gainFont);
+ setForeground(Color.BLACK);
+ }
+ }
+ });
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/MainPanel.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/MainPanel.java
index a49f5b7..5d4bb24 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/UI/MainPanel.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/MainPanel.java
@@ -1,38 +1,52 @@
package org.vcell.N5.UI;
+import org.vcell.N5.UI.Filters.SearchBar;
+import org.vcell.N5.UI.Filters.TimeFilter;
+
import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.util.Enumeration;
public class MainPanel {
- private static JDialog exportTableDialog;
- private final int paneWidth = 800;
+ public static JFrame exportTableDialog;
public final static ControlButtonsPanel controlButtonsPanel = new ControlButtonsPanel();
- public final N5ExportTable n5ExportTable = new N5ExportTable();
+ public final static N5ExportTable n5ExportTable = new N5ExportTable();
public final ExportDetailsPanel exportDetailsPanel = new ExportDetailsPanel();
public final RemoteFileSelection remoteFileSelection = new RemoteFileSelection();
-
+ public final static TimeFilter timeFilter = new TimeFilter();
+ public final static SearchBar searchBar = new SearchBar();
public MainPanel(){
- JPanel parentPanel = new JPanel();
-
-
- n5ExportTable.initialize(controlButtonsPanel, exportDetailsPanel);
+ n5ExportTable.initialize(controlButtonsPanel, exportDetailsPanel, timeFilter);
controlButtonsPanel.initialize(n5ExportTable, remoteFileSelection);
- parentPanel.setLayout(new BorderLayout());
- parentPanel.add(controlButtonsPanel, BorderLayout.NORTH);
+ JPanel contentPanel = new JPanel(new BorderLayout());
+ JPanel northPanel = new JPanel(new BorderLayout());
+ northPanel.add(controlButtonsPanel, BorderLayout.SOUTH);
+
JSplitPane jSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, n5ExportTable, exportDetailsPanel);
jSplitPane.setContinuousLayout(true);
- parentPanel.add(jSplitPane, BorderLayout.CENTER);
- parentPanel.setPreferredSize(new Dimension(paneWidth, 650));
- JOptionPane pane = new JOptionPane(parentPanel, JOptionPane.PLAIN_MESSAGE, 0, null, new Object[]{"Close"});
- exportTableDialog = pane.createDialog("VCell Exports");
- exportTableDialog.setModal(false);
+ JPanel filters = new JPanel(new BorderLayout());
+ Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
+ filters.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Filters "));
+ filters.add(timeFilter, BorderLayout.NORTH);
+ filters.add(searchBar, BorderLayout.SOUTH);
+
+ contentPanel.add(northPanel, BorderLayout.NORTH);
+ contentPanel.add(jSplitPane, BorderLayout.CENTER);
+ contentPanel.add(filters, BorderLayout.SOUTH);
+ contentPanel.setBorder(new EmptyBorder(15, 12, 15, 12));
+
+ exportTableDialog = new JFrame("VCell Exports");
+ exportTableDialog.add(contentPanel);
+ exportTableDialog.pack();
exportTableDialog.setResizable(true);
exportTableDialog.setVisible(true);
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java
index f9de4e0..ca79296 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java
@@ -3,6 +3,8 @@
import org.scijava.log.Logger;
import org.vcell.N5.ExportDataRepresentation;
import org.vcell.N5.N5ImageHandler;
+import org.vcell.N5.UI.Filters.SearchBar;
+import org.vcell.N5.UI.Filters.TimeFilter;
import org.vcell.N5.retrieving.SimLoadingListener;
import org.vcell.N5.retrieving.SimResultsLoader;
@@ -23,7 +25,7 @@
import java.util.concurrent.TimeUnit;
public class N5ExportTable extends JScrollPane implements ListSelectionListener, SimLoadingListener {
- private N5ExportTableModel n5ExportTableModel;
+ public N5ExportTableModel n5ExportTableModel;
private JTable exportListTable;
private final Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
@@ -32,16 +34,19 @@ public class N5ExportTable extends JScrollPane implements ListSelectionListener,
private ControlButtonsPanel controlPanel;
private ExportDetailsPanel exportDetailsPanel;
+ private TimeFilter timeFilter;
private final Logger logger = N5ImageHandler.getLogger(N5ExportTable.class);
public N5ExportTable(){}
- public void initialize(ControlButtonsPanel controlButtonsPanel, ExportDetailsPanel exportDetailsPanel){
+ public void initialize(ControlButtonsPanel controlButtonsPanel, ExportDetailsPanel exportDetailsPanel,
+ TimeFilter timeFilter){
this.controlPanel = controlButtonsPanel;
this.exportDetailsPanel = exportDetailsPanel;
- N5ImageHandler.loadingFactory.addSimLoadingListener(this);
+ this.timeFilter = timeFilter;
+ N5ImageHandler.loadingManager.addSimLoadingListener(this);
n5ExportTableModel = new N5ExportTableModel();
exportListTable = new JTable(n5ExportTableModel);
this.setViewportView(exportListTable);
@@ -71,38 +76,41 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Export Table"));
exportListTable.getSelectionModel().addListSelectionListener(this);
- if(!N5ImageHandler.exportedDataExists()){
- updateExampleExportsToTable();
- }
- else{
- updateTableData();
- }
+ updateTableData("");
automaticRefresh();
}
- void updateTableData(){
+ public void updateTableData(){
+ updateTableData(SearchBar.searchTextField.getText());
+ }
+
+ public void updateTableData(String strFilter){
// when initializing it is null
if (controlPanel == null){
- updateTableData(LocalDateTime.now().minusYears(10));
+ updateTableData(LocalDateTime.now().minusYears(10), strFilter);
} else {
- updateTableData(controlPanel.oldestTimeAllowed());
+ updateTableData(timeFilter.oldestTimeAllowed(), strFilter);
}
}
- void updateTableData(LocalDateTime oldestTimeAllowed){
+ void updateTableData(LocalDateTime oldestTimeAllowed, String strFilter){
n5ExportTableModel.resetData();
- this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Personal Exports"));
+ if (!controlPanel.includeExampleExports.isSelected()){
+ this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Personal Exports"));
+ } else {
+ this.setBorder(exampleBorder);
+ }
try {
- ExportDataRepresentation.FormatExportDataRepresentation formatExportData = N5ImageHandler.getJsonData();
- if (formatExportData != null){
- Stack jobStack = formatExportData.formatJobIDs;
- while (!jobStack.isEmpty()){
- String jobID = jobStack.pop();
- if (!n5ExportTableModel.appendRowData(formatExportData.simulationDataMap.get(jobID), oldestTimeAllowed)){
- break;
- }
- }
+ ExportDataRepresentation.FormatExportDataRepresentation formatExportData = N5ImageHandler.exportedDataExists() && !controlPanel.includeExampleExports.isSelected() ?
+ N5ImageHandler.getJsonData() : N5ImageHandler.getExampleJSONData();
+
+ Stack jobStack = (Stack) formatExportData.formatJobIDs.clone();
+ while (!jobStack.isEmpty()){
+ String jobID = jobStack.pop();
+ n5ExportTableModel.addToRowData(formatExportData.simulationDataMap.get(jobID), oldestTimeAllowed,
+ strFilter, true);
}
+
n5ExportTableModel.fireTableDataChanged();
this.updateUI();
} catch (FileNotFoundException e) {
@@ -110,41 +118,12 @@ void updateTableData(LocalDateTime oldestTimeAllowed){
}
}
- void updateExampleExportsToTable(){
- // when initializing it is null
- if (controlPanel == null){
- updateExampleExportsToTable(LocalDateTime.now().minusYears(10));
- } else {
- updateExampleExportsToTable(controlPanel.oldestTimeAllowed());
- }
- }
-
- void updateExampleExportsToTable(LocalDateTime oldestTimeAllowed){
- n5ExportTableModel.resetData();
- this.setBorder(exampleBorder);
- try{
- ExportDataRepresentation.FormatExportDataRepresentation exampleFormatExportData = N5ImageHandler.getExampleJSONData();
- Stack exampleJobStack = (Stack) exampleFormatExportData.formatJobIDs.clone();
- while (!exampleJobStack.isEmpty()){
- String jobID = exampleJobStack.pop();
- if (!n5ExportTableModel.appendRowData(exampleFormatExportData.simulationDataMap.get(jobID), oldestTimeAllowed)){
- break;
- }
- }
- n5ExportTableModel.fireTableDataChanged();
- this.updateUI();
- }
- catch (FileNotFoundException e){
- throw new RuntimeException("Can't open example N5 export table.", e);
- }
- }
-
private void automaticRefresh(){
Thread refreshTableThread = new Thread(() -> {
try {
while(true){
ExportDataRepresentation.FormatExportDataRepresentation formatExportData = N5ImageHandler.getJsonData();
- if (formatExportData != null && !this.getBorder().equals(exampleBorder)){
+ if (formatExportData != null && !controlPanel.includeExampleExports.isSelected()){
ExportDataRepresentation.SimulationExportDataRepresentation mostRecentTableEntry = !n5ExportTableModel.tableData.isEmpty() ? n5ExportTableModel.tableData.getFirst() : null;
Stack jobStack = formatExportData.formatJobIDs;
boolean isUpdated = false;
@@ -154,7 +133,9 @@ private void automaticRefresh(){
|| !formatExportData.simulationDataMap.containsKey(mostRecentTableEntry.jobID))){
break;
}
- isUpdated = n5ExportTableModel.prependRowData(formatExportData.simulationDataMap.get(currentJob), controlPanel.oldestTimeAllowed());
+ isUpdated = n5ExportTableModel.addToRowData(formatExportData.simulationDataMap.get(currentJob),
+ timeFilter.oldestTimeAllowed(), SearchBar.searchTextField.getText(),
+ false);
}
if(isUpdated){
n5ExportTableModel.fireTableDataChanged();
@@ -173,15 +154,16 @@ private void automaticRefresh(){
refreshTableThread.start();
}
- public void openSelectedRows(boolean inMemory){
+ public void openSelectedRows(boolean openInMemory, boolean performDataReduction, SimResultsLoader.OpenTag openTag){
ArrayList filesToOpen = new ArrayList<>();
for(int row: exportListTable.getSelectedRows()){
String uri = n5ExportTableModel.getRowData(row).uri;
ExportDataRepresentation.SimulationExportDataRepresentation rowData = n5ExportTableModel.getRowData(row);
- SimResultsLoader simResultsLoader = new SimResultsLoader(uri, rowData.savedFileName, row, rowData.jobID);
+ SimResultsLoader simResultsLoader = new SimResultsLoader(uri, rowData.savedFileName, row, rowData.jobID, openTag);
filesToOpen.add(simResultsLoader);
}
- N5ImageHandler.loadingFactory.openN5FileDataset(filesToOpen, inMemory);
+ N5ImageHandler.loadingManager.openN5FileDataset(filesToOpen, openInMemory,
+ performDataReduction);
}
public void copySelectedRowLink(){
@@ -213,25 +195,31 @@ public void valueChanged(ListSelectionEvent e) {
int row = exportListTable.getSelectedRow();
exportDetailsPanel.resetExportDetails();
if (row > exportListTable.getRowCount() || row < 0){
- controlPanel.enableRowContextDependentButtons(false);
+ controlPanel.disableAllContextDependentButtons();
return;
}
- controlPanel.enableRowContextDependentButtons(true);
MainPanel.setEnableParentAndChild(exportDetailsPanel, true);
ExportDataRepresentation.SimulationExportDataRepresentation rowData = n5ExportTableModel.getRowData(row);
exportDetailsPanel.addExportDetailEntries("Variables: " + rowData.variables, rowData.differentParameterValues);
int loadingRow = loadingRowsJobID.containsKey(row) ? findLoadingRow(row, row) : -1;
- controlPanel.allowCancel(loadingRow != -1);
+ controlPanel.updateButtonsToMatchState(loadingRow != -1);
}
- public void removeFromLoadingRows(){
+ public void stopSelectedImageFromLoading(){
int row = exportListTable.getSelectedRow();
- N5ImageHandler.loadingFactory.stopOpeningSimulation(n5ExportTableModel.tableData.get(row).jobID);
+ N5ImageHandler.loadingManager.stopLoadingImage(n5ExportTableModel.tableData.get(row).jobID);
loadingRowsJobID.remove(row);
exportListTable.repaint();
}
+ public void removeSpecificRowFromLoadingRows(int rowNumber){
+ int realRowNumber = findLoadingRow(rowNumber, rowNumber);
+ loadingRowsJobID.remove(realRowNumber);
+ controlPanel.updateButtonsToMatchState(false);
+ exportListTable.repaint();
+ }
+
@Override
public void simIsLoading(int itemRow, String exportID) {
loadingRowsJobID.put(itemRow, exportID);
@@ -239,13 +227,14 @@ public void simIsLoading(int itemRow, String exportID) {
}
@Override
- public void simFinishedLoading(int itemRow, String exportID) {
- loadingRowsJobID.remove(itemRow);
- exportListTable.repaint();
- controlPanel.allowCancel(false);
+ public void simFinishedLoading(SimResultsLoader loadedResults) {
+ if (loadedResults.openTag == SimResultsLoader.OpenTag.VIEW){
+ removeSpecificRowFromLoadingRows(loadedResults.rowNumber);
+ loadedResults.getImagePlus().show();
+ }
}
- static class N5ExportTableModel extends AbstractTableModel {
+ public static class N5ExportTableModel extends AbstractTableModel {
public final ArrayList headers = new ArrayList(){{
add("BioModel");
add("Application");
@@ -300,23 +289,21 @@ public ExportDataRepresentation.SimulationExportDataRepresentation getRowData(in
public void resetData(){
tableData = new LinkedList<>();
}
- public boolean appendRowData(ExportDataRepresentation.SimulationExportDataRepresentation rowData, LocalDateTime oldestExportAllowed){
- DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
- LocalDateTime exportDate = LocalDateTime.parse(rowData.exportDate, dateFormat);
- if (exportDate.isBefore(oldestExportAllowed)){
- return false;
- }
- tableData.add(rowData);
- return true;
+ private boolean stringFilter(ExportDataRepresentation.SimulationExportDataRepresentation rowData, String strFilter){
+ return rowData.biomodelName.contains(strFilter) || rowData.applicationName.contains(strFilter) ||
+ rowData.simulationName.contains(strFilter) || rowData.savedFileName.contains(strFilter);
}
-
- public boolean prependRowData(ExportDataRepresentation.SimulationExportDataRepresentation rowData, LocalDateTime oldestExportAllowed){
+ public boolean addToRowData(ExportDataRepresentation.SimulationExportDataRepresentation rowData, LocalDateTime oldestExportAllowed, String strFilter, boolean append){
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime exportDate = LocalDateTime.parse(rowData.exportDate, dateFormat);
- if (exportDate.isBefore(oldestExportAllowed)){
+ if (exportDate.isBefore(oldestExportAllowed) || !stringFilter(rowData, strFilter)){
return false;
}
- tableData.addFirst(rowData);
+ if (append){
+ tableData.add(rowData);
+ } else {
+ tableData.addFirst(rowData);
+ }
return true;
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/RangeSelector.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/RangeSelector.java
index feb47c8..8605a70 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/UI/RangeSelector.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/RangeSelector.java
@@ -1,15 +1,10 @@
package org.vcell.N5.UI;
-import org.scijava.log.Logger;
-import org.vcell.N5.N5ImageHandler;
-
import javax.swing.*;
import javax.swing.event.EventListenerList;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
public class RangeSelector extends JDialog implements ActionListener {
public int startC;
@@ -19,35 +14,39 @@ public class RangeSelector extends JDialog implements ActionListener {
public int startZ;
public int endZ;
- private final JTextField channelStartTextField;
- private final JTextField channelEndTextField;
- private final JTextField timeStartTextField;
- private final JTextField timeEndTextField;
- private final JTextField zStartTextField;
- private final JTextField zEndTextField;
+ private JTextField channelStartTextField;
+ private JTextField channelEndTextField;
+ private JTextField timeStartTextField;
+ private JTextField timeEndTextField;
+ private JTextField zStartTextField;
+ private JTextField zEndTextField;
public boolean cancel;
private static final String okayButtonText = "Okay";
private static final String cancelButtonText = "Cancel";
- public final JButton okayButton;
- public final JButton cancelButton;
- private final JFrame frame;
+ public JButton okayButton;
+ public JButton cancelButton;
+ private JFrame frame;
- private static final Logger logger = N5ImageHandler.getLogger(RangeSelector.class);
private static final EventListenerList eventListenerList = new EventListenerList();
private final ControlButtonsPanel controlButtonsPanel = MainPanel.controlButtonsPanel;
- public RangeSelector(double cDim, double zDim, double tDim, String userSetFileName){
- channelStartTextField = new HintTextField("1");
+ public RangeSelector(){
+
+ }
+
+ public void displayRangeMenu(double cDim, double zDim, double tDim){
channelEndTextField = new HintTextField("" + (int) cDim);
+ zEndTextField = new HintTextField("" + (int) zDim);
+ timeEndTextField = new HintTextField("" + (int) tDim);
+ String userSetFileName = "Range for All Images Used";
+ channelStartTextField = new HintTextField("1");
zStartTextField = new HintTextField("1");
- zEndTextField = new HintTextField("" + (int) zDim);
timeStartTextField = new HintTextField("1");
- timeEndTextField = new HintTextField("" + (int) tDim);
// Create the frame
frame = new JFrame("Select " + userSetFileName + " Dimensions");
@@ -93,15 +92,12 @@ public RangeSelector(double cDim, double zDim, double tDim, String userSetFileNa
frame.add(panel);
this.setContentPane(panel);
this.setModal(true);
- }
-
- public void displayRangeMenu(){
// Make the window visible
this.setVisible(true);
}
public static void main(String[] args) {
- RangeSelector inMemoryPopUp = new RangeSelector(1, 2, 3, null);
+ RangeSelector inMemoryPopUp = new RangeSelector();
}
@Override
@@ -122,50 +118,9 @@ public void actionPerformed(ActionEvent e) {
else if (e.getSource().equals(cancelButton)) {
MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR));
- controlButtonsPanel.enableCriticalButtons(true);
+ controlButtonsPanel.enableAllButtons(true);
cancel = true;
this.setVisible(false);
}
}
-
- static class HintTextField extends JTextField {
-
- Font gainFont = new Font("Tahoma", Font.PLAIN, 11);
- Font lostFont = new Font("Tahoma", Font.ITALIC, 11);
-
- public HintTextField(final String hint) {
-
- setText(hint);
- setFont(lostFont);
- setForeground(Color.GRAY);
-
- this.addFocusListener(new FocusAdapter() {
-
- @Override
- public void focusGained(FocusEvent e) {
- if (getText().equals(hint)) {
- setText("");
- setFont(gainFont);
- } else {
- setText(getText());
- setFont(gainFont);
- }
- }
-
- @Override
- public void focusLost(FocusEvent e) {
- if (getText().equals(hint)|| getText().isEmpty()) {
- setText(hint);
- setFont(lostFont);
- setForeground(Color.GRAY);
- } else {
- setText(getText());
- setFont(gainFont);
- setForeground(Color.BLACK);
- }
- }
- });
-
- }
- }
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java
index 6f0f827..eadf2bd 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java
@@ -95,8 +95,10 @@ public String getS3URL(){
@Override
public void actionPerformed(ActionEvent e) {
- SimResultsLoader simResultsLoader = new SimResultsLoader(getS3URL(), "", -1, "");
- N5ImageHandler.loadingFactory.openN5FileDataset(new ArrayList(){{add(simResultsLoader);}}, false);
+ SimResultsLoader simResultsLoader = new SimResultsLoader(getS3URL(), "", -1, "", SimResultsLoader.OpenTag.VIEW);
+ N5ImageHandler.loadingManager.openN5FileDataset(new ArrayList(){{add(simResultsLoader);}},
+ false,
+ false);
this.setVisible(false);
}
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/DTO/RangeOfImage.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DTO/RangeOfImage.java
new file mode 100644
index 0000000..fe23c90
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DTO/RangeOfImage.java
@@ -0,0 +1,45 @@
+package org.vcell.N5.reduction.DTO;
+
+public class RangeOfImage {
+ public final int timeStart;
+ public final int timeEnd;
+ public final int zStart;
+ public final int zEnd;
+ public final int channelStart;
+ public final int channelEnd;
+
+ public RangeOfImage(int timeStart, int timeEnd, int zStart, int zEnd, int channelStart, int channelEnd) {
+ this.timeStart = timeStart;
+ this.timeEnd = timeEnd;
+ this.zStart = zStart;
+ this.zEnd = zEnd;
+ this.channelStart = channelStart;
+ this.channelEnd = channelEnd;
+ }
+
+ public int getNChannels(){
+ return this.channelEnd - this.channelStart + 1;
+ }
+
+ public int getNFrames(){
+ return this.timeEnd - this.timeStart + 1;
+ }
+
+ public int getNSlices(){
+ return this.zEnd - this.zStart + 1;
+ }
+
+ /**
+ * Only regards time for range, and is used for normalization.
+ * @param timeStart
+ * @param timeEnd
+ */
+ public RangeOfImage(int timeStart, int timeEnd){
+ this.timeStart = timeStart;
+ this.timeEnd = timeEnd;
+ this.zStart = Integer.MIN_VALUE;
+ this.zEnd = Integer.MIN_VALUE;
+ this.channelStart = Integer.MIN_VALUE;
+ this.channelEnd = Integer.MIN_VALUE;
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/DTO/ReducedData.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DTO/ReducedData.java
new file mode 100644
index 0000000..2984c9f
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DTO/ReducedData.java
@@ -0,0 +1,47 @@
+package org.vcell.N5.reduction.DTO;
+
+import org.vcell.N5.reduction.GUI.SelectMeasurements;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+// Per Image, contain all ROI data
+// Shape: [time * z][channel * roi]
+public class ReducedData {
+ private final int nChannels;
+ private final int nSlices;
+ private final HashMap dataMap = new HashMap<>();
+
+ public final ArrayList measurements;
+ public final RangeOfImage rangeOfImage;
+ public final int nROIs;
+ public final HashMap roiNames = new HashMap<>();
+ public final HashMap channelNames = new HashMap<>();
+ public final String imageName;
+ public ReducedData(String imageName, RangeOfImage rangeOfImage, int nROIs, ArrayList measurements){
+ int nFrames = rangeOfImage.timeEnd - rangeOfImage.timeStart + 1;
+ nSlices = rangeOfImage.zEnd - rangeOfImage.zStart + 1;
+ this.measurements = measurements;
+ this.nChannels = rangeOfImage.getNChannels();
+ this.nROIs = nROIs;
+ this.rangeOfImage = rangeOfImage;
+ this.imageName = imageName;
+
+ for (SelectMeasurements.AvailableMeasurements measurement: measurements){
+ dataMap.put(measurement, new double[nFrames * nSlices][nChannels * nROIs]);
+ }
+ }
+
+ public void putDataPoint(double data,int time, int z, int channel, int roi, SelectMeasurements.AvailableMeasurements measurementType){
+ dataMap.get(measurementType)[(time * nSlices) + z][(roi * nChannels) + channel] = data;
+ }
+
+ public double getDataPoint(int time, int z, int channel, int roi, SelectMeasurements.AvailableMeasurements measurementType){
+ return dataMap.get(measurementType)[(time * nSlices) + z][(roi * nChannels) + channel];
+ }
+
+ public String getWideTableHeader(int r, int c){
+ return imageName + ":" + roiNames.get(r) + ":" + channelNames.get(c);
+ }
+
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/DataReductionManager.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DataReductionManager.java
new file mode 100644
index 0000000..1bce13a
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DataReductionManager.java
@@ -0,0 +1,204 @@
+package org.vcell.N5.reduction;
+
+import com.google.gson.internal.LinkedTreeMap;
+import ij.ImagePlus;
+import ij.WindowManager;
+import ij.gui.Roi;
+import org.jetbrains.annotations.NotNull;
+import org.vcell.N5.N5ImageHandler;
+import org.vcell.N5.UI.ControlButtonsPanel;
+import org.vcell.N5.UI.MainPanel;
+import org.vcell.N5.reduction.DTO.RangeOfImage;
+import org.vcell.N5.reduction.DTO.ReducedData;
+import org.vcell.N5.reduction.GUI.DataReductionGUI;
+import org.vcell.N5.retrieving.SimLoadingListener;
+import org.vcell.N5.retrieving.SimResultsLoader;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class DataReductionManager implements SimLoadingListener {
+ private final ArrayList arrayOfSimRois;
+ private final Object csvMatrixLock = new Object();
+
+ private int numOfImagesToOpen;
+ private final ReductionCalculations calculations;
+
+ public final DataReductionGUI.DataReductionSubmission submission;
+
+ private final ConcurrentHashMap threadPool = new ConcurrentHashMap<>();
+ private final Object threadPoolLock = new Object();
+
+ private DataReductionWriter dataReductionWriter;
+
+ public DataReductionManager(DataReductionGUI.DataReductionSubmission submission){
+ N5ImageHandler.loadingManager.addSimLoadingListener(this);
+ this.submission = submission;
+
+ this.arrayOfSimRois = submission.arrayOfSimRois;
+ this.numOfImagesToOpen = submission.numOfSimImages + 1; // Plus one for the lab image
+ this.calculations = new ReductionCalculations(submission.normalizeMeasurementsBool);
+
+ Thread processLabResults = new Thread(() -> {
+ if (submission.arrayOfLabRois.isEmpty()){
+ int height = submission.labResults.getHeight();
+ int width = submission.labResults.getWidth();
+ Roi roi = new Roi(0, 0, width, height);
+ roi.setName("Entire Image");
+ submission.arrayOfLabRois.add(roi);
+ }
+ calculateAndAddResults(submission.labResults, submission.experiementNormRange, submission.experimentImageRange,
+ submission.arrayOfLabRois, null, "Lab");
+ synchronized (threadPoolLock){
+ threadPool.remove("Lab");
+ }
+ }, "Processing Lab Image");
+ ThreadStruct threadStruct = new ThreadStruct(submission.labResults, new AtomicBoolean(true), processLabResults);
+ synchronized (threadPoolLock){
+ threadPool.put("Lab", threadStruct);
+ }
+ }
+
+ ////////////////////////
+ // General Functions //
+ //////////////////////
+
+ private void calculateAndAddResults(ImagePlus imagePlus, RangeOfImage normRange,
+ RangeOfImage imageRange, ArrayList rois,
+ LinkedTreeMap> channelInfo,
+ String threadName){
+ HashMap normValue = null;
+ if (submission.normalizeMeasurementsBool){
+ normValue = calculations.calculateNormalValue(imagePlus, normRange, rois, imageRange);
+ }
+
+ ReducedData reducedData = new ReducedData(imagePlus.getTitle(), imageRange, arrayOfSimRois.size(), submission.selectedMeasurements);
+ calculations.addAppropriateHeaders(rois, imageRange, reducedData, channelInfo);
+
+ AtomicBoolean continueOperation = threadPool.get(threadName).continueOperation;
+ calculations.calculateStatistics(imagePlus, rois, normValue, reducedData, imageRange, continueOperation);
+ if (continueOperation.get()){
+ synchronized (csvMatrixLock){
+ try {
+ dataReductionWriter.consumeNewData(reducedData);
+ } catch (IOException e) {
+ stopAllThreads();
+ throw new RuntimeException(e);
+ }
+ numOfImagesToOpen -= 1;
+ }
+ }
+ if (numOfImagesToOpen == 0 && continueOperation.get()){
+ try{
+ dataReductionWriter.close();
+ } catch (IOException ioException){
+ throw new RuntimeException(ioException);
+ } finally {
+ N5ImageHandler.loadingManager.removeFromSimLoadingListener(this);
+ MainPanel.controlButtonsPanel.updateButtonsToMatchState(false, ControlButtonsPanel.PanelState.NOTHING_OR_LOADING_IMAGE);
+ }
+ }
+ }
+
+ public void stopAllThreads(){
+ synchronized (threadPoolLock){
+ for (String threadName: threadPool.keySet()){
+ ThreadStruct threadStruct = threadPool.get(threadName);
+ threadStruct.continueOperation.set(false);
+ // Experiment image is in thread pool, so trying to retrieve a results loader for it would not work
+ if (threadStruct.simResultsLoader != null){
+ SimResultsLoader loadedResults = threadStruct.simResultsLoader;
+ MainPanel.n5ExportTable.removeSpecificRowFromLoadingRows(loadedResults.rowNumber);
+ ImagePlus openImage = WindowManager.getImage(loadedResults.getImagePlus().getID());
+ if (openImage != null){
+ openImage.close();
+ }
+ }
+ threadPool.remove(threadName);
+ }
+ }
+ N5ImageHandler.loadingManager.removeFromSimLoadingListener(this);
+ MainPanel.controlButtonsPanel.updateButtonsToMatchState(false, ControlButtonsPanel.PanelState.NOTHING_OR_LOADING_IMAGE);
+ }
+
+
+ @Override
+ public void simIsLoading(int itemRow, String exportID) {
+
+ }
+
+ @Override
+ public void simFinishedLoading(SimResultsLoader loadedResults) {
+ if (loadedResults.openTag == SimResultsLoader.OpenTag.DATA_REDUCTION){
+ ThreadStruct threadStruct = getThreadStruct(loadedResults);
+ synchronized (threadPoolLock){
+ threadPool.put(loadedResults.exportID, threadStruct);
+ if (threadPool.size() == (submission.numOfSimImages + 1)){
+ int maxZ = 0;
+ int maxT = 0;
+ //
+ if (arrayOfSimRois.isEmpty() && !threadStruct.thread.getName().equals("Lab")){
+ int height = loadedResults.getImagePlus().getHeight();
+ int width = loadedResults.getImagePlus().getWidth();
+ Roi roi = new Roi(0, 0, width, height);
+ roi.setName("Entire Image");
+ arrayOfSimRois.add(roi);
+ }
+ for (String threadName : threadPool.keySet()){
+ int curZ = threadPool.get(threadName).imagePlus.getNSlices();
+ int curT = threadPool.get(threadName).imagePlus.getNFrames();
+ if (!threadName.equals("Lab") && submission.simImageRange.zEnd - submission.simImageRange.zStart == 0){
+ curZ = 1;
+ }
+ maxZ = Math.max(curZ, maxZ);
+ maxT = Math.max(curT, maxT);
+ }
+ dataReductionWriter = new DataReductionWriter(submission, maxT, maxZ);
+ dataReductionWriter.initializeDataSheets();
+ for (String threadName : threadPool.keySet()){
+ threadPool.get(threadName).thread.start();
+ }
+ }
+ }
+ }
+ }
+
+ private @NotNull ThreadStruct getThreadStruct(SimResultsLoader loadedResults) {
+ Thread imageProcessingThread = new Thread(() -> {
+ ImagePlus imagePlus = loadedResults.getImagePlus();
+ imagePlus.show();
+ dataReductionWriter.addMetaData(loadedResults);
+ calculateAndAddResults(imagePlus, submission.simNormRange, submission.simImageRange,
+ submission.arrayOfSimRois, loadedResults.getChannelInfo(), loadedResults.exportID);
+ MainPanel.n5ExportTable.removeSpecificRowFromLoadingRows(loadedResults.rowNumber);
+ imagePlus.close();
+ synchronized (threadPoolLock){
+ threadPool.remove(loadedResults.exportID);
+ }
+ }, "Processing Image: " + loadedResults.userSetFileName);
+ return new ThreadStruct(loadedResults, new AtomicBoolean(true), imageProcessingThread);
+ }
+
+ static class ThreadStruct {
+ public final SimResultsLoader simResultsLoader;
+ public final ImagePlus imagePlus;
+ public final AtomicBoolean continueOperation;
+ public final Thread thread;
+ public ThreadStruct(SimResultsLoader simResultsLoader, AtomicBoolean continueOperation, Thread thread){
+ this.simResultsLoader = simResultsLoader;
+ this.continueOperation = continueOperation;
+ this.thread = thread;
+ this.imagePlus = simResultsLoader.getImagePlus();
+ }
+
+ public ThreadStruct(ImagePlus imagePlus, AtomicBoolean continueOperation, Thread thread){
+ this.imagePlus = imagePlus;
+ this.simResultsLoader = null;
+ this.continueOperation = continueOperation;
+ this.thread = thread;
+ }
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/DataReductionWriter.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DataReductionWriter.java
new file mode 100644
index 0000000..65c5509
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/DataReductionWriter.java
@@ -0,0 +1,268 @@
+package org.vcell.N5.reduction;
+
+import com.opencsv.CSVWriter;
+import org.vcell.N5.ExportDataRepresentation;
+import org.vcell.N5.UI.MainPanel;
+import org.vcell.N5.UI.N5ExportTable;
+import org.vcell.N5.reduction.DTO.RangeOfImage;
+import org.vcell.N5.reduction.DTO.ReducedData;
+import org.vcell.N5.reduction.GUI.DataReductionGUI;
+import org.vcell.N5.reduction.GUI.SelectMeasurements;
+import org.vcell.N5.retrieving.SimResultsLoader;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class DataReductionWriter{
+ private final Object metaDataLock = new Object();
+ private final File file;
+
+ public final DataReductionGUI.DataReductionSubmission submission;
+
+ private final ArrayList> averageMatrix = new ArrayList<>();
+ private final ArrayList> standardDivMatrix = new ArrayList<>();
+ private final ArrayList> maxIntensityMatrix = new ArrayList<>();
+ private final ArrayList> minIntensityMatrix = new ArrayList<>();
+ private final ArrayList> metaDataSheet = new ArrayList<>();
+
+
+ private final HashMap>> sheetsAvailable = new HashMap>>(){{
+ put(SelectMeasurements.AvailableMeasurements.AVERAGE, averageMatrix);
+ put(SelectMeasurements.AvailableMeasurements.STD_DEV, standardDivMatrix);
+ put(SelectMeasurements.AvailableMeasurements.MAX_INTENSITY, maxIntensityMatrix);
+ put(SelectMeasurements.AvailableMeasurements.MIN_INTENSITY, minIntensityMatrix);
+ }};
+ private final HashMap columnsForSheets = new HashMap<>();
+
+ private int metaDataParameterCol = 5;
+ private final HashMap parameterNameToCol = new HashMap<>();
+
+ private final ArrayList selectedMeasurements;
+
+ private final int maxZ;
+ private final int maxT;
+
+ private final boolean wideTable;
+
+ ///////////////////////////////////////
+ // Initialize Sheet and Lab results //
+ /////////////////////////////////////
+
+ public DataReductionWriter(DataReductionGUI.DataReductionSubmission submission, int maxT, int maxZ){
+ this.submission = submission;
+ this.selectedMeasurements = submission.selectedMeasurements;
+ this.file = submission.fileToSaveResultsTo;
+ this.maxZ = maxZ;
+ this.maxT = maxT;
+ this.wideTable = submission.wideTable;
+ }
+
+ public void consumeNewData(ReducedData reducedData) throws IOException {
+ if (wideTable){
+ addValuesToWideCSVMatrix(reducedData);
+ } else {
+ appendAndWriteTallTable(reducedData);
+ }
+ }
+
+ public void close() throws IOException {
+ if (wideTable){
+ writeWideTableCSVMatrix();
+ }
+ writeMetaDataTable();
+ }
+
+ public void initializeDataSheets(){
+ ArrayList headers = new ArrayList(){{add("Time Frame");}};
+ boolean is3D = maxZ > 1;
+
+ // Add Time and Z-Index Columns
+
+
+ metaDataSheet.add(new ArrayList<>());
+ metaDataSheet.get(0).add("");
+ metaDataSheet.get(0).add("BioModel Name");
+ metaDataSheet.get(0).add("Application Name");
+ metaDataSheet.get(0).add("Simulation Name");
+ metaDataSheet.get(0).add("N5 URL");
+
+ if (wideTable){
+ // Fill in Time and Z-Index Columns with selected range
+ if (is3D){
+ headers.add("Z Index");
+ }
+ for (SelectMeasurements.AvailableMeasurements measurement : selectedMeasurements){
+ ArrayList> dataSheet = sheetsAvailable.get(measurement);
+ dataSheet.add(new ArrayList<>());
+ ArrayList headerRow = dataSheet.get(0);
+
+ for (int i = 0; i < headers.size(); i++){
+ headerRow.add(i, headers.get(i));
+ }
+ columnsForSheets.put(measurement, headers.size() + 1);
+ }
+
+ for (SelectMeasurements.AvailableMeasurements measurement : selectedMeasurements){
+ ArrayList> dataSheet = sheetsAvailable.get(measurement);
+ for (int t = 1; t <= maxT; t++){
+ for (int z = 1; z <= maxZ; z++){
+ ArrayList pointRow = new ArrayList<>();
+ pointRow.add(0, String.valueOf(t));
+ if (is3D){
+ pointRow.add(1, String.valueOf(z));
+ }
+ dataSheet.add(pointRow);
+ }
+ }
+ }
+ } else {
+ headers.add(1, "Z Index");
+ headers.add("Image Name");
+ headers.add("ROI Name");
+ headers.add("Channel Name");
+ for (SelectMeasurements.AvailableMeasurements measurement : selectedMeasurements){
+ headers.add(measurement.publicName);
+ }
+ File file = new File(this.file.getAbsolutePath() + ".csv");
+ try(FileWriter fileWriter = new FileWriter(file)) {
+ CSVWriter csvWriter = new CSVWriter(fileWriter);
+ csvWriter.writeNext(headers.toArray(new String[0]));
+ } catch (IOException ioException){
+ throw new RuntimeException("Can't write to CSV file.", ioException);
+ }
+ }
+ }
+
+ // If parameter is not in list of parameters, add new column. If simulation does not have parameter say "not-present"
+ public void addMetaData(SimResultsLoader loadedResults){
+ synchronized (metaDataLock){
+ N5ExportTable n5ExportTable = MainPanel.n5ExportTable;
+ ExportDataRepresentation.SimulationExportDataRepresentation data = n5ExportTable.n5ExportTableModel.getRowData(loadedResults.rowNumber);
+ ArrayList newMetaData = new ArrayList<>();
+ newMetaData.add(loadedResults.userSetFileName);
+ newMetaData.add(data.biomodelName);
+ newMetaData.add(data.applicationName);
+ newMetaData.add(data.simulationName);
+ newMetaData.add(data.uri);
+ ArrayList parameterValues = data.differentParameterValues;
+ for (String s : parameterValues){
+ String[] tokens = s.split(":");
+ String colValue = tokens[1] + ":" + tokens[2];
+ if (parameterNameToCol.containsKey(tokens[0])){
+ int col = parameterNameToCol.get(tokens[0]);
+ fillWithEmptySpace(newMetaData, col);
+ newMetaData.add(col, colValue);
+ } else{
+ metaDataSheet.get(0).add(tokens[0] + " (Default:Set Value)");
+ fillWithEmptySpace(newMetaData, metaDataParameterCol);
+ newMetaData.add(metaDataParameterCol, colValue);
+ parameterNameToCol.put(tokens[0], metaDataParameterCol);
+ metaDataParameterCol += 1;
+ }
+ }
+ metaDataSheet.add(newMetaData);
+ }
+ }
+
+ ////////////////////////
+ // Private Functions //
+ //////////////////////
+
+ private void addValuesToWideCSVMatrix(ReducedData reducedData){
+ for (SelectMeasurements.AvailableMeasurements measurement: reducedData.measurements){
+ ArrayList> dataSheet = sheetsAvailable.get(measurement);
+ int colIndex = columnsForSheets.get(measurement);
+ fillWithEmptySpace(dataSheet.get(0), colIndex);
+ RangeOfImage rangeOfImage = reducedData.rangeOfImage;
+ for (int c = 0; c < rangeOfImage.getNChannels(); c++){
+ for (int r = 0; r < reducedData.nROIs; r++){
+ dataSheet.get(0).add(colIndex, reducedData.getWideTableHeader(r, c));
+ int tzCounter = 1;
+ for (int t = 1; t <= maxT; t++){
+ for (int z = 1; z <= maxZ; z++){
+ boolean inBetweenTime = t <= rangeOfImage.timeEnd && rangeOfImage.timeStart <= t;
+ boolean onlyOneZ = rangeOfImage.zEnd - rangeOfImage.zStart == 0 && maxZ == 1;
+ boolean inBetweenZ = z <= rangeOfImage.zEnd && rangeOfImage.zStart <= z || onlyOneZ;
+ ArrayList row = dataSheet.get(tzCounter);
+ fillWithEmptySpace(row, colIndex);
+ if (inBetweenTime && inBetweenZ){
+ int nt = t - rangeOfImage.timeStart;
+ int nz = onlyOneZ ? 0 : z - rangeOfImage.zStart;
+ row.add(String.valueOf(reducedData.getDataPoint(nt, nz, c, r, measurement)));
+ }
+ tzCounter += 1;
+ }
+ }
+ colIndex += 1;
+ }
+ }
+ colIndex += 1;
+ columnsForSheets.replace(measurement, colIndex);
+ }
+ }
+
+ // If specific entry to be added isn't in array list length, add empty space until it is
+ private void fillWithEmptySpace(ArrayList arrayList, int col){
+ while (arrayList.size() < col){
+ arrayList.add("");
+ }
+ }
+
+ // Each reduced data is a different measurement type
+ private void appendAndWriteTallTable(ReducedData reducedData) throws IOException {
+ RangeOfImage rangeOfImage = reducedData.rangeOfImage;
+ for (int t = rangeOfImage.timeStart; t <= rangeOfImage.timeEnd; t++) {
+ for (int z = rangeOfImage.zStart; z <= rangeOfImage.zEnd; z++) {
+ for (int channel = 0; channel < rangeOfImage.getNChannels(); channel++){
+ for(int roi= 0; roi < reducedData.nROIs; roi++){
+ File file = new File(this.file.getAbsolutePath() + ".csv");
+ ArrayList newRow = new ArrayList<>(Arrays.asList(String.valueOf(t), String.valueOf(z),
+ reducedData.imageName, reducedData.roiNames.get(roi), reducedData.channelNames.get(channel)));
+ for (SelectMeasurements.AvailableMeasurements measurement : reducedData.measurements){
+ int nt = t - rangeOfImage.timeStart;
+ int nz = z - rangeOfImage.zStart;
+ newRow.add(String.valueOf(reducedData.getDataPoint(nt, nz, channel, roi, measurement)));
+ }
+ try (FileWriter fileWriter = new FileWriter(file, true)) {
+ CSVWriter csvWriter = new CSVWriter(fileWriter);
+ csvWriter.writeNext(newRow.toArray(new String[0]));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void writeWideTableCSVMatrix() throws IOException {
+ for (SelectMeasurements.AvailableMeasurements measurements : sheetsAvailable.keySet()){
+ if (!sheetsAvailable.get(measurements).isEmpty()){
+ File currentFile = new File(file.getAbsolutePath() + "-" + measurements.publicName + ".csv");
+ try (FileWriter fileWriter = new FileWriter(currentFile)){
+ CSVWriter csvWriter = new CSVWriter(fileWriter);
+ for (ArrayList row : sheetsAvailable.get(measurements)){
+ csvWriter.writeNext(row.toArray(new String[0]));
+ }
+ }
+ }
+ }
+ }
+
+ private void writeMetaDataTable() throws IOException {
+ File currentFile = new File(file.getAbsolutePath() + "-Metadata.csv");
+ try (FileWriter fileWriter = new FileWriter(currentFile)){
+ CSVWriter csvWriter = new CSVWriter(fileWriter);
+ for (ArrayList row : metaDataSheet){
+ csvWriter.writeNext(row.toArray(new String[0]));
+ }
+ }
+ }
+}
+
+
+
+
+
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/DataReductionGUI.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/DataReductionGUI.java
new file mode 100644
index 0000000..7be7adf
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/DataReductionGUI.java
@@ -0,0 +1,231 @@
+package org.vcell.N5.reduction.GUI;
+
+import ij.ImagePlus;
+import ij.WindowManager;
+import ij.gui.Roi;
+import org.vcell.N5.UI.ControlButtonsPanel;
+import org.vcell.N5.UI.MainPanel;
+import org.vcell.N5.reduction.DTO.RangeOfImage;
+import org.vcell.N5.retrieving.SimResultsLoader;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.ArrayList;
+
+public class DataReductionGUI extends JPanel implements ActionListener {
+ private JComboBox chosenImage;
+ private final JCheckBox selectRangeOfMeasurement = new JCheckBox("Select Measurement Range: ");
+ private final JCheckBox normalizeMeasurement = new JCheckBox("Normalize Measurement: ");
+ private final JCheckBox choseCSVTableFormat = new JCheckBox("Choose CSV Format: ");
+
+ private final JDialog jDialog = new JDialog(MainPanel.exportTableDialog, true);
+ private final JButton okayButton = new JButton("Okay");
+ private final JButton cancelButton = new JButton("Cancel");
+ private File chosenFile;
+
+ private final ArrayList filesToOpen;
+
+ public int fileChooserReturnValue;
+
+ private final SelectSimRange selectSimRange;
+ private final RoiSelection roiSelection;
+ private final NormalizeGUI normalizeGUI;
+ private final SelectMeasurements selectMeasurements;
+ private final SelectTableFormat selectTableFormat;
+
+ private boolean continueWithProcess = false;
+
+ private final Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
+
+ public DataReductionGUI(ArrayList filesToOpen, double simCSize, double simZSize, double simTSize){
+ this.filesToOpen = filesToOpen;
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ okayButton.setEnabled(false);
+
+
+ selectSimRange = new SelectSimRange(jDialog, simCSize, simZSize, simTSize);
+ roiSelection = new RoiSelection(this);
+ normalizeGUI = new NormalizeGUI(jDialog, simTSize);
+ selectMeasurements = new SelectMeasurements(this);
+ selectTableFormat = new SelectTableFormat();
+
+ JPanel imagesToMeasurePanel = new JPanel();
+ imagesToMeasurePanel.setLayout(new BoxLayout(imagesToMeasurePanel, BoxLayout.Y_AXIS));
+ imagesToMeasurePanel.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Images To Measure"));
+ imagesToMeasurePanel.add(imageSelectionPanel());
+ imagesToMeasurePanel.add(selectedImagesToOpenPanel());
+
+ add(imagesToMeasurePanel);
+ add(roiSelection);
+ add(selectMeasurements);
+ add(displayOptionsPanel());
+ add(selectTableFormat);
+// add(normalizeGUI);
+ add(selectSimRange);
+ add(okayCancelPanel());
+
+ setVisible(true);
+
+ okayButton.addActionListener(this);
+ cancelButton.addActionListener(this);
+ normalizeMeasurement.addActionListener(this);
+ selectRangeOfMeasurement.addActionListener(this);
+ choseCSVTableFormat.addActionListener(this);
+
+ this.setBorder(new EmptyBorder(15, 12, 15, 12));
+
+ jDialog.add(this);
+ jDialog.setVisible(true);
+ jDialog.setResizable(true);
+ jDialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
+ jDialog.setTitle("Measurement Script");
+ jDialog.pack();
+ }
+
+ public DataReductionSubmission createSubmission(){
+ int[] simRange = normalizeGUI.getSimTimRange();
+ int[] labRange = normalizeGUI.getImageTimeRange();
+ return new DataReductionSubmission(normalizeMeasurement.isSelected(),
+ roiSelection.getSimROIList(), roiSelection.getImageROIList(),
+ WindowManager.getImage((String) chosenImage.getSelectedItem()),
+ simRange[0], simRange[1], labRange[0], labRange[1], filesToOpen.size(), chosenFile,
+ selectSimRange.getRangeOfSim(), selectMeasurements.getChosenMeasurements(), selectTableFormat.isWideTableSelected());
+ }
+
+ private JPanel okayCancelPanel(){
+ JPanel jPanel = new JPanel();
+ jPanel.add(okayButton);
+ jPanel.add(cancelButton);
+ return jPanel;
+ }
+
+ private JPanel imageSelectionPanel(){
+ JPanel jPanel = new JPanel(new GridLayout(1, 2));
+ jPanel.add(new JLabel("Experimental"));
+ chosenImage = new JComboBox<>(WindowManager.getImageTitles());
+ jPanel.add(chosenImage);
+ return jPanel;
+ }
+
+ private JPanel selectedImagesToOpenPanel(){
+ JPanel jPanel = new JPanel();
+ String[] namesOfImagesToOpen = new String[filesToOpen.size()];
+ for (int i = 0; i < filesToOpen.size(); i++){
+ namesOfImagesToOpen[i] = filesToOpen.get(i).userSetFileName;
+ }
+ JList selectedImagesToOpen = new JList<>(namesOfImagesToOpen);
+ selectedImagesToOpen.setEnabled(false);
+ selectedImagesToOpen.setVisibleRowCount(4);
+ JScrollPane jScrollPane = new JScrollPane(selectedImagesToOpen);
+ jPanel.add(new JLabel("Selected Simulations"));
+ jPanel.add(jScrollPane);
+ jPanel.setLayout(new GridLayout(1, 2));
+ return jPanel;
+ }
+
+ private JPanel displayOptionsPanel(){
+ JPanel jPanel = new JPanel();
+ jPanel.setLayout(new BoxLayout(jPanel, BoxLayout.X_AXIS));
+// jPanel.add(normalizeMeasurement);
+ jPanel.add(selectRangeOfMeasurement);
+ jPanel.add(choseCSVTableFormat);
+ return jPanel;
+ }
+
+ public void activateOkayButton(){
+ boolean selectedAMeasurement = !selectMeasurements.getChosenMeasurements().isEmpty();
+ boolean chosenExperimentImage = chosenImage.getSelectedItem() != null;
+// boolean roisIsSelected = !roiSelection.getImageROIList().isEmpty() && !roiSelection.getSimROIList().isEmpty();
+ okayButton.setEnabled(selectedAMeasurement && chosenExperimentImage);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource().equals(normalizeMeasurement)) {
+ normalizeGUI.setVisible(normalizeMeasurement.isSelected());
+ } else if (e.getSource().equals(selectRangeOfMeasurement)){
+ selectSimRange.setVisible(selectRangeOfMeasurement.isSelected());
+ } else if (e.getSource().equals(choseCSVTableFormat)) {
+ selectTableFormat.setVisible(choseCSVTableFormat.isSelected());
+ selectTableFormat.revalidate();
+ selectTableFormat.repaint();
+ jDialog.revalidate();
+ jDialog.repaint();
+ jDialog.pack();
+ } else if (e.getSource().equals(okayButton)) {
+ JFileChooser saveToFile = new JFileChooser();
+ saveToFile.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ fileChooserReturnValue = saveToFile.showDialog(this, "Save Results To File");
+ if (fileChooserReturnValue == JFileChooser.APPROVE_OPTION){
+ chosenFile = saveToFile.getSelectedFile();
+ MainPanel.controlButtonsPanel.updateButtonsToMatchState();
+ continueWithProcess = true;
+ jDialog.dispose();
+ }
+ } else if (e.getSource().equals(cancelButton)) {
+ MainPanel.controlButtonsPanel.updateButtonsToMatchState(false, ControlButtonsPanel.PanelState.NOTHING_OR_LOADING_IMAGE);
+ jDialog.dispose();
+ }
+ }
+
+ public boolean shouldContinueWithProcess() {
+ return continueWithProcess;
+ }
+
+ public static class DataReductionSubmission{
+ public final boolean normalizeMeasurementsBool;
+ public final ArrayList arrayOfSimRois;
+ public final ArrayList arrayOfLabRois;
+ public final ImagePlus labResults;
+ public final int numOfSimImages;
+ public final File fileToSaveResultsTo;
+
+ public final RangeOfImage experiementNormRange;
+ public final RangeOfImage simNormRange;
+
+ public final RangeOfImage experimentImageRange;
+ public final RangeOfImage simImageRange;
+ public final ArrayList selectedMeasurements;
+
+ public final boolean wideTable;
+
+ public DataReductionSubmission(boolean normalizeMeasurementsBool, ArrayList arrayOfSimRois, ArrayList arrayOfLabRois,
+ ImagePlus labResults, int simStartPointNorm, int simEndPointNorm, int imageStartPointNorm,
+ int imageEndPointNorm, int numOfSimImages, File fileToSaveResultsTo,
+ RangeOfImage simRange, ArrayList selectedMeasurements, boolean wideTable){
+ this.normalizeMeasurementsBool = normalizeMeasurementsBool;
+ this.arrayOfLabRois = arrayOfLabRois;
+ this.arrayOfSimRois = arrayOfSimRois;
+ this.labResults = labResults;
+ this.numOfSimImages = numOfSimImages;
+ this.fileToSaveResultsTo = fileToSaveResultsTo;
+
+ this.experiementNormRange = new RangeOfImage(imageStartPointNorm, imageEndPointNorm);
+ this.simNormRange = new RangeOfImage(simStartPointNorm, simEndPointNorm);
+
+ this.experimentImageRange = new RangeOfImage(1, labResults.getNFrames(),
+ 1, labResults.getNSlices(), 1, labResults.getNChannels());
+ this.simImageRange = simRange;
+ this.selectedMeasurements = selectedMeasurements;
+ this.wideTable = wideTable;
+ }
+ }
+
+ public static void main(String[] args) {
+ DataReductionGUI dataReductionGUI = new DataReductionGUI(new ArrayList<>(), 0, 0, 0);
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/NormalizeGUI.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/NormalizeGUI.java
new file mode 100644
index 0000000..4072d8d
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/NormalizeGUI.java
@@ -0,0 +1,75 @@
+package org.vcell.N5.reduction.GUI;
+
+import org.vcell.N5.UI.HintTextField;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.EtchedBorder;
+import java.awt.*;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+class NormalizeGUI extends JPanel {
+ private final JTextField createNormFromImageStart;
+ private final JTextField createNormFromImageEnd;
+ private final JTextField createNormFromSimStart;
+ private final JTextField createNormFromSimEnd;
+ private final JPanel entireImageFramesJPanel;
+
+ public NormalizeGUI(JDialog jDialog, double simTSize){
+ Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
+ Border normalizeBorder = BorderFactory.createTitledBorder(lowerEtchedBorder, "Timeframe Range to Create Norm");
+
+ JPanel fromImage = new JPanel(new GridLayout());
+ createNormFromImageStart = new JTextField();
+ createNormFromImageEnd = new JTextField();
+ fromImage.add(new JLabel("Exp. Timeframe: "));
+ fromImage.add(createNormFromImageStart);
+ fromImage.add(new JLabel("to"));
+ fromImage.add(createNormFromImageEnd);
+
+ JPanel fromSim = new JPanel(new GridLayout());
+ createNormFromSimStart = new HintTextField("1");
+ createNormFromSimEnd = new HintTextField(String.valueOf((int) simTSize));
+ fromSim.add(new JLabel("Sim Timeframe: "));
+ fromSim.add(createNormFromSimStart);
+ fromSim.add(new JLabel("to"));
+ fromSim.add(createNormFromSimEnd);
+
+ entireImageFramesJPanel = new JPanel(new GridLayout(3, 1));
+ entireImageFramesJPanel.add(fromImage);
+ entireImageFramesJPanel.add(fromSim);
+ this.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentShown(ComponentEvent e) {
+ jDialog.revalidate();
+ jDialog.repaint();
+ jDialog.pack();
+ }
+ @Override
+ public void componentHidden(ComponentEvent e) {
+ jDialog.revalidate();
+ jDialog.repaint();
+ jDialog.pack();
+ }
+ });
+ this.add(entireImageFramesJPanel);
+ this.setBorder(normalizeBorder);
+ this.setVisible(false);
+ this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ }
+
+ public int[] getSimTimRange(){
+ return new int[]{
+ createNormFromSimStart.getText().isEmpty() ? Integer.MIN_VALUE : Integer.parseInt(createNormFromSimStart.getText()),
+ createNormFromSimEnd.getText().isEmpty() ? Integer.MIN_VALUE: Integer.parseInt(createNormFromSimEnd.getText())
+ };
+ }
+
+ public int[] getImageTimeRange(){
+ return new int[]{
+ createNormFromImageStart.getText().isEmpty() ? Integer.MIN_VALUE: Integer.parseInt(createNormFromImageStart.getText()),
+ createNormFromImageEnd.getText().isEmpty() ? Integer.MIN_VALUE: Integer.parseInt(createNormFromImageEnd.getText())
+ };
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/RoiSelection.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/RoiSelection.java
new file mode 100644
index 0000000..731ded8
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/RoiSelection.java
@@ -0,0 +1,120 @@
+package org.vcell.N5.reduction.GUI;
+
+import ij.gui.Roi;
+import ij.io.RoiDecoder;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.ArrayList;
+
+class RoiSelection extends JPanel {
+ private final ROIDataModel imageTableModel = new ROIDataModel();
+ private final ROIDataModel simTableModel = new ROIDataModel();
+ private final DataReductionGUI parentGUI;
+
+ public RoiSelection(DataReductionGUI parentGUI){
+ this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+
+ JList imageROITable = new JList<>(imageTableModel);
+ JFileChooser imageROIFileChooser = new JFileChooser();
+ this.add(createROIInput(imageROITable, imageTableModel, imageROIFileChooser, "Experimental"));
+
+ JList simROITable = new JList<>(simTableModel);
+ JFileChooser simROIFileChooser = new JFileChooser();
+ this.add(createROIInput(simROITable, simTableModel, simROIFileChooser, "Sim"));
+ this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Apply 2D ROI Files"));
+ this.parentGUI = parentGUI;
+ }
+
+ private JPanel createROIInput(JList jList, ROIDataModel roiDataModel,
+ JFileChooser fileChooser, String label){
+ JPanel jPanel = new JPanel();
+ jPanel.setLayout(new BoxLayout(jPanel, BoxLayout.Y_AXIS));
+ jList.setVisibleRowCount(4);
+ JScrollPane jScrollPane = new JScrollPane(jList);
+ jPanel.add(jScrollPane);
+
+ JButton addButton = new JButton("+");
+ addButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ ArrayList roiList = fillROIList(fileChooser);
+ for (Roi roi : roiList){
+ roiDataModel.addRow(roi);
+ }
+ parentGUI.activateOkayButton();
+ jList.updateUI();
+ }
+ });
+ JButton minusButton = new JButton("-");
+ minusButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ for (int roiIndex: jList.getSelectedIndices()){
+ roiDataModel.removeRow(roiIndex);
+ }
+ parentGUI.activateOkayButton();
+ jList.updateUI();
+ }
+ });
+ JPanel buttonPanel = new JPanel(new GridLayout(1, 2));
+ buttonPanel.add(addButton);
+ buttonPanel.add(minusButton);
+ jPanel.add(buttonPanel);
+ jPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), label));
+
+ return jPanel;
+ }
+
+ public ArrayList getImageROIList(){
+ return imageTableModel.data;
+ }
+
+ public ArrayList getSimROIList(){
+ return simTableModel.data;
+ }
+
+ private void setROIPanelSettings(JPanel jPanel, JButton button, JScrollPane jScrollPane){
+ GridBagConstraints gridBagConstraints = new GridBagConstraints();
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.fill = GridBagConstraints.BOTH;
+ gridBagConstraints.insets = new Insets(5, 5, 5, 5);
+ jPanel.add(button, gridBagConstraints);
+ gridBagConstraints.gridy = 1;
+ jPanel.add(jScrollPane, gridBagConstraints);
+ }
+
+ private ArrayList fillROIList(JFileChooser fileChooser){
+ fileChooser.setMultiSelectionEnabled(true);
+ int choice = fileChooser.showDialog(this, "Open ROI's");
+ ArrayList roiList = new ArrayList<>();
+ if (choice == JFileChooser.APPROVE_OPTION){
+ for (File file: fileChooser.getSelectedFiles()){
+ roiList.add(RoiDecoder.open(file.getAbsolutePath()));
+ }
+ }
+ return roiList;
+ }
+
+ static class ROIDataModel extends AbstractListModel {
+ private final ArrayList data = new ArrayList<>();
+ public void addRow(Roi roi){
+ data.add(roi);
+ }
+ public void removeRow(int index){data.remove(index);}
+
+ @Override
+ public int getSize() {
+ return data.size();
+ }
+
+ @Override
+ public String getElementAt(int index) {
+ return data.get(index).getName();
+ }
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectMeasurements.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectMeasurements.java
new file mode 100644
index 0000000..782ca42
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectMeasurements.java
@@ -0,0 +1,71 @@
+package org.vcell.N5.reduction.GUI;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import java.awt.*;
+import java.util.ArrayList;
+
+public class SelectMeasurements extends JPanel implements ListSelectionListener {
+ private final JList chosenMeasurement;
+ private final MeasurementsDataModel measurementsDataModel = new MeasurementsDataModel();
+ private final DataReductionGUI parentGUI;
+
+ public SelectMeasurements(DataReductionGUI parentGUI){
+ setLayout(new GridLayout(1, 1));
+ this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Measurement Type"));
+ chosenMeasurement = new JList<>(measurementsDataModel);
+ chosenMeasurement.setVisibleRowCount(3);
+ chosenMeasurement.addListSelectionListener(this);
+ JScrollPane jScrollPane = new JScrollPane(chosenMeasurement);
+ this.add(jScrollPane);
+ this.parentGUI = parentGUI;
+ }
+
+ public ArrayList getChosenMeasurements(){
+ return measurementsDataModel.getSelectedMeasurements(chosenMeasurement.getSelectedIndices());
+ }
+
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ if (e.getSource().equals(chosenMeasurement)){
+ parentGUI.activateOkayButton();
+ }
+ }
+
+ public enum AvailableMeasurements{
+ AVERAGE("Average"),
+ STD_DEV("Standard Deviation"),
+ MAX_INTENSITY("Max Intensity"),
+ MIN_INTENSITY("Minimum Intensity");
+
+ public final String publicName;
+ AvailableMeasurements(String publicName){
+ this.publicName = publicName;
+ }
+ }
+
+ static class MeasurementsDataModel extends AbstractListModel{
+ private final AvailableMeasurements[] availableMeasurements = new AvailableMeasurements[]{
+ AvailableMeasurements.AVERAGE, AvailableMeasurements.STD_DEV, AvailableMeasurements.MAX_INTENSITY, AvailableMeasurements.MIN_INTENSITY};
+
+ public ArrayList getSelectedMeasurements(int[] indices){
+ ArrayList selected = new ArrayList<>();
+ for (int i : indices){
+ selected.add(availableMeasurements[i]);
+ }
+ return selected;
+ }
+
+ @Override
+ public int getSize() {
+ return availableMeasurements.length;
+ }
+
+ @Override
+ public String getElementAt(int index) {
+ return availableMeasurements[index].publicName;
+ }
+ }
+
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectSimRange.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectSimRange.java
new file mode 100644
index 0000000..600b57c
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectSimRange.java
@@ -0,0 +1,85 @@
+package org.vcell.N5.reduction.GUI;
+
+import org.vcell.N5.UI.HintTextField;
+import org.vcell.N5.reduction.DTO.RangeOfImage;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.EtchedBorder;
+import java.awt.*;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+class SelectSimRange extends JPanel {
+ private final JTextField cStart = new HintTextField("1");
+ private final JTextField cEnd;
+
+ private final JTextField zStart = new HintTextField("1");
+ private final JTextField zEnd;
+
+ private final JTextField tStart = new HintTextField("1");
+ private final JTextField tEnd;
+
+ public SelectSimRange(JDialog jDialog, double simCSize, double simZSize, double simTSize){
+ Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
+ Border rangeBorder = BorderFactory.createTitledBorder(lowerEtchedBorder, "Range of Simulation to Perform Measurement");
+ cEnd = new HintTextField(String.valueOf((int) simCSize - 1));
+ zEnd = new HintTextField(String.valueOf((int) simZSize));
+ tEnd = new HintTextField(String.valueOf((int) simTSize));
+
+ JPanel cRange = new JPanel(new GridLayout());
+ cRange.add(new JLabel("Channel Range: "));
+ cRange.add(cStart);
+ cRange.add(new JLabel("to"));
+ cRange.add(cEnd);
+
+ JPanel zRange = new JPanel(new GridLayout());
+ zRange.add(new JLabel("Z Range: "));
+ zRange.add(zStart);
+ zRange.add(new JLabel("to"));
+ zRange.add(zEnd);
+
+ JPanel tRange = new JPanel(new GridLayout());
+ tRange.add(new JLabel("Time Frame's: "));
+ tRange.add(tStart);
+ tRange.add(new JLabel("to"));
+ tRange.add(tEnd);
+
+ JPanel rangeSelectionPanel = new JPanel(new GridLayout(4, 1));
+ rangeSelectionPanel.add(cRange);
+ rangeSelectionPanel.add(zRange);
+ rangeSelectionPanel.add(tRange);
+
+ this.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentShown(ComponentEvent e) {
+ SelectSimRange.this.revalidate();
+ SelectSimRange.this.repaint();
+ jDialog.revalidate();
+ jDialog.repaint();
+ jDialog.pack();
+ }
+ @Override
+ public void componentHidden(ComponentEvent e) {
+ SelectSimRange.this.revalidate();
+ SelectSimRange.this.repaint();
+ jDialog.revalidate();
+ jDialog.repaint();
+ jDialog.pack();
+ }
+ });
+ this.add(rangeSelectionPanel);
+ this.setBorder(rangeBorder);
+ this.setVisible(false);
+ this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ }
+
+ public RangeOfImage getRangeOfSim(){
+ RangeOfImage rangeOfImage = new RangeOfImage(
+ Integer.parseInt(tStart.getText()), Integer.parseInt(tEnd.getText()),
+ Integer.parseInt(zStart.getText()), Integer.parseInt(zEnd.getText()),
+ Integer.parseInt(cStart.getText()), Integer.parseInt(cEnd.getText())
+ );
+ return rangeOfImage;
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectTableFormat.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectTableFormat.java
new file mode 100644
index 0000000..e90076a
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/GUI/SelectTableFormat.java
@@ -0,0 +1,29 @@
+package org.vcell.N5.reduction.GUI;
+
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+import java.awt.*;
+
+public class SelectTableFormat extends JPanel {
+ private final JRadioButton wideTable = new JRadioButton("Wide (Best for manual analysis)");
+
+ public SelectTableFormat(){
+ this.setLayout(new GridLayout(1,1));
+ ButtonGroup buttonGroup = new ButtonGroup();
+ buttonGroup.add(wideTable);
+ JRadioButton tallTable = new JRadioButton("Tall (Best for scripts)");
+ buttonGroup.add(tallTable);
+ this.add(wideTable);
+ this.add(tallTable);
+ this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), "Select CSV Table Format:"));
+ wideTable.setSelected(true);
+ this.setVisible(false);
+ }
+
+
+ public boolean isWideTableSelected(){
+ return wideTable.isSelected();
+ }
+
+
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/ReductionCalculations.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/ReductionCalculations.java
new file mode 100644
index 0000000..8580906
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/ReductionCalculations.java
@@ -0,0 +1,113 @@
+package org.vcell.N5.reduction;
+
+import com.google.gson.internal.LinkedTreeMap;
+import ij.ImagePlus;
+import ij.gui.Roi;
+import org.vcell.N5.reduction.DTO.RangeOfImage;
+import org.vcell.N5.reduction.DTO.ReducedData;
+import org.vcell.N5.reduction.GUI.SelectMeasurements;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+class ReductionCalculations {
+ private final boolean normalize;
+
+ public ReductionCalculations(boolean normalize){
+ this.normalize = normalize;
+ }
+
+ public void addAppropriateHeaders(ArrayList roiList, RangeOfImage rangeOfImage,
+ ReducedData reducedData,
+ LinkedTreeMap> channelInfo){
+ for (int r = 0; r < roiList.size(); r++){
+ for (int c = rangeOfImage.channelStart; c <= rangeOfImage.channelEnd; c++){ //Last channel is domain channel, not variable
+ String stringC = String.valueOf(c - 1);
+ String channelName = channelInfo != null && channelInfo.containsKey(stringC) ? channelInfo.get(stringC).get("Name") : String.valueOf(c);
+ reducedData.channelNames.put(c - 1, channelName);
+ reducedData.roiNames.put(r, roiList.get(r).getName());
+ }
+ }
+ }
+
+ /**
+ * Set position in image with specific ROI, and then with the appropriate reduced data store, perform the calculation
+ * and add it to reduced data.
+ * @param imagePlus
+ * @param roiList
+ * @param normalizationValue
+ * @param rangeOfImage
+ */
+ void calculateStatistics(ImagePlus imagePlus, ArrayList roiList,
+ HashMap normalizationValue,
+ ReducedData reducedData,
+ RangeOfImage rangeOfImage, AtomicBoolean continueOperation){
+ for (int roi = 0; roi < roiList.size(); roi++) {
+ imagePlus.setRoi(roiList.get(roi));
+ for (int t = rangeOfImage.timeStart; t <= rangeOfImage.timeEnd; t++){
+ for (int z = rangeOfImage.zStart; z <= rangeOfImage.zEnd; z++){
+ for (int c = rangeOfImage.channelStart; c <= rangeOfImage.channelEnd; c++){
+ if (!continueOperation.get()){
+ return;
+ }
+ imagePlus.setPosition(c, z, t);
+ int nT = t - rangeOfImage.timeStart;
+ int nZ = z - rangeOfImage.zStart;
+ int nC = c - rangeOfImage.channelStart;
+ double calculatedValue;
+ for (SelectMeasurements.AvailableMeasurements measurement : reducedData.measurements){
+ switch (measurement){
+ case AVERAGE:
+ calculatedValue = imagePlus.getStatistics().mean;
+ break;
+ case STD_DEV:
+ calculatedValue = imagePlus.getStatistics().stdDev;
+ break;
+ case MAX_INTENSITY:
+ calculatedValue = imagePlus.getStatistics().max;
+ break;
+ case MIN_INTENSITY:
+ calculatedValue = imagePlus.getStatistics().min;
+ break;
+ default:
+ throw new RuntimeException("Unknown measurement type selected.");
+ }
+ if (normalize){
+ calculatedValue = calculatedValue / normalizationValue.get(roiList.get(roi).getName() + c);
+ }
+ reducedData.putDataPoint(calculatedValue, nT, nZ, nC, roi, measurement);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ HashMap calculateNormalValue(ImagePlus imagePlus, RangeOfImage normRange,
+ ArrayList roiList, RangeOfImage rangeOfImage){
+ int startT = normRange.timeStart;
+ int endT = normRange.timeEnd;
+ HashMap result = new HashMap<>();
+ for (Roi roi : roiList){
+ imagePlus.setRoi(roi);
+ for (int c = rangeOfImage.channelStart; c <= rangeOfImage.channelEnd; c++){
+ double normal = 0;
+ for (int t = startT; t <= endT; t++){
+ double zAverage = 0;
+ for (int z = rangeOfImage.zStart; z <= rangeOfImage.zEnd; z++){
+ imagePlus.setPosition(c, z, t);
+ zAverage += imagePlus.getProcessor().getStatistics().mean;
+ }
+ zAverage = zAverage / (rangeOfImage.zEnd - rangeOfImage.zStart + 1);
+ normal += zAverage;
+ }
+ normal = normal / (endT - startT + 1); // inclusive of final point
+ result.put(roi.getName() + c, normal);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingFactory.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingFactory.java
deleted file mode 100644
index a673257..0000000
--- a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingFactory.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package org.vcell.N5.retrieving;
-
-import com.amazonaws.AbortedException;
-import com.amazonaws.http.timers.client.SdkInterruptedException;
-import ij.ImagePlus;
-import ij.plugin.Duplicator;
-import org.scijava.log.Logger;
-import org.vcell.N5.N5ImageHandler;
-import org.vcell.N5.UI.ControlButtonsPanel;
-import org.vcell.N5.UI.RangeSelector;
-import org.vcell.N5.UI.MainPanel;
-
-import javax.swing.*;
-import javax.swing.event.EventListenerList;
-import java.awt.*;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class LoadingFactory implements SimLoadingEventCreator {
- private static final EventListenerList eventListenerList = new EventListenerList();
-
- private final ControlButtonsPanel controlButtonsPanel = MainPanel.controlButtonsPanel;
-
- private final HashMap openingSimulations = new HashMap<>();
- private final Object openSimulationsLock = new Object();
-
- private static final Logger logger = N5ImageHandler.getLogger(RangeSelector.class);
-
- public void openN5FileDataset(ArrayList filesToOpen, boolean openInMemory){
- controlButtonsPanel.allowCancel(true);
- MainPanel.changeCursor(new Cursor(Cursor.WAIT_CURSOR));
-
- for (int i = 0; i < filesToOpen.size(); i++){
- SimResultsLoader simResultsLoader = filesToOpen.get(i);
- Thread openThread = new Thread(() -> {
- try{
- simResultsLoader.createS3ClientAndReader();
- notifySimIsLoading(simResultsLoader);
- RangeSelector rangeSelector;
- if (openInMemory){
- ArrayList dimensions = simResultsLoader.getN5Dimensions();
- rangeSelector = new RangeSelector(dimensions.get(2), dimensions.get(3), dimensions.get(4), simResultsLoader.userSetFileName);
- rangeSelector.displayRangeMenu();
- if (!rangeSelector.cancel){
- openInMemory(simResultsLoader, rangeSelector);
- }
- rangeSelector.dispose();
- } else{
- ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File();
- imagePlus.show();
- }
- }
- catch (RuntimeException e) {
- if (e.getCause().getCause().getCause() instanceof SdkInterruptedException ||
- e.getCause().getCause() instanceof AbortedException){
- logger.debug("Simulation stopped loading");
- } else {
- throw new RuntimeException(e);
- }
- }
- catch (Exception e){
- throw new RuntimeException(e);
- } finally {
- MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR));
- controlButtonsPanel.enableCriticalButtons(true);
- notifySimIsDoneLoading(simResultsLoader);
- synchronized (openSimulationsLock){
- openingSimulations.remove(simResultsLoader.exportID);
- }
- }
- });
- openThread.setName("Opening sim number: " + i + ". With id: " + simResultsLoader.exportID);
- synchronized (openSimulationsLock){
- openingSimulations.put(simResultsLoader.exportID, openThread);
- }
- openThread.start();
- }
- }
-
- private void openInMemory(SimResultsLoader simResultsLoader, RangeSelector rangeSelector) throws IOException {
- ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File();
- long start = System.currentTimeMillis();
- logger.debug("Loading Virtual N5 File " + simResultsLoader.userSetFileName + " Into Memory");
- imagePlus = new Duplicator().run(imagePlus, rangeSelector.startC, rangeSelector.endC, rangeSelector.startZ,
- rangeSelector.endZ, rangeSelector.startT, rangeSelector.endT);
- long end = System.currentTimeMillis();
- logger.debug("Loaded Virtual N5 File " + simResultsLoader.userSetFileName + " Into Memory taking: " + ((end - start)/ 1000) + "s");
- imagePlus.show();
- }
-
- public void stopOpeningSimulation(String exportID){
- Thread stopOtherThread = new Thread(() -> {
- synchronized (openSimulationsLock){
- openingSimulations.get(exportID).interrupt();
- openingSimulations.remove(exportID);
- }
- });
- stopOtherThread.start();
- }
-
- public void openLocalN5FS(ArrayList filesToOpen){
- controlButtonsPanel.enableCriticalButtons(true);
- JFileChooser fileChooser = new JFileChooser();
- fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- fileChooser.setAcceptAllFileFilterUsed(false);
- int result = fileChooser.showOpenDialog(null);
- if (result == JFileChooser.APPROVE_OPTION){
- File file = fileChooser.getSelectedFile();
- MainPanel.changeCursor(new Cursor(Cursor.WAIT_CURSOR));
- Thread openN5FileDataset = new Thread(() -> {
- try{
- for(SimResultsLoader simResultsLoader: filesToOpen){
- simResultsLoader.setSelectedLocalFile(file);
- ImagePlus imagePlus = simResultsLoader.getImgPlusFromLocalN5File();
- imagePlus.show();
- }
- } catch (IOException ex) {
- throw new RuntimeException(ex);
- } finally {
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR));
- controlButtonsPanel.enableCriticalButtons(true);
- }
- });
- }
- });
- openN5FileDataset.start();
- }
- }
-
- @Override
- public void addSimLoadingListener(SimLoadingListener simLoadingListener) {
- eventListenerList.add(SimLoadingListener.class, simLoadingListener);
- }
-
- @Override
- public void notifySimIsLoading(SimResultsLoader simResultsLoader) {
- for (SimLoadingListener simLoadingListener: eventListenerList.getListeners(SimLoadingListener.class)){
- simLoadingListener.simIsLoading(simResultsLoader.rowNumber, simResultsLoader.exportID);
- }
- }
-
- @Override
- public void notifySimIsDoneLoading(SimResultsLoader simResultsLoader) {
- for (SimLoadingListener simLoadingListener: eventListenerList.getListeners(SimLoadingListener.class)){
- simLoadingListener.simFinishedLoading(simResultsLoader.rowNumber, simResultsLoader.exportID);
- }
- }
-}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingManager.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingManager.java
new file mode 100644
index 0000000..c44ccac
--- /dev/null
+++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingManager.java
@@ -0,0 +1,172 @@
+package org.vcell.N5.retrieving;
+
+import com.amazonaws.AbortedException;
+import ij.ImagePlus;
+import org.scijava.log.Logger;
+import org.vcell.N5.N5ImageHandler;
+import org.vcell.N5.UI.ControlButtonsPanel;
+import org.vcell.N5.UI.RangeSelector;
+import org.vcell.N5.UI.MainPanel;
+import org.vcell.N5.reduction.GUI.DataReductionGUI;
+import org.vcell.N5.reduction.DataReductionManager;
+
+import javax.swing.*;
+import javax.swing.event.EventListenerList;
+import java.awt.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class LoadingManager implements SimLoadingEventCreator {
+ private static final EventListenerList eventListenerList = new EventListenerList();
+
+ private final ControlButtonsPanel controlButtonsPanel = MainPanel.controlButtonsPanel;
+
+ private final HashMap openingSimulations = new HashMap<>();
+ private final Object openSimulationsLock = new Object();
+ private DataReductionManager dataReductionWriter = null;
+
+ private static final Logger logger = N5ImageHandler.getLogger(RangeSelector.class);
+
+ public void openN5FileDataset(ArrayList filesToOpen, boolean openInMemory, boolean dataReduction){
+ RangeSelector rangeSelector = new RangeSelector();
+ DataReductionGUI dataReductionGUI = null;
+ if (dataReduction || openInMemory){
+ SimResultsLoader firstSim = filesToOpen.get(0);
+ firstSim.createS3ClientAndReader();
+ ArrayList dimensions = firstSim.getN5Dimensions();
+ if (dataReduction){
+ dataReductionGUI = new DataReductionGUI(filesToOpen, dimensions.get(2), dimensions.get(3), dimensions.get(4));
+ dataReductionWriter = dataReductionGUI.shouldContinueWithProcess() ? new DataReductionManager(dataReductionGUI.createSubmission()) : null;
+ } else {
+ rangeSelector.displayRangeMenu(dimensions.get(2), dimensions.get(3), dimensions.get(4));
+ }
+ }
+ boolean dataReductionOkay = dataReduction && dataReductionGUI.shouldContinueWithProcess();
+ if (dataReductionOkay || !dataReduction){
+ MainPanel.changeCursor(new Cursor(Cursor.WAIT_CURSOR));
+ for (int i = 0; i < filesToOpen.size(); i++){
+ SimResultsLoader simResultsLoader = filesToOpen.get(i);
+ Thread openThread = new Thread(() -> {
+ ImagePlus imagePlus = null;
+ try{
+ simResultsLoader.createS3ClientAndReader();
+ notifySimIsLoading(simResultsLoader);
+ if (openInMemory){
+ if (!rangeSelector.cancel){
+ imagePlus = simResultsLoader.openInMemory(rangeSelector);
+ }
+ } else{
+ simResultsLoader.loadImageFromN5File();
+ imagePlus = simResultsLoader.getImagePlus();
+ }
+ }
+ catch (RuntimeException e) {
+ simResultsLoader.setTagToCanceled();
+ MainPanel.n5ExportTable.removeSpecificRowFromLoadingRows(simResultsLoader.rowNumber);
+ if (e instanceof AbortedException){
+ logger.debug("Simulation stopped loading");
+ } else {
+ throw new RuntimeException(e);
+ }
+ } finally {
+ MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+ notifySimIsDoneLoading(simResultsLoader, imagePlus);
+ synchronized (openSimulationsLock){
+ openingSimulations.remove(simResultsLoader.exportID);
+ }
+ }
+ });
+ openThread.setName("Opening sim number: " + i + ". With id: " + simResultsLoader.exportID);
+ synchronized (openSimulationsLock){
+ openingSimulations.put(simResultsLoader.exportID, openThread);
+ }
+ openThread.start();
+ }
+ }
+ }
+
+ public void stopAllImagesAndAnalysis(){
+ Thread stopEverything = new Thread(() -> {
+ synchronized (openSimulationsLock){
+ for (String threadName : openingSimulations.keySet()){
+ openingSimulations.get(threadName).interrupt();
+ openingSimulations.remove(threadName);
+ }
+ }
+ if (dataReductionWriter != null){
+ dataReductionWriter.stopAllThreads();
+ }
+ });
+ stopEverything.start();
+ }
+
+
+ public void stopLoadingImage(String exportID){
+ Thread stopOtherThread = new Thread(() -> {
+ synchronized (openSimulationsLock){
+ if (openingSimulations.containsKey(exportID)){
+ openingSimulations.get(exportID).interrupt();
+ openingSimulations.remove(exportID);
+ }
+ }
+ });
+ stopOtherThread.start();
+ }
+
+ public void openLocalN5FS(ArrayList filesToOpen){
+ controlButtonsPanel.enableAllButtons(true);
+ JFileChooser fileChooser = new JFileChooser();
+ fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ fileChooser.setAcceptAllFileFilterUsed(false);
+ int result = fileChooser.showOpenDialog(null);
+ if (result == JFileChooser.APPROVE_OPTION){
+ File file = fileChooser.getSelectedFile();
+ MainPanel.changeCursor(new Cursor(Cursor.WAIT_CURSOR));
+ Thread openN5FileDataset = new Thread(() -> {
+ try{
+ for(SimResultsLoader simResultsLoader: filesToOpen){
+ simResultsLoader.setSelectedLocalFile(file);
+ ImagePlus imagePlus = simResultsLoader.getImgPlusFromLocalN5File();
+ imagePlus.show();
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+ controlButtonsPanel.enableAllButtons(true);
+ }
+ });
+ }
+ });
+ openN5FileDataset.start();
+ }
+ }
+
+ @Override
+ public void addSimLoadingListener(SimLoadingListener simLoadingListener) {
+ eventListenerList.add(SimLoadingListener.class, simLoadingListener);
+ }
+
+ public void removeFromSimLoadingListener(SimLoadingListener simLoadingListener){
+ eventListenerList.remove(SimLoadingListener.class, simLoadingListener);
+ }
+
+ @Override
+ public void notifySimIsLoading(SimResultsLoader simResultsLoader) {
+ for (SimLoadingListener simLoadingListener: eventListenerList.getListeners(SimLoadingListener.class)){
+ simLoadingListener.simIsLoading(simResultsLoader.rowNumber, simResultsLoader.exportID);
+ }
+ }
+
+ @Override
+ public void notifySimIsDoneLoading(SimResultsLoader simResultsLoader, ImagePlus imagePlus) {
+ for (SimLoadingListener simLoadingListener: eventListenerList.getListeners(SimLoadingListener.class)){
+ simLoadingListener.simFinishedLoading(simResultsLoader);
+ }
+ }
+}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingEventCreator.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingEventCreator.java
index 2a0a357..a69ac7e 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingEventCreator.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingEventCreator.java
@@ -1,10 +1,12 @@
package org.vcell.N5.retrieving;
+import ij.ImagePlus;
+
public interface SimLoadingEventCreator {
public void addSimLoadingListener(SimLoadingListener simLoadingListener);
public void notifySimIsLoading(SimResultsLoader simResultsLoader);
- public void notifySimIsDoneLoading(SimResultsLoader simResultsLoader);
+ public void notifySimIsDoneLoading(SimResultsLoader simResultsLoader, ImagePlus imagePlus);
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingListener.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingListener.java
index d2ddf09..e517f11 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingListener.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingListener.java
@@ -1,11 +1,13 @@
package org.vcell.N5.retrieving;
+import ij.ImagePlus;
+
import java.util.EventListener;
public interface SimLoadingListener extends EventListener {
public void simIsLoading(int itemRow, String exportID);
- public void simFinishedLoading(int itemRow, String exportID);
+ public void simFinishedLoading(SimResultsLoader loadedResult);
}
diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimResultsLoader.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimResultsLoader.java
index a3e9495..c005edf 100644
--- a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimResultsLoader.java
+++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimResultsLoader.java
@@ -8,8 +8,10 @@
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.google.gson.GsonBuilder;
+import com.google.gson.internal.LinkedTreeMap;
import ij.ImagePlus;
import ij.plugin.ContrastEnhancer;
+import ij.plugin.Duplicator;
import net.imglib2.cache.img.CachedCellImg;
import net.imglib2.img.display.imagej.ImageJFunctions;
import net.imglib2.type.numeric.real.DoubleType;
@@ -21,9 +23,9 @@
import org.janelia.saalfeldlab.n5.N5KeyValueReader;
import org.janelia.saalfeldlab.n5.N5Reader;
import org.janelia.saalfeldlab.n5.imglib2.N5Utils;
-import org.janelia.saalfeldlab.n5.s3.N5AmazonS3Reader;
import org.scijava.log.Logger;
import org.vcell.N5.N5ImageHandler;
+import org.vcell.N5.UI.RangeSelector;
import org.vcell.N5.library.extensions.S3KeyValueAccess;
import org.vcell.N5.library.extensions.SimCacheLoader;
@@ -39,34 +41,33 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
public class SimResultsLoader {
private File selectedLocalFile;
- private AmazonS3 s3Client;
- private String bucketName;
- private String s3ObjectKey;
private URI uri;
private String dataSetChosen;
- public String userSetFileName = null;
private static final String defaultS3Region = "site2-low";
- private N5Reader n5AmazonS3Reader;
-
+ private N5Reader n5AmazonS3Reader = null;
private static final Logger logger = N5ImageHandler.getLogger(SimResultsLoader.class);
public static AmazonS3ClientBuilder s3ClientBuilder;
+ private ImagePlus imagePlus = null;
+ public OpenTag openTag;
+
+
+ public String userSetFileName = null;
public int rowNumber;
public String exportID;
public SimResultsLoader(){
-
+ openTag = OpenTag.TEST;
}
- public SimResultsLoader(String stringURI, String userSetFileName, int rowNumber, String exportID){
- this(stringURI, userSetFileName);
+ public SimResultsLoader(String stringURI, String userSetFileName, int rowNumber, String exportID, OpenTag openTag){
+ this(stringURI, userSetFileName, openTag);
this.rowNumber = rowNumber;
this.exportID = exportID;
}
- public SimResultsLoader(String stringURI, String userSetFileName){
+ public SimResultsLoader(String stringURI, String userSetFileName, OpenTag openTag){
uri = URI.create(stringURI);
this.userSetFileName = userSetFileName;
if(!(uri.getQuery() == null)){
@@ -77,77 +78,112 @@ public SimResultsLoader(String stringURI, String userSetFileName){
throw new RuntimeException(e);
}
}
+ this.openTag = openTag;
}
- void createS3ClientAndReader(){
+ /////////////////////////////////
+ // Loading Simulation Results //
+ ///////////////////////////////
+
+ public void createS3ClientAndReader(){
logger.debug("Creating S3 Client with url: " + uri);
if (uri.getHost().equals("minikube.remote") || uri.getHost().equals("minikube.island")){
- SSLContext sslContext = null;
- try {
- sslContext = SSLContexts.custom().loadTrustMaterial(new TrustSelfSignedStrategy()).build();
- } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException ex) {
- throw new RuntimeException("Custom ssl context not functional.",ex);
- }
- HostnameVerifier hostnameVerifier = new HostnameVerifier() {
- @Override
- public boolean verify(String hostname, SSLSession session) {
- return true;
- }
- };
- ConnectionSocketFactory connectionSocketFactory = new SdkTLSSocketFactory(sslContext, hostnameVerifier);
- ClientConfiguration clientConfiguration = new ClientConfiguration();
- clientConfiguration.getApacheHttpClientConfig().setSslSocketFactory(connectionSocketFactory);
- s3ClientBuilder.setClientConfiguration(clientConfiguration);
+ allowInsecureConnections();
}
+ //////////////////////////////////////////////
+ // assume it is one of our URLs //
+ // http://vcell:8000/bucket/object/object2 //
+ //////////////////////////////////////////////
- // assume it is one of our URLs
- // http://vcell:8000/bucket/object/object2
String[] pathSubStrings = uri.getPath().split("/", 3);
- this.s3ObjectKey = pathSubStrings[2];
- this.bucketName = pathSubStrings[1];
+ String s3ObjectKey = pathSubStrings[2];
+ String bucketName = pathSubStrings[1];
s3ClientBuilder.withPathStyleAccessEnabled(true);
logger.debug("Creating S3 Client with Path Based Buckets");
s3ClientBuilder.withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials()));
s3ClientBuilder.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(uri.getScheme() + "://" + uri.getAuthority(), defaultS3Region));
- this.s3Client = s3ClientBuilder.build();
+ AmazonS3 s3Client = s3ClientBuilder.build();
S3KeyValueAccess amazonS3KeyValueAccess = new S3KeyValueAccess(s3Client, bucketName, false);
n5AmazonS3Reader = new N5KeyValueReader(amazonS3KeyValueAccess, s3ObjectKey, new GsonBuilder(), false);
}
+ private void allowInsecureConnections(){
+ SSLContext sslContext = null;
+ try {
+ sslContext = SSLContexts.custom().loadTrustMaterial(new TrustSelfSignedStrategy()).build();
+ } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException ex) {
+ throw new RuntimeException("Custom ssl context not functional.",ex);
+ }
+ HostnameVerifier hostnameVerifier = new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ };
+ ConnectionSocketFactory connectionSocketFactory = new SdkTLSSocketFactory(sslContext, hostnameVerifier);
+ ClientConfiguration clientConfiguration = new ClientConfiguration();
+ clientConfiguration.getApacheHttpClientConfig().setSslSocketFactory(connectionSocketFactory);
+ s3ClientBuilder.setClientConfiguration(clientConfiguration);
+ }
+
/**
By default N5 library assumes that S3 URL's are formated in the standard amazon format. That being
https://BUCKETNAME.s3.REGION.amazonaws.com {@link org.janelia.saalfeldlab.n5.s3.AmazonS3Utils}. Because our objects
don't originate from amazon this is not a format we can possibly mimic, so we have to use path based buckets because
it's the fallback style chosen by the N5 libraries if standard format is unavailable.
*/
- public ImagePlus getImgPlusFromN5File() throws IOException {
-// N5AmazonS3Reader n5AmazonS3Reader = new N5AmazonS3Reader(s3Client, bucketName, "/" + s3ObjectKey);
+ public ImagePlus getImagePlus(){
+ if (imagePlus != null){
+ return imagePlus;
+ }
+ if (n5AmazonS3Reader == null){
+ createS3ClientAndReader();
+ }
+ loadImageFromN5File();
+ return imagePlus;
+ }
+
+ public void loadImageFromN5File() {
long start = System.currentTimeMillis();
logger.debug("Reading N5 File " + userSetFileName + " Into Virtual Image");
if (userSetFileName == null || userSetFileName.isEmpty()){
userSetFileName = n5AmazonS3Reader.getAttribute(dataSetChosen, "name", String.class);
}
-
SimCacheLoader simCacheLoader = SimCacheLoader.factoryDefault(n5AmazonS3Reader, dataSetChosen);
CachedCellImg cachedCellImg = simCacheLoader.createCachedCellImage();
- ImagePlus imagePlus = ImageJFunctions.wrap(cachedCellImg, userSetFileName);
+ imagePlus = ImageJFunctions.wrap(cachedCellImg, userSetFileName);
simCacheLoader.setImagesResponsibleFor(imagePlus);
long end = System.currentTimeMillis();
logger.debug("Read N5 File " + userSetFileName + " Into ImageJ taking: " + ((end - start) / 1000.0) + "s");
setUnits(n5AmazonS3Reader, imagePlus);
- imagePlus.setProperty("channelInfo", n5AmazonS3Reader.getAttribute(dataSetChosen, "channelInfo", HashMap.class));
+ imagePlus.setProperty("channelInfo", getChannelInfo());
imagePlus.setProperty("maskInfo", n5AmazonS3Reader.getAttribute(dataSetChosen, "maskMapping", HashMap.class));
imagePlus.setZ(Math.floorDiv(imagePlus.getNSlices(), 2));
imagePlus.setT(Math.floorDiv(imagePlus.getNFrames(), 2));
new ContrastEnhancer().stretchHistogram(imagePlus, 1);
+ }
+
+ public ImagePlus openInMemory(RangeSelector rangeSelector){
+ loadImageFromN5File();
+ long start = System.currentTimeMillis();
+ logger.debug("Loading Virtual N5 File " + userSetFileName + " Into Memory");
+ imagePlus = new Duplicator().run(imagePlus, rangeSelector.startC, rangeSelector.endC, rangeSelector.startZ,
+ rangeSelector.endZ, rangeSelector.startT, rangeSelector.endT);
+ long end = System.currentTimeMillis();
+ logger.debug("Loaded Virtual N5 File " + userSetFileName + " Into Memory taking: " + ((end - start)/ 1000) + "s");
return imagePlus;
}
+
+ ////////////////
+ // Properties //
+ ////////////////
+
private void setUnits(N5Reader n5Reader, ImagePlus imagePlus){
try{
double pixelWidth = n5Reader.getAttribute(dataSetChosen, "pixelWidth", double.class);
@@ -170,38 +206,35 @@ public ArrayList getN5Dimensions(){
return n5AmazonS3Reader.getAttribute(dataSetChosen, "dimensions", ArrayList.class);
}
+ public LinkedTreeMap> getChannelInfo(){
+ return (LinkedTreeMap>) n5AmazonS3Reader.getAttribute(dataSetChosen, "channelInfo", LinkedTreeMap.class);
+ }
+
void setDataSetChosen(String dataSetChosen) {
this.dataSetChosen = dataSetChosen;
}
+ public void setTagToCanceled(){
+ openTag = OpenTag.CANCELED;
+ }
+
+ /////////////////////////
+ // Local File Reading //
+ ////////////////////////
+
void setSelectedLocalFile(File selectedLocalFile){
this.selectedLocalFile = selectedLocalFile;
}
- ArrayList getS3N5DatasetList() throws IOException {
- // used as a flag to tell that remote access is occurring, and that there is no local files
- try(N5AmazonS3Reader n5AmazonS3Reader = new N5AmazonS3Reader(this.s3Client, this.bucketName)) {
- return new ArrayList<>(Arrays.asList(n5AmazonS3Reader.deepListDatasets(this.s3ObjectKey)));
- }
- }
ImagePlus getImgPlusFromLocalN5File() throws IOException {
N5Reader n5Reader = new N5FSReader(selectedLocalFile.getPath());
return ImageJFunctions.wrap((CachedCellImg) N5Utils.open(n5Reader, dataSetChosen), userSetFileName);
}
- ArrayList getN5DatasetList() throws IOException {
- // auto closes reader
- logger.debug("Getting List of N5 Datasets");
- try (N5FSReader n5Reader = new N5FSReader(selectedLocalFile.getPath())) {
- String[] metaList = n5Reader.deepList("/");
- ArrayList fList = new ArrayList<>();
- for (String s : metaList) {
- if (n5Reader.datasetExists(s)) {
- fList.add(s);
- };
- }
- logger.debug("Got List of N5 Datasets");
- return fList;
- }
+ public enum OpenTag{
+ VIEW,
+ DATA_REDUCTION,
+ CANCELED,
+ TEST
}
}
diff --git a/view-simulation-results/src/test/java/org/vcell/N5/reduction/ReductionCalculationsTest.java b/view-simulation-results/src/test/java/org/vcell/N5/reduction/ReductionCalculationsTest.java
new file mode 100644
index 0000000..314c356
--- /dev/null
+++ b/view-simulation-results/src/test/java/org/vcell/N5/reduction/ReductionCalculationsTest.java
@@ -0,0 +1,125 @@
+package org.vcell.N5.reduction;
+
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
+import ij.ImagePlus;
+import ij.gui.Roi;
+import ij.io.RoiDecoder;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.vcell.N5.N5ImageHandler;
+import org.vcell.N5.reduction.DTO.RangeOfImage;
+import org.vcell.N5.reduction.DTO.ReducedData;
+import org.vcell.N5.reduction.GUI.SelectMeasurements;
+import org.vcell.N5.retrieving.LoadingManager;
+import org.vcell.N5.retrieving.SimResultsLoader;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class ReductionCalculationsTest {
+ // First two are SimROI, last two are LabROI
+ private final double[][] labMeans2D = new double[][]{{6, 0, 18, 0}, {6.489, 0, 16.341, 0},
+ {7.247, 0, 14.469, 0}}; //calculated through IJ measurement tool
+
+ private final double[][] threeDMeans = new double[][]{{2884.526, 3102.159}, {3884.279, 4668.205}, {5016.744, 5524.792}, {4794.329, 5624.351},
+ {4559.778, 5510.099}
+ };
+
+ private File getTestResourceFiles(String filePath){
+ try {
+ URL url = ClassLoader.getSystemClassLoader().getResource(filePath);
+ return new File(url.toURI().getPath());
+ }
+ catch (URISyntaxException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ @BeforeClass
+ public static void init(){
+ N5ImageHandler.initializeLogService();
+ SimResultsLoader.s3ClientBuilder = AmazonS3ClientBuilder.standard();
+ N5ImageHandler.loadingManager = new LoadingManager();
+ }
+
+ private void compareExpectedCalculations(ImagePlus imagePlus, ArrayList roiList, double[][] expectedResults,
+ boolean normalizeMeasurementsBool, int nz, int nt, int nc){
+ ReductionCalculations reductionCalculations = new ReductionCalculations(normalizeMeasurementsBool);
+
+ RangeOfImage entireRange = new RangeOfImage(1, imagePlus.getNFrames(), 1, imagePlus.getNSlices(), 1, imagePlus.getNChannels());
+ RangeOfImage normRange = new RangeOfImage(1, 1);
+ ReducedData reducedData = new ReducedData("", entireRange, roiList.size(), new ArrayList<>(Collections.singletonList(SelectMeasurements.AvailableMeasurements.AVERAGE)));
+
+ HashMap norms = reductionCalculations.calculateNormalValue(imagePlus, normRange, roiList, entireRange);
+ reductionCalculations.calculateStatistics(imagePlus, roiList, norms, reducedData, entireRange, new AtomicBoolean(true));
+ for (int c = 0; c < nc; c++){
+ for (int r = 0; r < roiList.size(); r++){
+ for (int t = 0; t < nt; t++){
+ for (int z = 0; z < nz; z++){
+ int row = (t * nz) + z;
+ int col = (r * nc) + c;
+ Assert.assertEquals(expectedResults[row][col], reducedData.getDataPoint(t, z, c, r, SelectMeasurements.AvailableMeasurements.AVERAGE), 0.0009);
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testMean2DCalculation(){
+ // Ensure the mean calculated for each ROI, and each time point is what's to be expected
+ SimResultsLoader simResultsLoader = new SimResultsLoader("https://vcell.cam.uchc.edu/n5Data/ezequiel23/ddf7f4f0c77dffd.n5?dataSetName=4864003788", "test1", SimResultsLoader.OpenTag.TEST);
+ ImagePlus labResultImage2D = simResultsLoader.getImagePlus();
+
+ Roi labRoi = RoiDecoder.open(getTestResourceFiles("ROIs/Lab ROI.roi").getAbsolutePath());
+ Roi simROI = RoiDecoder.open(getTestResourceFiles("ROIs/Sim ROI.roi").getAbsolutePath());
+ ArrayList roiList = new ArrayList(){{add(labRoi); add(simROI);}};
+ compareExpectedCalculations(labResultImage2D, roiList, labMeans2D, false,
+ 1, 3, 2);
+ }
+
+ @Test
+ public void testMean3DCalculation(){
+ ImagePlus mitosis = new ImagePlus(getTestResourceFiles("mitosis.tif").getAbsolutePath());
+ Roi mitosisROI = RoiDecoder.open(getTestResourceFiles("ROIs/Mitosis Center.roi").getAbsolutePath());
+ ArrayList roiList = new ArrayList(){{add(mitosisROI);}};
+ compareExpectedCalculations(mitosis, roiList, threeDMeans, false,
+ 5, 1, 2);
+ }
+
+ @Test
+ public void testMeanAndNormalization2DCalculation(){
+ SimResultsLoader simResultsLoader = new SimResultsLoader("https://vcell.cam.uchc.edu/n5Data/ezequiel23/ddf7f4f0c77dffd.n5?dataSetName=4864003788", "test1", SimResultsLoader.OpenTag.TEST);
+ ImagePlus labResultImage2D = simResultsLoader.getImagePlus();
+ Roi labRoi = RoiDecoder.open(getTestResourceFiles("ROIs/Lab ROI.roi").getAbsolutePath());
+ Roi simROI = RoiDecoder.open(getTestResourceFiles("ROIs/Sim ROI.roi").getAbsolutePath());
+ ArrayList roiList = new ArrayList(){{add(labRoi); add(simROI);}};
+ HashMap normValues = new HashMap<>();
+
+ for (Roi roi: roiList){
+ labResultImage2D.setRoi(roi);
+ for (int c = 1; c <= labResultImage2D.getNChannels(); c++){
+ labResultImage2D.setC(c);
+ normValues.put(roi.getName() + c, labResultImage2D.getStatistics().mean);
+ }
+ }
+ double[][] normalizedValues = new double[labMeans2D.length][labMeans2D[0].length];
+
+ for (int r = 0; r < labMeans2D.length; r++){
+ for (int c =0; c < labMeans2D[0].length; c++){
+ String roiName = c < 2 ? labRoi.getName() : simROI.getName();
+ double normValue = c % 2 == 0 ? normValues.get(roiName + 1) : normValues.get(roiName + 2);
+ normalizedValues[r][c] = labMeans2D[r][c] / normValue;
+ }
+ }
+
+ compareExpectedCalculations(labResultImage2D, roiList, normalizedValues, true,
+ 1, 3, 2);
+ }
+}
diff --git a/view-simulation-results/src/test/java/org/vcell/N5/retrieving/N5ImageHandlerTest.java b/view-simulation-results/src/test/java/org/vcell/N5/retrieving/N5ImageHandlerTest.java
index 1403cb3..3f189a1 100644
--- a/view-simulation-results/src/test/java/org/vcell/N5/retrieving/N5ImageHandlerTest.java
+++ b/view-simulation-results/src/test/java/org/vcell/N5/retrieving/N5ImageHandlerTest.java
@@ -59,13 +59,6 @@ public void run(){
N5ImageHandler.initializeLogService();
}
- @Test
- public void testN5DatasetList() throws IOException {
- SimResultsLoader simResultsLoader = new SimResultsLoader();
- simResultsLoader.setSelectedLocalFile(this.getTestResourceFiles(n5FileName));
- this.dataSetListTest(simResultsLoader.getN5DatasetList());
- }
-
@Test
public void testGettingImgPlus() throws IOException {
SimResultsLoader simResultsLoader = new SimResultsLoader();
@@ -82,9 +75,10 @@ public void testGettingImgPlus() throws IOException {
public void testS3AlphaInstance() throws IOException{
N5DataSetFile[] n5DataSetFiles = N5DataSetFile.alphaTestFiles();
for(N5DataSetFile n5DataSetFile : n5DataSetFiles) {
- SimResultsLoader simResultsLoader = new SimResultsLoader(n5DataSetFile.uri, "");
+ SimResultsLoader simResultsLoader = new SimResultsLoader(n5DataSetFile.uri, "", SimResultsLoader.OpenTag.TEST);
simResultsLoader.createS3ClientAndReader();
- ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File();
+ simResultsLoader.loadImageFromN5File();
+ ImagePlus imagePlus = simResultsLoader.getImagePlus();
//stats that have been preemptively calculated within VCell
alphaStatsTest(imagePlus, n5DataSetFile, stats.HISTMAX);
@@ -97,9 +91,10 @@ public void testS3AlphaInstance() throws IOException{
public void testS3AlphaInstanceLoadedIntoMemory() throws IOException {
N5DataSetFile[] n5DataSetFiles = N5DataSetFile.alphaTestFiles();
for(N5DataSetFile n5DataSetFile : n5DataSetFiles) {
- SimResultsLoader simResultsLoader = new SimResultsLoader(n5DataSetFile.uri, "");
+ SimResultsLoader simResultsLoader = new SimResultsLoader(n5DataSetFile.uri, "", SimResultsLoader.OpenTag.TEST);
simResultsLoader.createS3ClientAndReader();
- ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File();
+ simResultsLoader.loadImageFromN5File();
+ ImagePlus imagePlus = simResultsLoader.getImagePlus();
ImagePlus inMemory = new Duplicator().run(imagePlus);
for (Object property : imagePlus.getProperties().keySet()){
inMemory.setProperty((String) property, imagePlus.getProperty((String) property));
@@ -118,9 +113,10 @@ interface PixelCalculations {
public void testUnits() throws IOException {
N5DataSetFile[] n5DataSetFiles = N5DataSetFile.alphaTestFiles();
for (N5DataSetFile n5DataSetFile: n5DataSetFiles){
- SimResultsLoader simResultsLoader = new SimResultsLoader(n5DataSetFile.uri, "");
+ SimResultsLoader simResultsLoader = new SimResultsLoader(n5DataSetFile.uri, "", SimResultsLoader.OpenTag.TEST);
simResultsLoader.createS3ClientAndReader();
- ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File();
+ simResultsLoader.loadImageFromN5File();
+ ImagePlus imagePlus = simResultsLoader.getImagePlus();
double areaOfPixel = imagePlus.getCalibration().getX(1) * imagePlus.getCalibration().getY(1);
double totalArea = areaOfPixel * imagePlus.getWidth() * imagePlus.getHeight();
@@ -287,15 +283,6 @@ private ImagePlus setImageMask(ImagePlus imagePlus){
return imagePlus;
}
-
- private void remoteN5ImgPlusTests(SimResultsLoader simResultsLoader) throws IOException {
- ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File();
- dataSetListTest(simResultsLoader.getS3N5DatasetList());
- fiveDStackTests(imagePlus);
- imagePlus = new Duplicator().run(imagePlus); //Tests taking the N5 file from streaming to in memory
- fiveDStackTests(imagePlus);
- }
-
private void fiveDStackTests(ImagePlus variableImgPlus){
ImagePlus controlImgPlus = Opener.openUsingBioFormats(this.getTestResourceFiles("mitosis.tif").getAbsolutePath());
int[] variableDimensions = variableImgPlus.getDimensions();
diff --git a/view-simulation-results/src/test/resources/ROIs/Lab ROI.roi b/view-simulation-results/src/test/resources/ROIs/Lab ROI.roi
new file mode 100644
index 0000000..6e4170b
Binary files /dev/null and b/view-simulation-results/src/test/resources/ROIs/Lab ROI.roi differ
diff --git a/view-simulation-results/src/test/resources/ROIs/Mitosis Center.roi b/view-simulation-results/src/test/resources/ROIs/Mitosis Center.roi
new file mode 100644
index 0000000..15225b4
Binary files /dev/null and b/view-simulation-results/src/test/resources/ROIs/Mitosis Center.roi differ
diff --git a/view-simulation-results/src/test/resources/ROIs/Sim ROI.roi b/view-simulation-results/src/test/resources/ROIs/Sim ROI.roi
new file mode 100644
index 0000000..c3b6344
Binary files /dev/null and b/view-simulation-results/src/test/resources/ROIs/Sim ROI.roi differ