Search in sources :

Example 1 with TMAGrid

use of qupath.lib.objects.hierarchy.TMAGrid in project qupath by qupath.

the class TMACommands method promptToRelabelTMAGrid.

/**
 * Prompt to relabel the core names within a TMA grid.
 * @param imageData image containing the TMA grid
 */
public static void promptToRelabelTMAGrid(ImageData<?> imageData) {
    String title = "Relabel TMA grid";
    if (imageData == null) {
        Dialogs.showNoImageError(title);
        return;
    }
    if (imageData.getHierarchy().getTMAGrid() == null) {
        Dialogs.showErrorMessage(title, "No TMA grid selected!");
        return;
    }
    ParameterList params = new ParameterList();
    params.addStringParameter("labelsHorizontal", "Column labels", columnLabelsProperty.get(), "Enter column labels.\nThis can be a continuous range of letters or numbers (e.g. 1-10 or A-J),\nor a discontinuous list separated by spaces (e.g. A B C E F G).");
    params.addStringParameter("labelsVertical", "Row labels", rowLabelsProperty.get(), "Enter row labels.\nThis can be a continuous range of letters or numbers (e.g. 1-10 or A-J),\nor a discontinuous list separated by spaces (e.g. A B C E F G).");
    params.addChoiceParameter("labelOrder", "Label order", rowFirstProperty.get() ? "Row first" : "Column first", Arrays.asList("Column first", "Row first"), "Create TMA labels either in the form Row-Column or Column-Row");
    if (!Dialogs.showParameterDialog(title, params))
        return;
    // Parse the arguments
    String labelsHorizontal = params.getStringParameterValue("labelsHorizontal");
    String labelsVertical = params.getStringParameterValue("labelsVertical");
    boolean rowFirst = "Row first".equals(params.getChoiceParameterValue("labelOrder"));
    // Figure out if this will work
    TMAGrid grid = imageData.getHierarchy().getTMAGrid();
    String[] columnLabels = PathObjectTools.parseTMALabelString(labelsHorizontal);
    String[] rowLabels = PathObjectTools.parseTMALabelString(labelsVertical);
    if (columnLabels.length < grid.getGridWidth()) {
        Dialogs.showErrorMessage(title, "Not enough column labels specified!");
        return;
    }
    if (rowLabels.length < grid.getGridHeight()) {
        Dialogs.showErrorMessage(title, "Not enough row labels specified!");
        return;
    }
    // Apply the labels
    QP.relabelTMAGrid(imageData.getHierarchy(), labelsHorizontal, labelsVertical, rowFirst);
    // Add to workflow history
    imageData.getHistoryWorkflow().addStep(new DefaultScriptableWorkflowStep("Relabel TMA grid", String.format("relabelTMAGrid(\"%s\", \"%s\", %s)", GeneralTools.escapeFilePath(labelsHorizontal), GeneralTools.escapeFilePath(labelsVertical), Boolean.toString(rowFirst))));
    // Store values
    rowLabelsProperty.set(labelsVertical);
    columnLabelsProperty.set(labelsHorizontal);
    rowFirstProperty.set(rowFirst);
}
Also used : DefaultScriptableWorkflowStep(qupath.lib.plugins.workflow.DefaultScriptableWorkflowStep) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) ParameterList(qupath.lib.plugins.parameters.ParameterList)

Example 2 with TMAGrid

use of qupath.lib.objects.hierarchy.TMAGrid in project qupath by qupath.

the class TMACommands method promptToDeleteTMAGridRowOrColumn.

