From 0ebb4ec572a91261ccd6b8a8e4d644948ad1027a Mon Sep 17 00:00:00 2001 From: Ezequiel Valencia Date: Wed, 20 Nov 2024 11:15:05 -0500 Subject: [PATCH] Add Tall Table Writer and Implement Opinionated Data Retrieval Have a writer function which allows for tall tables, and make data retrieval from reduced data be through an opinionated method. --- .../vcell/N5/reduction/DTO/RangeOfImage.java | 12 ++ .../vcell/N5/reduction/DTO/ReducedData.java | 47 ++++++ .../N5/reduction/DataReductionManager.java | 52 ++---- .../N5/reduction/DataReductionWriter.java | 156 ++++++++++++------ .../N5/reduction/ReductionCalculations.java | 33 ++-- .../org/vcell/N5/reduction/RoiSelection.java | 2 +- .../N5/reduction/SelectMeasurements.java | 2 +- .../reduction/ReductionCalculationsTest.java | 32 ++-- 8 files changed, 221 insertions(+), 115 deletions(-) create mode 100644 view-simulation-results/src/main/java/org/vcell/N5/reduction/DTO/ReducedData.java 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 index 1613c24..fe23c90 100644 --- 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 @@ -17,6 +17,18 @@ public RangeOfImage(int timeStart, int timeEnd, int zStart, int zEnd, int channe 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 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..42466d8 --- /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.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 index 70385e6..656d744 100644 --- 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 @@ -8,6 +8,7 @@ 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.retrieving.SimLoadingListener; import org.vcell.N5.retrieving.SimResultsLoader; @@ -21,7 +22,7 @@ public class DataReductionManager implements SimLoadingListener { private final ArrayList arrayOfSimRois; private final Object csvMatrixLock = new Object(); - private int numOfCalculationsTimesNumImages; + private int numOfImagesToOpen; private final ReductionCalculations calculations; public final DataReductionGUI.DataReductionSubmission submission; @@ -31,31 +32,12 @@ public class DataReductionManager implements SimLoadingListener { private DataReductionWriter dataReductionWriter; - - // Per Image - public static class ReducedData{ - public final double[][] data; - public final ArrayList columnHeaders; - public final SelectMeasurements.AvailableMeasurements measurementType; - public final RangeOfImage rangeOfImage; - public final int colLen; - public ReducedData(RangeOfImage rangeOfImage, int colLen, SelectMeasurements.AvailableMeasurements measurementType){ - int nFrames = rangeOfImage.timeEnd - rangeOfImage.timeStart + 1; - int nSlices = rangeOfImage.zEnd - rangeOfImage.zStart + 1; - data = new double[nFrames * nSlices][colLen]; // row - col - columnHeaders = new ArrayList<>(); - this.measurementType = measurementType; - this.colLen = colLen; - this.rangeOfImage = rangeOfImage; - } - } - public DataReductionManager(DataReductionGUI.DataReductionSubmission submission){ N5ImageHandler.loadingManager.addSimLoadingListener(this); this.submission = submission; this.arrayOfSimRois = submission.arrayOfSimRois; - this.numOfCalculationsTimesNumImages = (submission.numOfSimImages + 1) * submission.selectedMeasurements.size(); // Plus one for the lab image + this.numOfImagesToOpen = submission.numOfSimImages + 1; // Plus one for the lab image this.calculations = new ReductionCalculations(submission.normalizeMeasurementsBool); Thread processLabResults = new Thread(() -> { @@ -84,27 +66,25 @@ private void calculateAndAddResults(ImagePlus imagePlus, RangeOfImage normRange, normValue = calculations.calculateNormalValue(imagePlus, normRange, rois, imageRange); } - int nChannels = imageRange.channelEnd - imageRange.channelStart + 1; + ReducedData reducedData = new ReducedData(imagePlus.getTitle(), imageRange, arrayOfSimRois.size(), submission.selectedMeasurements); + calculations.addAppropriateHeaders(rois, imageRange, reducedData, channelInfo); - ArrayList reducedDataArrayList = new ArrayList<>(); - for (SelectMeasurements.AvailableMeasurements measurement : submission.selectedMeasurements){ - ReducedData reducedData = new ReducedData(imageRange, nChannels * arrayOfSimRois.size(), measurement); - reducedDataArrayList.add(reducedData); - calculations.addAppropriateHeaders(imagePlus, rois, imageRange, reducedData, channelInfo); - } AtomicBoolean continueOperation = threadPool.get(threadName).continueOperation; - calculations.calculateStatistics(imagePlus, rois, normValue, reducedDataArrayList, imageRange, continueOperation); - for (ReducedData reducedData: reducedDataArrayList){ - if (continueOperation.get()){ - synchronized (csvMatrixLock){ - dataReductionWriter.addValuesToWideCSVMatrix(reducedData); - numOfCalculationsTimesNumImages -= 1; + 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 (numOfCalculationsTimesNumImages == 0){ + if (numOfImagesToOpen == 0 && continueOperation.get()){ try{ - dataReductionWriter.writeCSVMatrix(); + dataReductionWriter.close(); } catch (IOException ioException){ throw new RuntimeException(ioException); } finally { 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 index 1d92edb..4858895 100644 --- 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 @@ -5,13 +5,14 @@ import org.vcell.N5.UI.MainPanel; import org.vcell.N5.UI.N5ExportTable; import org.vcell.N5.reduction.DTO.RangeOfImage; -import org.vcell.N5.reduction.DataReductionManager.ReducedData; +import org.vcell.N5.reduction.DTO.ReducedData; 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{ @@ -39,6 +40,8 @@ public class DataReductionWriter{ private final int maxZ; private final int maxT; + private final boolean wideTable = true; + /////////////////////////////////////// // Initialize Sheet and Lab results // ///////////////////////////////////// @@ -51,12 +54,23 @@ public DataReductionWriter(DataReductionGUI.DataReductionSubmission submission, this.maxT = maxT; } + public void consumeNewData(ReducedData reducedData) throws IOException { + if (wideTable){ + addValuesToWideCSVMatrix(reducedData); + } else { + appendAndWriteTallTable(reducedData); + } + } + + public void close() throws IOException { + if (wideTable){ + writeWideTableCSVMatrix(); + } + } + public void initializeDataSheets(){ ArrayList headers = new ArrayList(){{add("Time Frame");}}; boolean is3D = maxZ > 1; - if (is3D){ - headers.add("Z Index"); - } // Add Time and Z-Index Columns for (SelectMeasurements.AvailableMeasurements measurement : selectedMeasurements){ @@ -77,54 +91,40 @@ public void initializeDataSheets(){ metaDataSheet.get(0).add("Simulation Name"); metaDataSheet.get(0).add("N5 URL"); - // Fill in Time and Z-Index Columns with selected range - - 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); - } + if (wideTable){ + // Fill in Time and Z-Index Columns with selected range + if (is3D){ + headers.add("Z Index"); } - } - } - - //////////////////////// - // General Functions // - ////////////////////// - - public void addValuesToWideCSVMatrix(ReducedData reducedData){ - ArrayList> dataSheet = sheetsAvailable.get(reducedData.measurementType); - int colIndex = columnsForSheets.get(reducedData.measurementType); - fillWithEmptySpace(dataSheet.get(0), colIndex); - for (int c = 0; c < reducedData.columnHeaders.size(); c++){ - dataSheet.get(0).add(colIndex, reducedData.columnHeaders.get(c)); - } - RangeOfImage rangeOfImage = reducedData.rangeOfImage; - 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 inBetweenZ = z <= rangeOfImage.zEnd && rangeOfImage.zStart <= z; - ArrayList row = dataSheet.get(tzCounter); - fillWithEmptySpace(row, colIndex); - for (int c = 0; c < reducedData.colLen; c++){ - if (inBetweenTime && inBetweenZ){ - int dataRow = ((t - rangeOfImage.timeStart) * (z - rangeOfImage.zStart)) + (z - rangeOfImage.zStart); - double mean = reducedData.data[dataRow][c]; - row.add(String.valueOf(mean)); + 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); } } - tzCounter += 1; + } + } 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); } } - colIndex += 1 + reducedData.data[0].length; - columnsForSheets.replace(reducedData.measurementType, colIndex); } // If parameter is not in list of parameters, add new column. If simulation does not have parameter say "not-present" @@ -158,6 +158,42 @@ public void addMetaData(SimResultsLoader loadedResults){ } } + //////////////////////// + // 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 inBetweenZ = z <= rangeOfImage.zEnd && rangeOfImage.zStart <= z; + ArrayList row = dataSheet.get(tzCounter); + fillWithEmptySpace(row, colIndex); + if (inBetweenTime && inBetweenZ){ + int nt = t - rangeOfImage.timeStart; + int nz = 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){ @@ -165,8 +201,32 @@ private void fillWithEmptySpace(ArrayList arrayList, int col){ } } + // 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])); + } + } + } + } + } + } - public void writeCSVMatrix() throws IOException { + 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"); 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 index 5b66008..4ee879d 100644 --- 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 @@ -4,12 +4,13 @@ import ij.ImagePlus; import ij.gui.Roi; import org.vcell.N5.reduction.DTO.RangeOfImage; -import org.vcell.N5.reduction.DataReductionManager.ReducedData; +import org.vcell.N5.reduction.DTO.ReducedData; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.atomic.AtomicBoolean; + class ReductionCalculations { private final boolean normalize; @@ -17,14 +18,15 @@ public ReductionCalculations(boolean normalize){ this.normalize = normalize; } - public void addAppropriateHeaders(ImagePlus imagePlus, ArrayList roiList, RangeOfImage rangeOfImage, + public void addAppropriateHeaders(ArrayList roiList, RangeOfImage rangeOfImage, ReducedData reducedData, LinkedTreeMap> channelInfo){ - for (Roi roi: roiList){ + 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.columnHeaders.add(0, imagePlus.getTitle() + ":" + roi.getName() + ":" + channelName); + reducedData.channelNames.put(c - 1, channelName); + reducedData.roiNames.put(r, roiList.get(r).getName()); } } } @@ -35,28 +37,27 @@ public void addAppropriateHeaders(ImagePlus imagePlus, ArrayList roiList, R * @param imagePlus * @param roiList * @param normalizationValue - * @param reducedDataArrayList * @param rangeOfImage */ void calculateStatistics(ImagePlus imagePlus, ArrayList roiList, HashMap normalizationValue, - ArrayList reducedDataArrayList, + ReducedData reducedData, RangeOfImage rangeOfImage, AtomicBoolean continueOperation){ - int roiCounter = 0; - for (Roi roi: roiList) { - imagePlus.setRoi(roi); - int tzCounter = 0; + 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++){ - int channelSize = rangeOfImage.channelEnd - rangeOfImage.channelStart + 1; 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 (ReducedData reducedData : reducedDataArrayList){ - switch (reducedData.measurementType){ + for (SelectMeasurements.AvailableMeasurements measurement : reducedData.measurements){ + switch (measurement){ case AVERAGE: calculatedValue = imagePlus.getStatistics().mean; break; @@ -67,15 +68,13 @@ void calculateStatistics(ImagePlus imagePlus, ArrayList roiList, throw new RuntimeException("Unknown measurement type selected."); } if (normalize){ - calculatedValue = calculatedValue / normalizationValue.get(roi.getName() + c); + calculatedValue = calculatedValue / normalizationValue.get(roiList.get(roi).getName() + c); } - reducedData.data[tzCounter][c - 1 + (roiCounter * channelSize)] = calculatedValue; + reducedData.putDataPoint(calculatedValue, nT, nZ, nC, roi, measurement); } } - tzCounter += 1; } } - roiCounter += 1; } } diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/RoiSelection.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/RoiSelection.java index 6f1072f..cfe3d82 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/reduction/RoiSelection.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/RoiSelection.java @@ -25,7 +25,7 @@ public RoiSelection(DataReductionGUI parentGUI){ JList simROITable = new JList<>(simTableModel); JFileChooser simROIFileChooser = new JFileChooser(); this.add(createROIInput(simROITable, simTableModel, simROIFileChooser, "Sim")); - this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "ROI Files")); + this.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "2D ROI Files")); this.parentGUI = parentGUI; } diff --git a/view-simulation-results/src/main/java/org/vcell/N5/reduction/SelectMeasurements.java b/view-simulation-results/src/main/java/org/vcell/N5/reduction/SelectMeasurements.java index 1579f08..970457c 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/reduction/SelectMeasurements.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/reduction/SelectMeasurements.java @@ -6,7 +6,7 @@ import java.awt.*; import java.util.ArrayList; -class SelectMeasurements extends JPanel implements ListSelectionListener { +public class SelectMeasurements extends JPanel implements ListSelectionListener { private final JList chosenMeasurement; private final MeasurementsDataModel measurementsDataModel = new MeasurementsDataModel(); private final DataReductionGUI parentGUI; 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 index 6c1ff2f..39e2e71 100644 --- 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 @@ -9,14 +9,15 @@ 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.retrieving.LoadingManager; import org.vcell.N5.retrieving.SimResultsLoader; -import org.vcell.N5.reduction.DataReductionManager.ReducedData; 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; @@ -47,20 +48,24 @@ public static void init(){ } private void compareExpectedCalculations(ImagePlus imagePlus, ArrayList roiList, double[][] expectedResults, - boolean normalizeMeasurementsBool){ + 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, imagePlus.getNChannels() * roiList.size(), SelectMeasurements.AvailableMeasurements.AVERAGE); - ArrayList reducedDataArrayList = new ArrayList<>(); - reducedDataArrayList.add(reducedData); + 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, reducedDataArrayList, entireRange, new AtomicBoolean(true)); - for (int r = 0; r < expectedResults.length; r++){ - for (int c = 0; c < expectedResults[r].length; c++){ - Assert.assertEquals(expectedResults[r][c], reducedData.data[r][c], 0.0009); + 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); + } + } } } } @@ -74,7 +79,8 @@ public void testMean2DCalculation(){ 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); + compareExpectedCalculations(labResultImage2D, roiList, labMeans2D, false, + 1, 3, 2); } @Test @@ -82,7 +88,8 @@ 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); + compareExpectedCalculations(mitosis, roiList, threeDMeans, false, + 5, 1, 2); } @Test @@ -111,6 +118,7 @@ public void testMeanAndNormalization2DCalculation(){ } } - compareExpectedCalculations(labResultImage2D, roiList, normalizedValues, true); + compareExpectedCalculations(labResultImage2D, roiList, normalizedValues, true, + 1, 3, 2); } }