/* Simple macro to plot multiple columns from the active table. Inspired even simpler macro by Kees Straatman https://www2.le.ac.uk/colleges/medbiopsych/facilities-and-services/cbs/AIF/software-1/imagej-macros#Plot%20results 1st version v240808. v240812: Adds rolling average for sorted b: Adds std dev error bar options. v240813: Outputs rolling average and stats to table. b: Can plot original and rolling average plots. v240814: Added ability to output fits over selected range (separate plot). v240815: Rolling averages sent to new table using undocumented argument [see Michael Cammer: IMAGEJ@LIST.NIH.GOV 8/15/2024]. v240816: Cross-checks prefs data with available table data. Expands column names for legends. */ macro ASC_Quick_Plot { macroL = "ASC_QuickPlot_v240816.ijm"; xChar = fromCharCode(0x00D7); ascPrefsKey = "asc.quickplot.Prefs."; if (Table.size<1) exit("An open table is required for " + macroL); tableHeadings = split(Table.headings, "\t"); sortChoices = newArray("no", "ascending", "descending"); infoColor = "#006db0"; /* Honolulu blue */ /* ASC message theme */ instructionColor = "#798541"; /* green_dark_modern (121, 133, 65) AKA Wasabi */ infoWarningColor = "#ff69b4"; /* pink_modern AKA hot pink */ infoFontSize = 13; selectResultsWindow(true); plotTypes = newArray("circle", "box", "triangle", "diamond", "cross", "x", "dot", "line", "connected circle", "filled", "bar", "separated bar"); favoritePlotColorChoices = newArray("black", "gray", "dark_gray", "aqua_modern", "blue_modern", "blue_honolulu", "green_dark_modern", "green_modern", "orange_modern", "pink_modern", "purple_modern", "red_n_modern", "screamin'_green", "garnet", "gold", "vault_gold"); moreStdColorChoices = newArray("white", "black", "light_gray", "red", "green", "blue", "cyan", "magenta", "yellow", "pink", "orange", "violet"); colorChoicesNeon = newArray("jazzberry_jam", "radical_red", "wild_watermelon", "outrageous_orange", "supernova_orange", "atomic_tangerine", "neon_carrot", "sunglow", "laser_lemon", "electric_lime", "screamin'_green", "magic_mint", "blizzard_blue", "dodger_blue", "shocking_pink", "razzle_dazzle_rose", "hot_magenta"); allColorChoices = Array.concat(favoritePlotColorChoices, moreStdColorChoices, colorChoicesNeon); Dialog.create("Plot set selection \(" + macroL + "\)"); xChoice = call("ij.Prefs.get", ascPrefsKey + "xChoice", tableHeadings[1]); iXChoice = indexOfArray(tableHeadings, xChoice, -1); if (iXChoice <0 ) plotsDataSet = tableHeadings[1]; Dialog.addChoice("Select the column for the x-axis", tableHeadings, xChoice); sortTable = call("ij.Prefs.get", ascPrefsKey + "sortTable", false); Dialog.setInsets(-3, 210, 5); Dialog.addCheckbox("Sort table by x column?", sortTable); for (i = 0; i < minOf(6, tableHeadings.length - 1); i++) { plotsDataSet = call("ij.Prefs.get", ascPrefsKey + "plotsDataSet_" + i, "---none---"); iData = indexOfArray(tableHeadings, plotsDataSet, -1); if (iData <0 ) plotsDataSet = "---none---"; Dialog.setInsets(0, 0, 0); Dialog.addChoice("Choose data set to plot__________" + i + 1, Array.concat("---none---", tableHeadings), plotsDataSet); plotsColor = call("ij.Prefs.get", ascPrefsKey + "plotsColor_" + i, allColorChoices[floor(lengthOf(favoritePlotColorChoices) * random())]); Dialog.setInsets(0, 20, 0); Dialog.addChoice("Color: Marker line", allColorChoices, plotsColor); plotsColor2 = call("ij.Prefs.get", ascPrefsKey + "plotsColor2_" + i, allColorChoices[floor(lengthOf(favoritePlotColorChoices) * random())]); Dialog.setInsets(0, 20, 0); Dialog.addChoice("Color: Marker fill/connecting line", allColorChoices, plotsColor2); plotsType = call("ij.Prefs.get", ascPrefsKey + "plotsType" + i, plotTypes[i]); Dialog.setInsets(0, 20, 10); Dialog.addChoice("Select plot \(symbol\) type", plotTypes, plotsType); } Dialog.setInsets(0, 20, 0); if (tableHeadings.length > 7) Dialog.addMessage("Additional data can be added from the built-in plot menu: Data>", infoFontSize, infoColor); Dialog.show(); xChoice = Dialog.getChoice; call("ij.Prefs.set", ascPrefsKey + "xChoice", xChoice); sortTable = Dialog.getCheckbox(); call("ij.Prefs.set", ascPrefsKey + "sortTable", sortTable); /* End Plot Set Selection User Input*/ plotsDataSets = newArray(); plotsColors = newArray(); plotsColor2s = newArray(); plotsTypes = newArray(); for (i = 0, plotN = 0; i < minOf(6, tableHeadings.length - 1); i++) { plotsDataSet = Dialog.getChoice(); plotsColor = Dialog.getChoice(); plotsColor2 = Dialog.getChoice(); plotsType = Dialog.getChoice(); if (plotsDataSet != "---none---") { plotsDataSets[plotN] = plotsDataSet; call("ij.Prefs.set", ascPrefsKey + "plotsDataSet_" + i, plotsDataSet); plotsColors[plotN] = plotsColor; call("ij.Prefs.set", ascPrefsKey + "plotsColor_" + i, plotsColor); plotsColor2s[plotN] = plotsColor2; call("ij.Prefs.set", ascPrefsKey + "plotsColor2_" + i, plotsColor2); plotsTypes[plotN] = plotsType; call("ij.Prefs.set", ascPrefsKey + "plotsType" + i, plotsType); plotN++; } } /* End of dataset selection dialog */ /* Start of plot format dialog */ Dialog.create("Plot format \(" + macroL + "\)"); lineWidth = call("ij.Prefs.get", ascPrefsKey + "lineWidth", 1); Dialog.addNumber("Choose line width", lineWidth, 0, 2, "pixels"); plotWidth = call("ij.Prefs.get", ascPrefsKey + "plotWidth", 512); Dialog.addNumber("Plot width", plotWidth, 0, 5, "pixels"); plotHeight = call("ij.Prefs.get", ascPrefsKey + "plotHeight", 384); Dialog.addNumber("Plot Height", plotHeight, 0, 5, "pixels"); fontSize = call("ij.Prefs.get", ascPrefsKey + "fontSize", 14); Dialog.addNumber("Font size", fontSize, 0, 5, "pixels"); axisLabelFontSize = call("ij.Prefs.get", ascPrefsKey + "axisLabelFontSize", 14); Dialog.addNumber("Axis label font size", axisLabelFontSize, 0, 5, "pixels"); boldAxisLabel = call("ij.Prefs.get", ascPrefsKey + "boldAxisLabel", true); Dialog.setInsets(0, 110, 10); Dialog.addCheckbox("Bold axis label", true); xTitle = call("ij.Prefs.get", ascPrefsKey + "xTitle", xChoice); Dialog.addString("X-axis title", xTitle, 40); yTitle = call("ij.Prefs.get", ascPrefsKey + "yTitle", plotsDataSets[0]); Dialog.addString("y-ayis title", yTitle, 40); if (nImages > 0) plotTitle = call("ij.Prefs.get", ascPrefsKey + "plotTitle", getTitle()); else if (Table.title != "Results") plotTitle = Table.title; else plotTitle = call("ij.Prefs.get", ascPrefsKey + "plotTitle", ""); Dialog.addString("Plot title", plotTitle, 40); Dialog.addNumber("x-axis min", NaN, 0, 4, "Leave blank for automatic"); Dialog.addNumber("x-axis max", NaN, 0, 4, "Leave blank for automatic"); Dialog.addNumber("y-axis min", NaN, 0, 4, "Leave blank for automatic"); Dialog.addNumber("y-axis max", NaN, 0, 4, "Leave blank for automatic"); if (plotN > 1) { legendOptions = newArray("None", "Auto", "top-left", "top-right", "bottom-left", "bottom-right"); legendOption = call("ij.Prefs.get", ascPrefsKey + "legendOption", "Auto"); Dialog.setInsets(0, 50, 10); Dialog.addRadioButtonGroup("Legend options:__________________________", legendOptions, 2, 3, legendOption); } Dialog.addChoice("Create a fit plot for this set:", Array.concat("No fit", plotsDataSets), "No fit"); Dialog.setInsets(0, 20, 0); Dialog.addMessage("Rolling average \(mean\) options:_________________", infoFontSize, infoColor); rollAvgXInterval = call("ij.Prefs.get", ascPrefsKey + "rollAvgXInterval", NaN); Dialog.setInsets(0, 20, 0); Dialog.addNumber("Roll range", rollAvgXInterval, 3, 4, "x-axis units \(leave blank for no\)"); sigmaShow = call("ij.Prefs.get", ascPrefsKey + "sigmaShow", 1); sigmaChar = fromCharCode(0x03C3); xChar = fromCharCode(0x00D7); Dialog.setInsets(0, 20, 0); Dialog.addNumber("Roll error bars", sigmaShow, 0, 2, xChar + " " + sigmaChar + " \(StdDevs\), leave blank for none"); Dialog.setInsets(0, 180, 0); plotOriginalToo = call("ij.Prefs.get", ascPrefsKey + "plotOriginalToo", false); Dialog.addCheckbox("Also plot original data \(set lightness % below\)", plotOriginalToo); Dialog.setInsets(0, 170, 0); oMarkerLightness = call("ij.Prefs.get", ascPrefsKey + "oMarkerLightness", 85); Dialog.addSlider("%", 0, 99, oMarkerLightness); Dialog.setInsets(5, 20, 0); Dialog.addMessage("Additional formatting can be added from the built-in plot menu: More>", infoFontSize, infoColor); Dialog.show(); lineWidth = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "lineWidth", lineWidth); plotWidth = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "plotWidth", plotWidth); plotHeight = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "plotHeight", plotHeight); fontSize = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "fontSize", fontSize); axisLabelFontSize = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "axisLabelFontSize", axisLabelFontSize); boldAxisLabel = Dialog.getCheckbox(); call("ij.Prefs.set", ascPrefsKey + "boldAxisLabel", boldAxisLabel); xTitle = Dialog.getString(); if (xTitle == "") xTitle = xChoice; if (endsWith(xTitle, "um")) xTitle = substring(xTitle, 0, xTitle.length - 2) + getInfo("micrometer.abbreviation"); else if (endsWith(xTitle, "microns")) xTitle = substring(xTitle, 0, xTitle.length - 2) + getInfo("micrometer.abbreviation"); call("ij.Prefs.set", ascPrefsKey + "xTitle", xTitle); yTitle = Dialog.getString(); call("ij.Prefs.set", ascPrefsKey + "yTitle", yTitle); if (yTitle == "") yTitle = yChoice; plotTitle = Dialog.getString(); if (plotTitle == "") plotTitle = xTitle + "-" + yTitle; xMin = Dialog.getNumber(); xMax = Dialog.getNumber(); yMin = Dialog.getNumber(); yMax = Dialog.getNumber(); if (plotN > 1) { legendOption = Dialog.getRadioButton(); call("ij.Prefs.set", ascPrefsKey + "legendOption", legendOption); } else legendOption = "None"; fitChoice = Dialog.getChoice(); rollAvgXInterval = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "rollAvgXInterval", rollAvgXInterval); sigmaShow = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "sigmaShow", sigmaShow); plotOriginalToo = Dialog.getCheckbox(); call("ij.Prefs.set", ascPrefsKey + "plotOriginalToo", plotOriginalToo); oMarkerLightness = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "oMarkerLightness", oMarkerLightness); /* End of plot format dialog */ run("Plots...", "width=&plotWidth height=&plotHeight font=&fontSize draw draw_ticks"); xTitle = replace(xTitle, " um ", " " + getInfo("micrometer.abbreviation") + " "); Plot.create(plotTitle, xTitle, yTitle); Plot.setLineWidth(lineWidth); plotXs = Table.getColumn(xChoice); if (rollAvgXInterval>0){ rollXs = newArray(); Array.getStatistics(plotXs, minX, maxX, null, null); rangeX = maxX - minX; intervalXN = rangeX / rollAvgXInterval; for (i = 0; i < intervalXN; i++) rollXs[i] = minX + (i + 0.5) * rollAvgXInterval; /* Use the midpoint of the interval as the x-value */ if (indexOf(xTitle, "olling")<0) xTitle += " \(Rolling Avg. Over " + rollAvgXInterval +"\)"; Table.setColumn("RollAvg_" + xChoice + "_" + rollAvgXInterval, rollXs); } for (i = 0; i < plotN; i++) { plotYs = Table.getColumn(plotsDataSets[i]); if (rollAvgXInterval>0){ rollYs = newArray(intervalXN); sDs = newArray(intervalXN); for (j = 0; j < intervalXN - 1; j++){ inRangeYs = newArray(); for (k = 0; k < plotYs.length; k++){ tempX = plotXs[k]; if (tempX >= rollXs[j] && tempX < rollXs[j + 1]) inRangeYs = Array.concat(inRangeYs, plotYs[k]); } Array.getStatistics(inRangeYs, null, null, rollYs[j], stdY); sDs[j] = sigmaShow * stdY; } if (plotOriginalToo){ Plot.setColor(getLighterHexColorFromColorName(plotsColors[i], oMarkerLightness)); Plot.add(plotsTypes[i], plotXs, plotYs); } Plot.setColor(getHexColorFromColorName(plotsColors[i]), getHexColorFromColorName(plotsColor2s[i])); Plot.add(plotsTypes[i], rollXs, rollYs, replace(plotsDataSets[i], "_", " ")); plusminus = fromCharCode(0x00B1); Plot.add("error bars", rollXs, sDs, replace(plotsDataSets[i], "_", " ") + " \(Error bars: " + plusminus + sigmaShow + sigmaChar + "\)"); resultsTable = Table.title; rAvgTableTitle = resultsTable + "_Rolling-Average_" + rollAvgXInterval; if (!isOpen(rAvgTableTitle)) Table.create(rAvgTableTitle); Table.setColumn(xTitle, rollXs, rAvgTableTitle); /* Could use Array.show but this gives more control of column titles */ Table.setColumn("RollAvg_" + plotsDataSets[i] + "_" + rollAvgXInterval, rollYs, rAvgTableTitle); Table.setColumn("RollAvg_" + plotsDataSets[i] + "_" + sigmaShow + xChar + sigmaChar, sDs, rAvgTableTitle); selectWindow(resultsTable); } else { Plot.setColor(getHexColorFromColorName(plotsColors[i]), getHexColorFromColorName(plotsColor2s[i])); Plot.add(plotsTypes[i], plotXs, plotYs, plotsDataSets[i]); } } Plot.setLimits(xMin, xMax, yMin, yMax); if (rollAvgXInterval<=0) Plot.removeNaNs(); /* Why not? Well, stops multi-plot from working */ // Plot.setFormatFlags("11001100111111"); /* all default options! */ if (boldAxisLabel) Plot.setAxisLabelSize(axisLabelFontSize, "bold"); else Plot.setAxisLabelSize(axisLabelFontSize); // Fit.plot; // if (showFit) Fit.logResults; if (legendOption != "None") { if (legendOption == "Auto") Plot.setLegend(""); else Plot.setLegend("", legendOption); } Plot.show(); if (fitChoice != "No fit"){ fitYs = Table.getColumn(fitChoice); /* Start plot Dialog */ Array.getStatistics(plotXs, plotXMin, plotXMax, null, null); fitTypes = newArray("Straight Line", "2nd Degree Polynomial", "3rd Degree Polynomial", "4th Degree Polynomial", "4th Degree Polynomial", "5th Degree Polynomial", "Exponential", "Power", "Power (linear regression)", "Exponential with offset", "Log", "Gaussian", "Rodbard", "Gama Variate", "Chapman-Richards"); Dialog.create("Fit options \(" + macroL + "\)"); lowerFitX = maxOf(plotXMin, call("ij.Prefs.get", ascPrefsKey + "lowerFitX", plotXMin)); Dialog.addNumber("Start of x range to be fitted", lowerFitX, 3, 5, ""); upperFitX = minOf(plotXMax, call("ij.Prefs.get", ascPrefsKey + "upperFitX", plotXMax)); Dialog.addNumber("End of x range to be fitted", plotXMax, 3, 5, ""); fitType = call("ij.Prefs.get", ascPrefsKey + "fitType", fitTypes[0]); Dialog.addRadioButtonGroup("Choose fit type:", fitTypes, round(fitTypes.length/round(fitTypes.length/3)), round(fitTypes.length/3), "fitType"); showFit = call("ij.Prefs.get", ascPrefsKey + "showFit", true); Dialog.addCheckbox("Show fit parameter summary on plot", showFit); Dialog.addMessage("Additional fits can be tested from the built-in plot menu: Data>Add Fit...", infoFontSize + 1, infoColor); Dialog.addMessage("The fit can also be added to the original plot from the plot menu: Data>Add From Plot...", infoFontSize + 1, infoColor); Dialog.show(); lowerFitX = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "lowerFitX", lowerFitX); upperFitX = Dialog.getNumber(); call("ij.Prefs.set", ascPrefsKey + "upperFitX", upperFitX); fitType = Dialog.getRadioButton(); call("ij.Prefs.set", ascPrefsKey + "fitType", fitType); showFit = Dialog.getCheckbox(); call("ij.Prefs.set", ascPrefsKey + "showFit", showFit); /* End plot Dialog */ if (lowerFitX == minX && upperFitX == maxX){ fitXRange = plotXs; fitYRange = plotYs; } else { fitXRange = newArray(); fitYRange = newArray(); for (i = 0, r = 0; i < fitYs.length; i++){ if (plotXs[i] >= lowerFitX && plotXs[i] <= upperFitX){ fitXRange[r] = plotXs[i]; fitYRange[r] = fitYs[i]; r++; } } } Fit.doFit(fitType, fitXRange, fitYRange); Fit.plot; } } showStatus(macroL + " completed", "flash green"); beep(); wait(300); beep(); wait(300); beep(); run("Collect Garbage"); /* ( 8(|) ( 8(|) All ASC Functions @@@@@:-) @@@@@:-) */ function expandLabel(str) { /* Expands abbreviations typically used for compact column titles v200604 fromCharCode(0x207B) removed as superscript hyphen not working reliably v211102-v211103 Some more fixes and updated to match latest extended geometries v220808 replaces ° with fromCharCode(0x00B0) v230106 Added a few separation abbreviations v230109 Reorganized to prioritize all standard IJ labels and make more consistent. Also introduced string.replace and string.substring */ requires("1.52t"); /* for string.replace */ /* standard IJ labels */ if (str=="Angle") str = "Ellipse Angle"; else if (str=="AR") str = "Aspect Ratio \(ellipse fit\)"; else if (str=="AR_Box") str = "Aspect Ratio \(bounding rectangle\)"; else if (str=="AR_Feret") str = "Aspect Ratio \(Feret\)"; else if (str=="BX") str = "Bounding Rectangle X Start"; else if (str=="BY") str = "Bounding Rectangle Y Start"; else if (str=="Circ.") str = "Circularity "; else if (str=="Elongation") str = "Elongation \(of bounding rectangle\)"; else if (str=="Feret") str = "Feret's Diameter"; else if (str=="FeretX") str = "Feret X Start"; else if (str=="FeretX2") str = "Feret X End"; else if (str=="FeretY") str = "Feret Y Start"; else if (str=="FeretY2") str = "Feret Y End"; else if (str=="Heigth") str = "Bounding Rectangle Height"; else if (str=="Major") str = "Major Ellipse Axis Length"; else if (str=="Minor") str = "Minor Ellipse Axis Length"; else if (str=="MinFeret") str = "Minimum Feret's Diameter"; else if (str=="MinFeretX") str = "Minimum Feret Start \(x\)"; else if (str=="MinFeretY") str = "Minimum Feret Start \(y\)"; else if (str=="MinFeretX2") str = "Minimum Feret End \(x\)"; else if (str=="MinFeretY2") str = "Minimum Feret End \(y\)"; else if (str=="Perim.") str = "Perimeter "; else if (str=="Round") str = "Roundness \(from area and major ellipse axis\)"; else if (str=="Rnd_Feret") str = "Roundness \(from maximal Feret's diameter\)"; else if (str=="Sqr_Diag_A") str = "Diagonal of Square \(from area\)"; else if (str=="X") str = "Centroid \(x\)"; else if (str=="Y") str = "Centroid \(y\)"; else { /* additional ASC geometries */ str = str.replace(fromCharCode(0x00B0), "degrees"); str = str.replace("0-90_degrees", "0-90" + fromCharCode(0x00B0)); /* An exception to the above*/ str = str.replace("0-90degrees", "0-90" + fromCharCode(0x00B0)); /* An exception to the above*/ str = str.replace("_cAR", "\(Corrected by Aspect Ratio\) "); str = str.replace("AR_", "Aspect Ratio: "); str = str.replace("BoxH", "Bounding Rectangle Height "); str = str.replace("BoxW", "Bounding Rectangle Width "); str = str.replace("Cir_to_El_Tilt", "Circle Tilt \(tilt of curcle to match measured ellipse\) "); str = str.replace(" Crl ", " Curl "); str = str.replace("Compact_Feret", "Compactness \(from Feret axis\) "); str = str.replace("Da_Equiv", "Diameter \(from circle area\) "); str = str.replace("Dp_Equiv", "Diameter \(from circle perimeter\) "); str = str.replace("Dsph_Equiv", "Diameter \(from spherical Feret diameter\) "); str = str.replace("Da", "Diameter \(from circle area\) "); str = str.replace("Dp", "Diameter \(from circle perimeter\) "); str = str.replace("equiv", "Equivalent "); str = str.replace("FeretAngle", "Feret's Angle "); str = str.replace("Feret's Angle 0to90", "Feret's Angle \(0-90" + fromCharCode(0x00B0) + "\)"); /* fixes a precious labelling inconsistency */ str = str.replace("Fbr", "Fiber "); str = str.replace("FiberThAnn", "Fiber Thickness \(from annulus\) "); str = str.replace("FiberLAnn", "Fiber Length (\from annulus\) "); str = str.replace("FiberLR", "Fiber Length R "); str = str.replace("HSFR", "Hexagon Shape Factor Ratio "); str = str.replace("HSF", "Hexagon Shape Factor "); str = str.replace("Hxgn_", "Hexagon: "); str = str.replace("Intfc_D", "Interfacial Density "); str = str.replace("MinSepNNROI", "Minimum Separation NN ROI "); str = str.replace("MinSepROI", "Minimum ROI Separation "); str = str.replace("MinSepThisROI", "Minimum Separation this ROI "); str = str.replace("MinSep", "Minimum Separation "); str = str.replace("NN", "Nearest Neighbor "); str = str.replace("ObjectN", "Object Number "); str = str.replace("Perim.", "Perimeter "); if (indexOf(str, "Perimeter")!=indexOf(str, "Perim")) str.replace("Perim", "Perimeter "); str = str.replace("Perimetereter", "Perimeter "); /* just in case above failed */ str = str.replace("Snk", "\(Snake\) "); str = str.replace("Raw Int Den", "Raw Interfacial Density "); str = str.replace("Rndnss", "Roundness "); str = str.replace("Rnd_", "Roundness: "); str = str.replace("Rss1", "/(Russ Formula 1/) "); str = str.replace("Rss1", "/(Russ Formula 2/) "); str = str.replace("Sqr_", "Square: "); str = str.replace("Squarity_AP", "Squarity \(from area and perimeter\) "); str = str.replace("Squarity_AF", "Squarity \(from area and Feret\) "); str = str.replace("Squarity_Ff", "Squarity \(from Feret\) "); str = str.replace(" Th ", " Thickness "); str = str.replace("ThisROI", " this ROI "); str = str.replace("Vol_", "Volume: "); if(str=="Width") str = "Bounding Rectangle Width"; str = str.replace("XM", "Center of Mass \(x\)"); str = str.replace("XY", "Center of Mass \(y\)"); str = str.replace(fromCharCode(0x00C2), ""); /* Remove mystery  */ str = str.replace(fromCharCode(0x2009), " "); } while (indexOf(str, "_")>=0) str = str.replace("_", " "); while (indexOf(str, " ")>=0) str = str.replace(" ", " "); while (endsWith(str, " ")) str = str.substring(0, lengthOf(str)-1); return str; } function indexOfArray(array, value, default){ /* v190423 Adds "default" parameter (use -1 for backwards compatibility). Returns only first found value v230902 Limits default value to array size */ index = minOf(lengthOf(array) - 1, default); for (i=0; i0){ resultsWindows = newArray(); for (i=0; i1){ resultsWindows = Array.sort(resultsWindows); /* R for Results comes before S for Summary */ Dialog.create("Select table for analysis: " + functionL); Dialog.addChoice("Choose Results Table: ", resultsWindows, resultsWindows[0]); Dialog.show(); selectWindow(Dialog.getChoice()); } else if (resultsWindows.length==1) selectWindow(resultsWindows[0]); else restoreExit("Sorry, no results windows found"); } /* Color Functions - Expanded from BAR utilities - Ferreira et al (2017). https://zenodo.org/records/495245 */ function getColorArrayFromColorName(colorName) { /* v180828 added Fluorescent Colors v181017-8 added off-white and off-black for use in gif transparency and also added safe exit if no color match found v191211 added Cyan v211022 all names lower-case, all spaces to underscores v220225 Added more hash value comments as a reference v220706 restores missing magenta v230130 Added more descriptions and modified order. v230908: Returns "white" array if not match is found and logs issues without exiting. v240123: Removed duplicate entries: Now 53 unique colors. v240709: Added 2024 FSU-Branding Colors. Some reorganization. Now 60 unique colors. */ functionL = "getColorArrayFromColorName_v240709"; cA = newArray(255, 255, 255); /* defaults to white */ if (colorName == "white") cA = newArray(255, 255, 255); else if (colorName == "black") cA = newArray(0, 0, 0); else if (colorName == "off-white") cA = newArray(245, 245, 245); else if (colorName == "off-black") cA = newArray(10, 10, 10); else if (colorName == "light_gray") cA = newArray(200, 200, 200); else if (colorName == "gray") cA = newArray(127, 127, 127); else if (colorName == "dark_gray") cA = newArray(51, 51, 51); else if (colorName == "red") cA = newArray(255, 0, 0); else if (colorName == "green") cA = newArray(0, 255, 0); /* #00FF00 AKA Lime green */ else if (colorName == "blue") cA = newArray(0, 0, 255); else if (colorName == "cyan") cA = newArray(0, 255, 255); else if (colorName == "yellow") cA = newArray(255, 255, 0); else if (colorName == "magenta") cA = newArray(255, 0, 255); /* #FF00FF */ else if (colorName == "pink") cA = newArray(255, 192, 203); else if (colorName == "violet") cA = newArray(127, 0, 255); else if (colorName == "orange") cA = newArray(255, 165, 0); /* Excel Modern + */ else if (colorName == "aqua_modern") cA = newArray(75, 172, 198); /* #4bacc6 AKA "Viking" aqua */ else if (colorName == "blue_accent_modern") cA = newArray(79, 129, 189); /* #4f81bd */ else if (colorName == "blue_dark_modern") cA = newArray(31, 73, 125); /* #1F497D */ else if (colorName == "blue_honolulu") cA = newArray(0, 118, 182); /* Honolulu Blue #006db0 */ else if (colorName == "blue_modern") cA = newArray(58, 93, 174); /* #3a5dae */ else if (colorName == "gray_modern") cA = newArray(83, 86, 90); /* bright gray #53565A */ else if (colorName == "green_dark_modern") cA = newArray(121, 133, 65); /* Wasabi #798541 */ else if (colorName == "green_modern") cA = newArray(155, 187, 89); /* #9bbb59 AKA "Chelsea Cucumber" */ else if (colorName == "green_modern_accent") cA = newArray(214, 228, 187); /* #D6E4BB AKA "Gin" */ else if (colorName == "green_spring_accent") cA = newArray(0, 255, 102); /* #00FF66 AKA "Spring Green" */ else if (colorName == "orange_modern") cA = newArray(247, 150, 70); /* #f79646 tan hide, light orange */ else if (colorName == "pink_modern") cA = newArray(255, 105, 180); /* hot pink #ff69b4 */ else if (colorName == "purple_modern") cA = newArray(128, 100, 162); /* blue-magenta, purple paradise #8064A2 */ else if (colorName == "red_n_modern") cA = newArray(227, 24, 55); else if (colorName == "red_modern") cA = newArray(192, 80, 77); else if (colorName == "tan_modern") cA = newArray(238, 236, 225); else if (colorName == "violet_modern") cA = newArray(76, 65, 132); else if (colorName == "yellow_modern") cA = newArray(247, 238, 69); /* FSU */ else if (colorName == "garnet") cA = newArray(120, 47, 64); /* #782F40 */ else if (colorName == "gold") cA = newArray(206, 184, 136); /* #CEB888 */ else if (colorName == "gulf_sands") cA = newArray(223, 209, 167); /* #DFD1A7 */ else if (colorName == "stadium_night") cA = newArray(16, 24, 32); /* #101820 */ else if (colorName == "westcott_water") cA = newArray(92, 184, 178); /* #5CB8B2 */ else if (colorName == "vault_garnet") cA = newArray(166, 25, 46); /* #A6192E */ else if (colorName == "legacy_blue") cA = newArray(66, 85, 99); /* #425563 */ else if (colorName == "plaza_brick") cA = newArray(66, 85, 99); /* #572932 */ else if (colorName == "vault_gold") cA = newArray(255, 199, 44); /* #FFC72C */ /* Fluorescent Colors https://www.w3schools.com/colors/colors_crayola.asp */ else if (colorName == "radical_red") cA = newArray(255, 53, 94); /* #FF355E */ else if (colorName == "jazzberry_jam") cA = newArray(165, 11, 94); else if (colorName == "wild_watermelon") cA = newArray(253, 91, 120); /* #FD5B78 */ else if (colorName == "shocking_pink") cA = newArray(255, 110, 255); /* #FF6EFF Ultra Pink */ else if (colorName == "razzle_dazzle_rose") cA = newArray(238, 52, 210); /* #EE34D2 */ else if (colorName == "hot_magenta") cA = newArray(255, 0, 204); /* #FF00CC AKA Purple Pizzazz */ else if (colorName == "outrageous_orange") cA = newArray(255, 96, 55); /* #FF6037 */ else if (colorName == "supernova_orange") cA = newArray(255, 191, 63); /* FFBF3F Supernova Neon Orange*/ else if (colorName == "sunglow") cA = newArray(255, 204, 51); /* #FFCC33 */ else if (colorName == "neon_carrot") cA = newArray(255, 153, 51); /* #FF9933 */ else if (colorName == "atomic_tangerine") cA = newArray(255, 153, 102); /* #FF9966 */ else if (colorName == "laser_lemon") cA = newArray(255, 255, 102); /* #FFFF66 "Unmellow Yellow" */ else if (colorName == "electric_lime") cA = newArray(204, 255, 0); /* #CCFF00 */ else if (colorName == "screamin'_green") cA = newArray(102, 255, 102); /* #66FF66 */ else if (colorName == "magic_mint") cA = newArray(170, 240, 209); /* #AAF0D1 */ else if (colorName == "blizzard_blue") cA = newArray(80, 191, 230); /* #50BFE6 Malibu */ else if (colorName == "dodger_blue") cA = newArray(9, 159, 255); /* #099FFF Dodger Neon Blue */ else IJ.log(colorName + " not found in " + functionL + ": Color defaulted to white"); return cA; } /* Hex conversion below adapted from T.Ferreira, 20010.01 https://imagej.net/doku.php?id=macro:rgbtohex */ function getHexColorFromColorName(colorNameString) { /* v231207: Uses IJ String.pad instead of function: pad */ colorArray = getColorArrayFromColorName(colorNameString); r = toHex(colorArray[0]); g = toHex(colorArray[1]); b = toHex(colorArray[2]); hexName = "#" + "" + String.pad(r, 2) + "" + String.pad(g, 2) + "" + String.pad(b, 2); return hexName; } function getLighterHexColorFromColorName(colorNameString, lighterPC) { /* v240813: 1st version. Based on getHexColorFromColorName(colorNameString) */ cRGBs = getColorArrayFromColorName(colorNameString); for (i = 0; i<3; i++){ if (lighterPC > 0) cRGBs[i] = cRGBs[i] + (255 - cRGBs[i]) * minOf(100, lighterPC) / 100; else if (lighterPC < 0) cRGBs[i] = cRGBs[i] + (cRGBs[i]) * maxOf(-100, lighterPC) / 100; } Array.getStatistics(cRGBs, intMin, intMax, intMean, null); r = toHex(cRGBs[0]); g = toHex(cRGBs[1]); b = toHex(cRGBs[2]); hexName = "#" + "" + String.pad(r, 2) + "" + String.pad(g, 2) + "" + String.pad(b, 2); return hexName; }