private static boolean promptToDeleteTMAGridRowOrColumn(ImageData<?> imageData, TMARemoveType type) {
    String typeString = type.toString();
    String title = "Delete TMA " + typeString;
    boolean removeRow = type == TMARemoveType.ROW;
    if (imageData == null) {
        Dialogs.showNoImageError(title);
        return false;
    }
    if (imageData.getHierarchy().getTMAGrid() == null) {
        Dialogs.showErrorMessage(title, "No image with dearrayed TMA cores selected!");
        return false;
    }
    PathObjectHierarchy hierarchy = imageData.getHierarchy();
    PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
    TMACoreObject selectedCore = null;
    if (selected != null)
        selectedCore = PathObjectTools.getAncestorTMACore(selected);
    // Try to identify the row/column that we want
    TMAGrid grid = hierarchy.getTMAGrid();
    int row = -1;
    int col = -1;
    if (selectedCore != null) {
        for (int y = 0; y < grid.getGridHeight(); y++) {
            for (int x = 0; x < grid.getGridWidth(); x++) {
                if (grid.getTMACore(y, x) == selectedCore) {
                    row = y;
                    col = x;
                    break;
                }
            }
        }
    }
    // We need a selected core to know what to remove
    if (row < 0 || col < 0) {
        Dialogs.showErrorMessage(title, "Please select a TMA core to indicate which " + typeString + " to remove");
        return false;
    }
    // Check we have enough rows/columns - if not, this is just a clear operation
    if ((removeRow && grid.getGridHeight() <= 1) || (!removeRow && grid.getGridWidth() <= 1)) {
        if (Dialogs.showConfirmDialog(title, "Are you sure you want to delete the entire TMA grid?"))
            hierarchy.setTMAGrid(null);
        return false;
    }
    // Confirm the removal - add 1 due to 'base 0' probably not being expected by most users...
    int num = removeRow ? row : col;
    if (!Dialogs.showConfirmDialog(title, "Are you sure you want to delete " + typeString + " " + (num + 1) + " from TMA grid?"))
        return false;
    // Create a new grid
    List<TMACoreObject> coresNew = new ArrayList<>();
    for (int r = 0; r < grid.getGridHeight(); r++) {
        if (removeRow && row == r)
            continue;
        for (int c = 0; c < grid.getGridWidth(); c++) {
            if (!removeRow && col == c)
                continue;
            coresNew.add(grid.getTMACore(r, c));
        }
    }
    int newWidth = removeRow ? grid.getGridWidth() : grid.getGridWidth() - 1;
    TMAGrid gridNew = DefaultTMAGrid.create(coresNew, newWidth);
    hierarchy.setTMAGrid(gridNew);
    hierarchy.getSelectionModel().clearSelection();
    // Request new labels
    promptToRelabelTMAGrid(imageData);
    return true;
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathObject(qupath.lib.objects.PathObject) TMACoreObject(qupath.lib.objects.TMACoreObject) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) ArrayList(java.util.ArrayList)

Example 3 with TMAGrid

use of qupath.lib.objects.hierarchy.TMAGrid in project qupath by qupath.

the class TMASummaryViewer method updateSurvivalCurves.

