Skip to content

Commit

Permalink
API improvements/fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
tferr committed May 7, 2024
1 parent f78effe commit f79b725
Show file tree
Hide file tree
Showing 17 changed files with 479 additions and 238 deletions.
18 changes: 18 additions & 0 deletions src/main/java/sc/fiji/snt/Tree.java
Original file line number Diff line number Diff line change
Expand Up @@ -1605,6 +1605,11 @@ public String toString() {

}

/**
* Assigns distinct colors to a collection of Trees.
*
* @see SNTColor#getDistinctColors(int)
*/
public static void assignUniqueColors(final Collection<Tree> trees) {
final ColorRGB[] colors = SNTColor.getDistinctColors(trees.size());
int i = 0;
Expand All @@ -1613,6 +1618,19 @@ public static void assignUniqueColors(final Collection<Tree> trees) {
}
}

/**
* Assigns distinct colors to a collection of Trees.
*
* @param excludedHue an optional string defining a hue to be excluded. Either 'red', 'green', or 'blue'.
* @see SNTColor#getDistinctColors(int, String)
*/
public static void assignUniqueColors(final Collection<Tree> trees, final String excludedHue) {
final ColorRGB[] colors = SNTColor.getDistinctColors(trees.size(), excludedHue);
int i = 0;
for (Iterator<Tree> it = trees.iterator(); it.hasNext(); i++) {
it.next().setColor(colors[i]);
}
}
/**
* Assigns the spatial calibration of an image to this Tree.
*
Expand Down
63 changes: 63 additions & 0 deletions src/main/java/sc/fiji/snt/analysis/AnnotationMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*-
* #%L
* Fiji distribution of ImageJ for the life sciences.
* %%
* Copyright (C) 2010 - 2024 Fiji developers.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/

package sc.fiji.snt.analysis;

import net.imglib2.display.ColorTable;
import sc.fiji.snt.viewer.Annotation3D;


import java.util.*;

public class AnnotationMapper extends ColorMapper {

private final Collection<Annotation3D> annotations;
private double transparency;

public AnnotationMapper(final Collection<Annotation3D> annotations) {
this.annotations = annotations;
}

/**
* @param transparencyPercent the color transparency (in percentage) of mapped annotations
*/
public void setTransparency(final double transparencyPercent) {
this.transparency = transparencyPercent;
}

@Override
public void map(final String measurement, final ColorTable colorTable) {
super.map(measurement, colorTable);
for (final Annotation3D annotation : annotations) {
final double v = getValue(annotation);
if (v < min) min = v;
if (v > max) max = v;
}
for (final Annotation3D annotation : annotations) {
annotation.setColor(getColorRGB(getValue(annotation)), transparency);
}
}

