/* Original method by Volker Backer via https://www.reddit.com/r/ImageJ/comments/qleu36/reordering_particlesrois/ v260420 1st ASC mod (just adds user input via dialog). v260421 Renames original Results table if called results to avoid add to original when re-Measuring. Adds prefs. Adds diagnotics option. v260428 Retains original name as suffix to sequential number and also add Row and Column number. Does not need an open table. */ macroL = "Sort_ROIs_by_Grid_v260428.ijm"; if (isOpen("ROI Manager")) nROIs = RoiManager.size(); else { nROIs = 0; run("ROI Manager..."); } columnsN = round(sqrt(nROIs)); rowsN = nROIs / columnsN; tableN = Table.size(); tableOps = true; closeUnsorted = true; if (tableN == 0) tableName = ""; else if (tableN != nROIs) exit("Mismatch between number of Results \(" + tableN + "\), and the number of ROIs \(" + nROIs + "\)"); else tableName = Table.title; Dialog.create(macroL); Dialog.addMessage("This macro assumes that the " + nROIs + "objects are in a rectangular array,\nso only the row count is needed", 12, "#798541"); Dialog.addNumber("Number of rows", rowsN, 0, 3, ""); Dialog.addCheckbox("Measure ROIs and create new Results Table \(old Results will be in incorrect order\) ", call("ij.Prefs.get", "asc.sortROIGrid.reMeasure", true)); if (tableName != "") Dialog.addCheckbox("Close original " + tableName + " table", call("ij.Prefs.get", "asc.sortROIGrid.closeUnsorted", true)); Dialog.addCheckbox("Add ROI names to new Results table", false); Dialog.addCheckbox("Diagnostics", false); Dialog.show(); rowsN = Dialog.getNumber(); columnsN = nROIs / rowsN; if (nROIs != rowsN * round(columnsN) || nROIs != rowsN * Math.ceil(columnsN)) exit("Either this is not a rectangular grid or the row count \(" + rowsN + "\) is incorrect "); reMeasure = Dialog.getCheckbox(); if (tableName != "") closeUnsorted = Dialog.getCheckbox(); addNamesToTable = Dialog.getCheckbox(); diagnostics = Dialog.getCheckbox(); call("ij.Prefs.set", "asc.sortROIGrid.reMeasure", reMeasure); if (tableName != "") call("ij.Prefs.set", "asc.sortROIGrid.reMeasure", closeUnsorted); if (maxOf(rowsN, columnsN) > 52) exit(maxOf(rowsN, columnsN) + " exceeds the maximum number of columns or rows, this can easily \(if tediously\) be extended if there is a need"); // run("Set Measurements...", "area mean standard min centroid center bounding integrated limit display redirect=None decimal=3"); columnNames = newArray(columnsN); padN = lengthOf(d2s(columnsN, 0)); for (i = 0; i < columnsN; i++) columnNames[i] = "C" + IJ.pad(i + 1, padN); rowNames = newArray(rowsN); padN = lengthOf(d2s(rowsN, 0)); for (i = 0; i < rowsN; i++) rowNames[i] = "R" + IJ.pad(i + 1, padN); for (row = 0; row < rowsN; row++) { xCenters = newArray(); for (column = 0; column < columnsN; column++) { roiManager("select", columnsN * row + column); getSelectionBounds(x, null, width, null); xCenters = Array.concat(xCenters, x + width / 2); } rankPositions = Array.rankPositions(Array.rankPositions(xCenters)); if (diagnostics){ IJ.log("Row " + row + " xCenters:"); Array.print(xCenters); IJ.log("Row " + row + " rankPositions:"); Array.print(rankPositions); } for (column = 0; column < columnsN; column++) { roiManager("select", columnsN * row + column); roiManager("rename", rowNames[row] + "-" + columnNames[rankPositions[column]] + " " + Roi.getName); } } roiManager("Deselect"); roiManager("Sort"); padN = lengthOf(d2s(nROIs, 0)); newNames = newArray(nROIs); /* Can be used later to add ROI names to Results */ for (i = 0; i < nROIs; i++) { roiManager("select", i); newNames[i] = IJ.pad(i + 1, padN) + " " + Roi.getName; roiManager("Rename", newNames[i]); } if (tableName != "") { if (closeUnsorted){ selectWindow(tableName); run("Close"); } } roiManager("Show None"); roiManager("Show All"); /* Re-"Measure" the ROIs in the ROI manager */ if (reMeasure){ if (!closeUnsorted && tableName == "Results") Table.rename("Results", "Unsorted_Results"); roiManager("Measure"); if (addNamesToTable) Table.setColumn("ROI", newNames); rename(tableName + "_resortedROIs"); }