private void updateSurvivalCurves() {
    String colID = null;
    String colScore = null;
    colCensored = null;
    for (String nameOrig : model.getAllNames()) {
        if (nameOrig.equals(TMACoreObject.KEY_UNIQUE_ID))
            colID = nameOrig;
        else // else if (nameOrig.equals(TMACoreObject.KEY_CENSORED))
        // colCensored = nameOrig;
        // else if (!Number.class.isAssignableFrom())
        // continue;
        {
            if (nameOrig.trim().length() == 0 || !model.getMeasurementNames().contains(nameOrig))
                continue;
            String name = nameOrig.toLowerCase();
            if (name.equals("h-score"))
                colScore = nameOrig;
            else if (name.equals("positive %") && colScore == null)
                colScore = nameOrig;
        }
    }
    // Check for a column with the exact requested name
    String colCensoredRequested = null;
    String colSurvival = getSurvivalColumn();
    if (colSurvival != null) {
        colCensoredRequested = getRequestedSurvivalCensoredColumn(colSurvival);
        if (model.getAllNames().contains(colCensoredRequested))
            colCensored = colCensoredRequested;
        else // Check for a general 'censored' column... less secure since it doesn't specify OS or RFS (but helps with backwards-compatibility)
        if (model.getAllNames().contains("Censored")) {
            logger.warn("Correct censored column for \"{}\" unavailable - should be \"{}\", but using \"Censored\" column instead", colSurvival, colCensoredRequested);
            colCensored = "Censored";
        }
    }
    if (colCensored == null && colSurvival != null) {
        logger.warn("Unable to find censored column - survival data will be uncensored");
    } else
        logger.info("Survival column: {}, Censored column: {}", colSurvival, colCensored);
    colScore = comboMainMeasurement.getSelectionModel().getSelectedItem();
    if (colID == null || colSurvival == null || colCensored == null) {
        // Adjust priority depending on whether we have any data at all..
        if (!model.getItems().isEmpty())
            logger.warn("No survival data found!");
        else
            logger.trace("No entries or survival data available");
        return;
    }
    // Generate a pseudo TMA core hierarchy
    Map<String, List<TMAEntry>> scoreMap = createScoresMap(model.getItems(), colScore, colID);
    // System.err.println("Score map size: " + scoreMap.size() + "\tEntries: " + model.getEntries().size());
    List<TMACoreObject> cores = new ArrayList<>(scoreMap.size());
    double[] scores = new double[15];
    for (Entry<String, List<TMAEntry>> entry : scoreMap.entrySet()) {
        TMACoreObject core = new TMACoreObject();
        core.setName("ID: " + entry.getKey());
        MeasurementList ml = core.getMeasurementList();
        Arrays.fill(scores, Double.POSITIVE_INFINITY);
        List<TMAEntry> list = entry.getValue();
        // Increase array size, if needed
        if (list.size() > scores.length)
            scores = new double[list.size()];
        for (int i = 0; i < list.size(); i++) {
            scores[i] = model.getNumericValue(list.get(i), colScore);
        // scores[i] = list.get(i).getMeasurement(colScore).doubleValue();
        }
        Arrays.sort(scores);
        int n = list.size();
        double score;
        if (n % 2 == 1)
            score = scores[n / 2];
        else
            score = (scores[n / 2 - 1] + scores[n / 2]) / 2;
        core.putMetadataValue(TMACoreObject.KEY_UNIQUE_ID, entry.getKey());
        // System.err.println("Putting: " + list.get(0).getMeasurement(colSurvival).doubleValue() + " LIST: " + list.size());
        ml.putMeasurement(colSurvival, list.get(0).getMeasurementAsDouble(colSurvival));
        ml.putMeasurement(colCensoredRequested, list.get(0).getMeasurementAsDouble(colCensored));
        if (colScore != null)
            ml.putMeasurement(colScore, score);
        cores.add(core);
    // logger.info(entry.getKey() + "\t" + score);
    }
    TMAGrid grid = DefaultTMAGrid.create(cores, 1);
    PathObjectHierarchy hierarchy = new PathObjectHierarchy();
    hierarchy.setTMAGrid(grid);
    kmDisplay.setHierarchy(hierarchy, colSurvival, colCensoredRequested);
    kmDisplay.setScoreColumn(comboMainMeasurement.getSelectionModel().getSelectedItem());
// new KaplanMeierPlotTMA.KaplanMeierDisplay(hierarchy, colScore).show(frame, colScore);
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) TMACoreObject(qupath.lib.objects.TMACoreObject) MeasurementList(qupath.lib.measurements.MeasurementList) TMAEntry(qupath.lib.gui.tma.TMAEntries.TMAEntry) ArrayList(java.util.ArrayList) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) ObservableList(javafx.collections.ObservableList) ArrayList(java.util.ArrayList) MeasurementList(qupath.lib.measurements.MeasurementList) SortedList(javafx.collections.transformation.SortedList) FilteredList(javafx.collections.transformation.FilteredList) List(java.util.List)

Example 4 with TMAGrid

use of qupath.lib.objects.hierarchy.TMAGrid in project qupath by qupath.

the class TMADataIO method writeTMAData.

/**
 * Write TMA data in a human-readable (and viewable) way, with JPEGs and TXT/CSV files.
 *
 * @param file
 * @param imageData
 * @param overlayOptions
 * @param downsampleFactor The downsample factor used for the TMA cores. If NaN, an automatic downsample value will be selected (&gt;= 1).  If &lt;= 0, no cores are exported.
 */