private double getValue(final Annotation3D annotation) {
return annotation.getVolume(); // currently only volume is supported
}
}
25 changes: 13 additions & 12 deletions src/main/java/sc/fiji/snt/analysis/GroupedTreeStatistics.java
Original file line number Diff line number Diff line change
Expand Up @@ -453,18 +453,19 @@ public SNTChart getFlowPlot(final String feature, final int depth) {
* Assembles a Flow plot (aka Sankey diagram) for the specified feature using
* "mean" as integration statistic, no cutoff value, and all of the brain
* regions of the specified ontology depth. *
*
* @param feature the feature ({@value MultiTreeStatistics#LENGTH},
* {@value MultiTreeStatistics#N_BRANCH_POINTS},
* {@value MultiTreeStatistics#N_TIPS}, etc.)
* @param depth the ontological depth of the compartments to be considered
* @param cutoff a filtering option. If the computed {@code feature} for an
* annotation is below this value, that annotation is excluded
* from the plot * @param normalize If true, values are retrieved
* as ratios. E.g., If {@code feature} is
* {@value MultiTreeStatistics#LENGTH}, and {@code cutoff} 0.1,
* BrainAnnotations in {@code annotations} associated with less
* than 10% of cable length are ignored.
*
* @param feature the feature ({@value MultiTreeStatistics#LENGTH},
* {@value MultiTreeStatistics#N_BRANCH_POINTS},
* {@value MultiTreeStatistics#N_TIPS}, etc.)
* @param depth the ontological depth of the compartments to be considered
* @param cutoff a filtering option. If the computed {@code feature} for an
* annotation is below this value, that annotation is excluded
* from the plot
* @param normalize If true, values are retrieved as ratios. E.g., If
* {@code feature} is {@value MultiTreeStatistics#LENGTH},
* and {@code cutoff} 0.1, BrainAnnotations in
* {@code annotations} associated with less than 10% of cable
* length are ignored.
* @return the flow plot
*/
public SNTChart getFlowPlot(final String feature, final int depth, final double cutoff, final boolean normalize) {
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/sc/fiji/snt/analysis/MultiTreeStatistics.java
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,16 @@ public SNTChart getPolarHistogram(final String metric) {
}
}

public SNTTable getRawValues(final String metric) {
final String normMeasurement = getNormalizedMeasurement(metric);
final HistogramDatasetPlusMulti datasetPlus = new HistogramDatasetPlusMulti(normMeasurement);
try {
return datasetPlus.getTable();
} catch (final IllegalArgumentException ex) {
throw new IllegalArgumentException("TreeStatistics metric is likely not supported by MultiTreeStatistics",
ex);
}
}
@Override
public Set<PointInImage> getTips() {
assignGroupToSuperTree();
Expand Down Expand Up @@ -404,6 +414,11 @@ class HistogramDatasetPlusMulti extends HDPlus {
values.add(v);
}
}
SNTTable getTable() {
final SNTTable table = new SNTTable();
table.addColumn(measurement, lastDstats.dStats.getValues());
return table;
}
}

public static List<String> getMetrics() {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/sc/fiji/snt/analysis/NodeColorMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@

import org.scijava.Context;

import net.imagej.display.ColorTables;
import net.imglib2.display.ColorTable;
import sc.fiji.snt.SNTService;
import sc.fiji.snt.Tree;
import sc.fiji.snt.util.ColorMaps;
import sc.fiji.snt.util.PointInImage;
import sc.fiji.snt.util.SNTPoint;
import sc.fiji.snt.viewer.Viewer3D;
Expand Down Expand Up @@ -222,12 +222,12 @@ public static void main(final String... args) {
final List<PointInImage> nodes = tree.getNodes();
final NodeStatistics<?> nodeStats = new NodeStatistics<>(nodes);
final NodeColorMapper mapper = new NodeColorMapper(nodeStats);
mapper.map("x-coord", ColorTables.ICE);
mapper.map("x-coord", ColorMaps.ICE);
final Viewer3D viewer1 = new Viewer3D();
viewer1.annotatePoints(nodes, "dummy annotation");
//viewer.annotatePoints(mapper.getNodes(), "dummy annotation");
nodeStats.assignBranches(tree);
mapper.map("length", ColorTables.ICE);
mapper.map("length", ColorMaps.ICE);
final Viewer3D viewer2 = new Viewer3D();
viewer2.annotatePoints(nodes, "dummy annotation");
viewer1.show();
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/sc/fiji/snt/analysis/NodeStatistics.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,43 @@ private void assembleStats() throws UnknownMetricException {
}
}

/**
* Filters the current pool of nodes matching a measurement-based criterion.
*
* @param metric the measurement ({@link #X_COORDINATES}, {@link #Y_COORDINATES},
* {@link #BRANCH_ORDER}, etc.)
* @param lowerBound the lower metric value (inclusive)
* @param upperBound the upper metric value (inclusive)
* @return the filtered list.
*/
public List<T> filter(final String metric, final double lowerBound, final double upperBound) throws UnknownMetricException {
currentMetric = getNormalizedMeasurement(metric);
switch (currentMetric) {
case BRANCH_LENGTH:
assessIfBranchesHaveBeenAssigned();
return points.stream().filter(p ->
p.getPath().getLength() >= lowerBound && p.getPath().getLength() <= upperBound).collect(Collectors.toList());
case BRANCH_ORDER:
assessIfBranchesHaveBeenAssigned();
return points.stream().filter(p ->
p.getPath().getOrder() >= lowerBound && p.getPath().getOrder() <= upperBound).collect(Collectors.toList());
case VALUES:
return points.stream().filter(p ->
p.v >= lowerBound && p.v <= upperBound).collect(Collectors.toList());
case X_COORDINATES:
return points.stream().filter(p ->
p.getX() >= lowerBound && p.getX() <= upperBound).collect(Collectors.toList());
case Y_COORDINATES:
return points.stream().filter(p ->
p.getY() >= lowerBound && p.getY() <= upperBound).collect(Collectors.toList());
case Z_COORDINATES:
return points.stream().filter(p ->
p.getZ() >= lowerBound && p.getZ() <= upperBound).collect(Collectors.toList());
default:
throw new UnknownMetricException("Unrecognized metric: " + currentMetric);
}
}

/**
* Gets the relative frequencies histogram for a univariate measurement. The
* number of bins is determined using the Freedman-Diaconis rule.
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/sc/fiji/snt/analysis/SNTChart.java
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ public void saveAsPNG(final File file) throws IOException {

public void saveAsPNG(final String filePath) throws IOException {
final File f = new File((filePath.toLowerCase().endsWith(".png")) ? filePath : filePath + ".png");
f.mkdirs();
if(!f.getParentFile().exists()) f.getParentFile().mkdirs();
saveAsPNG(f);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/sc/fiji/snt/analysis/SNTTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ public static String toString(final GenericTable table, final int firstRow, fina

public static void save(final Table<?, ?> table, final char columnSep, final boolean saveColHeaders,
final boolean saveRowHeaders, final File outputFile) throws IOException {
if(!outputFile.exists()) outputFile.mkdirs();
if(!outputFile.getParentFile().exists()) outputFile.getParentFile().mkdirs();
final FileOutputStream fos = new FileOutputStream(outputFile, false);
final OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
final PrintWriter pw = new PrintWriter(new BufferedWriter(osw), true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

package sc.fiji.snt.analysis;

class UnknownMetricException extends IllegalArgumentException {
public class UnknownMetricException extends IllegalArgumentException {
private static final long serialVersionUID = 1L;

protected UnknownMetricException(final String msg) {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/sc/fiji/snt/annotation/AllenUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ public static AllenCompartment getCompartment(final int id) {
* null if no match was found
*/
public static AllenCompartment getCompartment(final String nameOrAcronym) {
if (nameOrAcronym.equalsIgnoreCase("root"))
return getCompartment(AllenUtils.BRAIN_ROOT_ID);
areaList = getBrainAreasList();
for (int n = 0; n < areaList.length(); n++) {
final JSONObject area = (JSONObject) areaList.get(n);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/sc/fiji/snt/gui/GuiUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1281,7 +1281,7 @@ public void mouseClicked(final MouseEvent me) {
SNTUtils.getContext().getService(CommandService.class).run("org.scijava.plugins.commands.debug.SystemInformation", true);
timer = new Timer(3000, e -> d.dispose());
} else {
ijDetails.setText("<HTML>SystemInformation command not found!?");
ijDetails.setText("<HTML>System Information command not found!?");
timer = new Timer(3000, e -> ijDetails.setText(details));
}
timer.setRepeats(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
package sc.fiji.snt.gui.cmds;

import net.imagej.ImageJ;
import net.imagej.display.ColorTables;

import org.scijava.ItemVisibility;
import org.scijava.command.Command;
Expand All @@ -36,6 +35,7 @@
import sc.fiji.snt.analysis.graph.AnnotationWeightedEdge;
import sc.fiji.snt.analysis.graph.GraphColorMapper;
import sc.fiji.snt.annotation.BrainAnnotation;
import sc.fiji.snt.util.ColorMaps;
import sc.fiji.snt.viewer.GraphViewer;
import sc.fiji.snt.viewer.geditor.AnnotationGraphAdapter;
import sc.fiji.snt.viewer.geditor.GraphEditor;
Expand Down Expand Up @@ -118,7 +118,7 @@ public void run() {
graphViewer.setContext(getContext());
final GraphEditor editor = graphViewer.getEditor();
final GraphColorMapper<BrainAnnotation, AnnotationWeightedEdge> mapper = new GraphColorMapper<>();
mapper.map(annotationGraph, GraphColorMapper.EDGE_WEIGHT, ColorTables.ICE);
mapper.map(annotationGraph, GraphColorMapper.EDGE_WEIGHT, ColorMaps.ICE);
final AnnotationGraphAdapter graphAdapter = (AnnotationGraphAdapter) (editor.getGraphComponent()
.getGraph());
graphAdapter.scaleEdgeWidths(1, (large) ? 15 : 10, "linear");
Expand Down
28 changes: 17 additions & 11 deletions src/main/java/sc/fiji/snt/gui/cmds/FigCreatorCmd.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,15 @@ private void init() {

@Override
public void run() {
if (trees == null || trees.isEmpty()) {
if (trees == null) {
error("No reconstructions have been specified.");
return;
}
trees.removeIf(tree -> tree == null || tree.isEmpty());
if (trees.isEmpty()) { // may happen with auto-traced structures!?
error("No valid reconstructions exist.");
return;
}
String transformationFlags = normalize;
if (!type.toLowerCase().contains("3d"))
transformationFlags += " " + view;
Expand All @@ -106,17 +111,18 @@ public void run() {
}

private static Viewer3D.ViewMode getView(final String flag) {
if (flag.toLowerCase().contains("xz"))
final String lcFlag = flag.toLowerCase();
if (lcFlag.contains("xz") || lcFlag.contains("zx"))
return Viewer3D.ViewMode.XZ;
if (flag.toLowerCase().contains("zy"))
if (lcFlag.contains("yz") || lcFlag.contains("zy"))
return Viewer3D.ViewMode.YZ;
return Viewer3D.ViewMode.XY;
return Viewer3D.ViewMode.DEFAULT;
}

private static Collection<Tree> getTreesForRendering(final Collection<Tree> trees, final String renderOptions) {
final String options = renderOptions.toLowerCase();
final boolean isZY = options.contains("zy");
final boolean isXZ = options.contains("xz");
final boolean isZY = options.contains("zy") || options.contains("yz");
final boolean isXZ = options.contains("xz") || options.contains("zx");
final boolean center = options.contains("norm") || options.contains("relative") || options.contains("center");
final Collection<Tree> renderingTrees;
if (center || isZY || isXZ) {
Expand Down Expand Up @@ -168,7 +174,7 @@ private static Object singleScene(final Collection<Tree> renderingTrees, final S
result.add(renderingTrees);
result.show();
return result;
} else if (flags.contains("3d")) {
} else if (flags.contains("3d") || flags.contains("interactive")) {
final Viewer3D result = new Viewer3D();
result.add(renderingTrees);
result.setViewMode(getView(renderOptions));
Expand All @@ -190,10 +196,10 @@ private static Object singleScene(final Collection<Tree> renderingTrees, final S
* <tt>2d raster</tt>: trees are rendered as 2D skeletonized images<br>
* <tt>2d vector</tt>: trees are rendered in a static (non-interactive) Viewer2D<br>
* <tt>3d</tt>: trees are rendered in interactive Viewer3D canvas(es)<br>
* <tt>xz</tt>: whether trees should be rendered in a XZ view (default is XY)<br>
* <tt>zy</tt>: whether trees should be rendered in a ZY view (default is XY)<br>
* <tt>center</tt>: whether trees should be translated so that their roots/somas are displayed at a
* common origin (0,0,0)
* <tt>xz</tt>: whether trees should be displayed in a XZ view (default is XY)<br>
* <tt>zy</tt>: whether trees should be displayed in a ZY view (default is XY)<br>
* <tt>center</tt>: whether trees should be translated so that their roots/somas are displayed
* at a common origin (0,0,0)<br>
* </p>
* @return a reference to the displayed viewer
*/
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/sc/fiji/snt/plugin/ij1/Strahler.java
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ public void run(final String arg) {
if (outIS)
imp2.show();
ip3.setMinAndMax(0, order);
ColorMaps.applyMagmaColorMap(imp3, 200, false);
ColorMaps.applyPlasma(imp3, 200, false);
if (validRootRoi)
imp3.setRoi(rootRoi);
imp3.show();
Expand Down
Loading

0 comments on commit f79b725

Please sign in to comment.