neu_morpho.measure.metrics¶
Per-body measurements from a skeleton. Pure: arrays in, numbers out.
Everything takes a neu_lib.Skeleton, so a published skeleton can be measured
without rerunning anything, and so can an excluded one (skel.exclude(inside)).
Diameter statistics are weighted by edge length, never per vertex: node density is a property of the skeletonizer, and a densely sampled region would dominate a vertex mean.
The radii are INSCRIBED radii: exact at the node, but systematically small wherever a
cross-section is not round. Volume goes as r^2, so frustum_volume_nm3() is a lower
bound whose tightness depends on how round the neurites are.
Missing radii give NaN, not zero: an unknown calibre must not read as “infinitely thin” in an average.
Functions¶
|
Total edge length, in nm. |
|
Edge-length-weighted diameter statistics, in nm. |
|
Lateral surface area of that same tube: |
|
Volume of the tube the radii imply: one truncated cone per edge. |
|
The largest vertex radius; NaN without radii. |
|
Every skeleton-derived measurement for one body, as one flat row. |
|
Tip, branch-point and connected-component counts from the edge list. |
|
Quantiles of |
Module Contents¶
- neu_morpho.measure.metrics.cable_length_nm(skeleton: neu_lib.Skeleton) float¶
Total edge length, in nm.
Sensitive to skeleton postprocessing (joins add cable, tick removal drops it), so it is only comparable across datasets skeletonized with the same settings.
- neu_morpho.measure.metrics.diameter_stats(skeleton: neu_lib.Skeleton) dict¶
Edge-length-weighted diameter statistics, in nm.
Each edge contributes the mean of its two endpoint radii, weighted by its length; NaN throughout without radii.
p10-p90 describes the twigs, not the trunk: the thick part of a cell is a small length fraction and sits above p90, so read
p99/maxfor the thick end. Percentiles are steps (weighted_quantile()), so where one edge dominates the length they collapse onto its diameter.
- neu_morpho.measure.metrics.frustum_area_nm2(skeleton: neu_lib.Skeleton) float¶
Lateral surface area of that same tube:
pi * (r0 + r1) * slantper edge.End caps are excluded (a neurite’s ends are cuts, not surface). NaN without radii.
- neu_morpho.measure.metrics.frustum_volume_nm3(skeleton: neu_lib.Skeleton) float¶
Volume of the tube the radii imply: one truncated cone per edge.
V = (pi/3) * L * (r0^2 + r0*r1 + r1^2)per edge, summed. Cones overlapping at a junction are double-counted: the opposite sign to the inscribed-radius bias, but not a cancellation of it. NaN without radii.
- neu_morpho.measure.metrics.max_radius_nm(skeleton: neu_lib.Skeleton) float¶
The largest vertex radius; NaN without radii.
Non-positive radii are skipped: kimimaro writes -1 where a radius is unknown.
- neu_morpho.measure.metrics.measure_skeleton(skeleton: neu_lib.Skeleton, *, variant: str = 'all', body_id: int | None = None, dataset: str | None = None) dict¶
Every skeleton-derived measurement for one body, as one flat row.
variantlabels what was measured ("all","minus_nucleus","minus_soma_nucleus","neurite_positive") and is carried into the row, since rows measured differently cannot be compared safely.
- neu_morpho.measure.metrics.topology(skeleton: neu_lib.Skeleton) dict¶
Tip, branch-point and connected-component counts from the edge list.
Segmented bodies are often genuinely fragmented, so more than one component is correct reporting, not a defect.
- neu_morpho.measure.metrics.weighted_quantile(values: Any, weights: Any, q: Any) numpy.ndarray¶
Quantiles of
valuesweighted byweights. Step, not interpolated.Each edge is a length of cable with one diameter, so the weighted median is “the diameter at which half the cable is thinner”: an empirical distribution over cable. Interpolating would let a few sparse samples drag the answer away from where the cable is. Weights of zero are allowed and do not count.