public static void writeTMAData(File file, final ImageData<BufferedImage> imageData, OverlayOptions overlayOptions, final double downsampleFactor) {
    if (imageData == null || imageData.getHierarchy() == null || imageData.getHierarchy().getTMAGrid() == null) {
        logger.error("No TMA data available to save!");
        return;
    }
    final ImageServer<BufferedImage> server = imageData.getServer();
    String coreExt = imageData.getServer().isRGB() ? ".jpg" : ".tif";
    if (file == null) {
        file = Dialogs.promptToSaveFile("Save TMA data", null, ServerTools.getDisplayableImageName(server), "TMA data", "qptma");
        if (file == null)
            return;
    } else if (file.isDirectory() || (!file.exists() && file.getAbsolutePath().endsWith(File.pathSeparator))) {
        // Put inside the specified directory
        file = new File(file, ServerTools.getDisplayableImageName(server) + TMA_DEARRAYING_DATA_EXTENSION);
        if (!file.getParentFile().exists())
            file.getParentFile().mkdirs();
    }
    final File dirData = new File(file + ".data");
    if (!dirData.exists())
        dirData.mkdir();
    // Write basic file info
    String delimiter = "\t";
    TMAGrid tmaGrid = imageData.getHierarchy().getTMAGrid();
    try {
        PrintWriter writer = new PrintWriter(file);
        writer.println(server.getPath());
        writer.println(ServerTools.getDisplayableImageName(server));
        writer.println();
        writer.println("TMA grid width: " + tmaGrid.getGridWidth());
        writer.println("TMA grid height: " + tmaGrid.getGridHeight());
        writer.println("Core name" + delimiter + "X" + delimiter + "Y" + delimiter + "Width" + delimiter + "Height" + delimiter + "Present" + delimiter + TMACoreObject.KEY_UNIQUE_ID);
        for (int row = 0; row < tmaGrid.getGridHeight(); row++) {
            for (int col = 0; col < tmaGrid.getGridWidth(); col++) {
                TMACoreObject core = tmaGrid.getTMACore(row, col);
                if (!core.hasROI()) {
                    writer.println(core.getName() + delimiter + delimiter + delimiter + delimiter);
                    continue;
                }
                ROI pathROI = core.getROI();
                int x = (int) pathROI.getBoundsX();
                int y = (int) pathROI.getBoundsY();
                int w = (int) Math.ceil(pathROI.getBoundsWidth());
                int h = (int) Math.ceil(pathROI.getBoundsHeight());
                String id = core.getUniqueID() == null ? "" : core.getUniqueID();
                writer.println(core.getName() + delimiter + x + delimiter + y + delimiter + w + delimiter + h + delimiter + !core.isMissing() + delimiter + id);
            }
        }
        writer.close();
    } catch (Exception e) {
        logger.error("Error writing TMA data: " + e.getLocalizedMessage(), e);
        return;
    }
    // Save the summary results
    ObservableMeasurementTableData tableData = new ObservableMeasurementTableData();
    tableData.setImageData(imageData, tmaGrid.getTMACoreList());
    SummaryMeasurementTableCommand.saveTableModel(tableData, new File(dirData, "TMA results - " + ServerTools.getDisplayableImageName(server) + ".txt"), Collections.emptyList());
    boolean outputCoreImages = Double.isNaN(downsampleFactor) || downsampleFactor > 0;
    if (outputCoreImages) {
        // Create new overlay options, if we don't have some already
        if (overlayOptions == null) {
            overlayOptions = new OverlayOptions();
            overlayOptions.setFillDetections(true);
        }
        final OverlayOptions options = overlayOptions;
        // Write an overall TMA map (for quickly checking if the dearraying is ok)
        File fileTMAMap = new File(dirData, "TMA map - " + ServerTools.getDisplayableImageName(server) + ".jpg");
        double downsampleThumbnail = Math.max(1, (double) Math.max(server.getWidth(), server.getHeight()) / 1024);
        RegionRequest request = RegionRequest.createInstance(server.getPath(), downsampleThumbnail, 0, 0, server.getWidth(), server.getHeight());
        OverlayOptions optionsThumbnail = new OverlayOptions();
        optionsThumbnail.setShowTMAGrid(true);
        optionsThumbnail.setShowGrid(false);
        optionsThumbnail.setShowAnnotations(false);
        optionsThumbnail.setShowDetections(false);
        try {
            var renderedServer = new RenderedImageServer.Builder(imageData).layers(new TMAGridOverlay(overlayOptions)).downsamples(downsampleThumbnail).build();
            ImageWriterTools.writeImageRegion(renderedServer, request, fileTMAMap.getAbsolutePath());
        // ImageWriters.writeImageRegionWithOverlay(imageData.getServer(), Collections.singletonList(new TMAGridOverlay(overlayOptions, imageData)), request, fileTMAMap.getAbsolutePath());
        } catch (IOException e) {
            logger.warn("Unable to write image overview: " + e.getLocalizedMessage(), e);
        }
        final double downsample = Double.isNaN(downsampleFactor) ? (server.getPixelCalibration().hasPixelSizeMicrons() ? ServerTools.getDownsampleFactor(server, preferredExportPixelSizeMicrons) : 1) : downsampleFactor;
        // Creating a plugin makes it possible to parallelize & show progress easily
        var renderedImageServer = new RenderedImageServer.Builder(imageData).layers(new HierarchyOverlay(null, options, imageData)).downsamples(downsample).build();
        ExportCoresPlugin plugin = new ExportCoresPlugin(dirData, renderedImageServer, downsample, coreExt);
        PluginRunner<BufferedImage> runner;
        var qupath = QuPathGUI.getInstance();
        if (qupath == null || qupath.getImageData() != imageData) {
            runner = new CommandLinePluginRunner<>(imageData);
            plugin.runPlugin(runner, null);
        } else {
            try {
                qupath.runPlugin(plugin, null, false);
            } catch (Exception e) {
                logger.error("Error writing TMA data: " + e.getLocalizedMessage(), e);
            }
        // new Thread(() -> qupath.runPlugin(plugin, null, false)).start();
        // runner = new PluginRunnerFX(QuPathGUI.getInstance());
        // new Thread(() -> plugin.runPlugin(runner, null)).start();
        }
    }
}
Also used : TMACoreObject(qupath.lib.objects.TMACoreObject) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) IOException(java.io.IOException) ROI(qupath.lib.roi.interfaces.ROI) RenderedImageServer(qupath.lib.gui.images.servers.RenderedImageServer) BufferedImage(java.awt.image.BufferedImage) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) HierarchyOverlay(qupath.lib.gui.viewer.overlays.HierarchyOverlay) ObservableMeasurementTableData(qupath.lib.gui.measure.ObservableMeasurementTableData) OverlayOptions(qupath.lib.gui.viewer.OverlayOptions) File(java.io.File) RegionRequest(qupath.lib.regions.RegionRequest) TMAGridOverlay(qupath.lib.gui.viewer.overlays.TMAGridOverlay) PrintWriter(java.io.PrintWriter)

Example 5 with TMAGrid

use of qupath.lib.objects.hierarchy.TMAGrid in project qupath by qupath.

the class TMAScoreImporter method importFromCSV.

private static int importFromCSV(final Map<String, List<String>> map, final PathObjectHierarchy hierarchy) {
    TMAGrid tmaGrid = hierarchy.getTMAGrid();
    if (tmaGrid == null || tmaGrid.nCores() == 0) {
        logger.error("No TMA grid found!");
        return 0;
    }
    // Try to get a 'core' column
    String coreKey = null;
    for (String key : map.keySet()) {
        if (key.trim().toLowerCase().equals("core")) {
            coreKey = key;
            break;
        }
    }
    List<String> coreNames = coreKey == null ? null : map.remove(coreKey);
    // Try to get a unique ID column
    List<String> coreIDs = map.remove(TMACoreObject.KEY_UNIQUE_ID);
    // If we don't have a core column OR a unique ID column, we can't do anything
    if (coreNames == null && coreIDs == null) {
        logger.error("No column with header 'core' or '" + TMACoreObject.KEY_UNIQUE_ID + "' found");
        return 0;
    }
    // int n = coreNames == null ? coreIDs.size() : coreNames.size();
    // Get a list of cores ordered by whatever info we have
    Map<Integer, List<TMACoreObject>> cores = new HashMap<>();
    boolean coresFound = false;
    // If we have any unique IDs, use these and change names accordingly - if possible, and necessary
    if (coreIDs != null) {
        int i = 0;
        for (String id : coreIDs) {
            List<TMACoreObject> coresByID = new ArrayList<>();
            for (TMACoreObject coreTemp : tmaGrid.getTMACoreList()) if (id != null && id.equals(coreTemp.getUniqueID()))
                coresByID.add(coreTemp);
            if (!coresByID.isEmpty()) {
                cores.put(i, coresByID);
                coresFound = true;
                if (coreNames != null && coresByID.size() == 1) {
                    String currentName = coresByID.get(0).getName();
                    String newName = coreNames.get(i);
                    if (!newName.equals(currentName)) {
                        coresByID.get(0).setName(newName);
                        if (currentName != null)
                            logger.warn("Core name changed from {} to {}", currentName, newName);
                    }
                }
            }
            i++;
        }
    }
    // If we didn't have any unique IDs, we need to work with core names instead
    if (!coresFound && coreNames != null) {
        int i = 0;
        for (String name : coreNames) {
            TMACoreObject core = tmaGrid.getTMACore(name);
            if (core != null) {
                cores.put(i, Collections.singletonList(core));
                coresFound = true;
                if (coreIDs != null) {
                    String currentID = core.getUniqueID();
                    String newID = coreIDs.get(i);
                    if (newID != null && !newID.equals(currentID)) {
                        core.setUniqueID(newID);
                        // It shouldn't occur that an existing ID is changed... although it's possible if there are duplicates
                        if (currentID != null)
                            logger.warn("Core unique ID changed from {} to {}", currentID, newID);
                    }
                }
            }
            i++;
        }
    }
    // Add extra columns from the map, either as metadata or measurements
    for (Entry<String, List<String>> entry : map.entrySet()) {
        // Skip columns without headers
        if (entry.getKey() == null || entry.getKey().trim().length() == 0)
            continue;
        // If we have survival data, or else can't parse numeric values, add as metadata
        boolean isOverallSurvival = entry.getKey().equalsIgnoreCase(TMACoreObject.KEY_OVERALL_SURVIVAL);
        boolean isRecurrenceFreeSurvival = entry.getKey().equalsIgnoreCase(TMACoreObject.KEY_RECURRENCE_FREE_SURVIVAL);
        boolean isOSCensored = entry.getKey().equalsIgnoreCase(TMACoreObject.KEY_OS_CENSORED);
        boolean isRFSCensored = entry.getKey().equalsIgnoreCase(TMACoreObject.KEY_RFS_CENSORED);
        // Try to parse numeric data, if we can
        boolean isSurvivalRelated = isOverallSurvival || isRecurrenceFreeSurvival || isOSCensored || isRFSCensored;
        double[] vals = parseNumeric(entry.getValue(), !isSurvivalRelated);
        if (isSurvivalRelated || vals == null || vals.length == GeneralTools.numNaNs(vals)) {
            for (int i : cores.keySet()) {
                for (TMACoreObject core : cores.get(i)) {
                    if (core == null)
                        continue;
                    if (isOverallSurvival)
                        core.getMeasurementList().putMeasurement(TMACoreObject.KEY_OVERALL_SURVIVAL, vals[i]);
                    else if (isRecurrenceFreeSurvival)
                        core.getMeasurementList().putMeasurement(TMACoreObject.KEY_RECURRENCE_FREE_SURVIVAL, vals[i]);
                    else if (isOSCensored)
                        core.getMeasurementList().putMeasurement(TMACoreObject.KEY_OS_CENSORED, vals[i] > 0 ? 1 : 0);
                    else if (isRFSCensored)
                        core.getMeasurementList().putMeasurement(TMACoreObject.KEY_RFS_CENSORED, vals[i] > 0 ? 1 : 0);
                    else
                        core.putMetadataValue(entry.getKey(), entry.getValue().get(i));
                }
            }
        } else {
            // If we have a numeric column, add to measurement list
            for (int i : cores.keySet()) {
                for (TMACoreObject core : cores.get(i)) {
                    core.getMeasurementList().addMeasurement(entry.getKey(), vals[i]);
                }
            }
        }
    }
    // Loop through and close any measurement lists, recording anywhere changes were made
    Set<PathObject> changed = new HashSet<>();
    for (List<TMACoreObject> coreList : cores.values()) {
        for (TMACoreObject core : coreList) {
            if (core == null)
                continue;
            core.getMeasurementList().close();
            changed.add(core);
        }
    }
    hierarchy.fireObjectsChangedEvent(null, changed);
    return changed.size();
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) TMACoreObject(qupath.lib.objects.TMACoreObject) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) ArrayList(java.util.ArrayList) PathObject(qupath.lib.objects.PathObject) ArrayList(java.util.ArrayList) List(java.util.List) HashSet(java.util.HashSet)

Aggregations

TMAGrid (qupath.lib.objects.hierarchy.TMAGrid)17 TMACoreObject (qupath.lib.objects.TMACoreObject)11 ArrayList (java.util.ArrayList)7 DefaultTMAGrid (qupath.lib.objects.hierarchy.DefaultTMAGrid)7 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)7 PathObject (qupath.lib.objects.PathObject)5 BufferedImage (java.awt.image.BufferedImage)4 IOException (java.io.IOException)4 File (java.io.File)3 HashMap (java.util.HashMap)3 List (java.util.List)3 RunningStatistics (qupath.lib.analysis.stats.RunningStatistics)2 RegionRequest (qupath.lib.regions.RegionRequest)2 Graphics2D (java.awt.Graphics2D)1 Point2D (java.awt.geom.Point2D)1 FileNotFoundException (java.io.FileNotFoundException)1 PrintWriter (java.io.PrintWriter)1 Arrays (java.util.Arrays)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1