ToskaSkeleton class for skeleton analysis

ToskaSkeleton class for skeleton analysis#

This notebook demonstrates the usage of the ToskaSkeleton class for skeleton analysis with napari-toska

import napari_toska as nts
from skimage.morphology import skeletonize
from skimage.data import binary_blobs
from skimage.measure import label
import napari
viewer = napari.Viewer()
labels = label(binary_blobs(rng=0))
skeleton = skeletonize(labels)
Skeleton = nts.ToskaSkeleton(labels, neighborhood='n8')
Skeleton.analyze()
Building Graph: 100%|██████████| 48/48 [00:00<00:00, 1998.44it/s]
detected malformatted label: 87 changed type from 2 (branch) -> 1 (end point)
Found isolated nodes:  [24]
Could not connect isolated node:  24
Finding spines: 100%|██████████| 14/14 [00:00<00:00, 1555.34it/s]
Calculating summary features: 100%|██████████| 14/14 [00:00<00:00, 875.01it/s]
viewer.add_layer(Skeleton)
<ToskaSkeleton layer 'labels_data' at 0x2d69ba6dd90>

The measured features can be retrieved by inspecting the Skeleton.features attribute. The features are stored in a pandas DataFrame. Note that some measurements describe individual parts of the skeleton (such as the branch_length) whereas others summarize the entire Skeleton (e.g., n_cycle_basis).

Skeleton.features
label object_type skeleton_id branch_length spine n_branches n_endpoints n_branch_points n_cycle_basis n_possible_undirected_cycles
0 1 1 2 0.0 0 25 11 13 2.0 3.0
1 2 1 4 0.0 0 1 2 0 0.0 0.0
2 3 1 4 0.0 0 1 2 0 0.0 0.0
3 4 1 2 0.0 0 25 11 13 2.0 3.0
4 5 1 1 0.0 0 1 2 0 0.0 0.0
... ... ... ... ... ... ... ... ... ... ...
102 103 3 2 0.0 0 25 11 13 2.0 3.0
103 104 3 2 0.0 0 25 11 13 2.0 3.0
104 105 3 2 0.0 0 25 11 13 2.0 3.0
105 106 3 12 0.0 0 3 3 1 0.0 0.0
106 107 3 2 0.0 0 25 11 13 2.0 3.0

107 rows × 10 columns

To retrieve summary statistics about the skeletons in a single dataframe, you can group the dataframe by the skeleton_id and aggregate all other values. In this example, all branch_lengths are summed up whereas the first entry is kept for the summary fields, as they are identical for every graph element, anyway:

# Group Skeletons by skeleton_id
grouped = Skeleton.features.groupby('skeleton_id').agg({'branch_length': 'sum', 'n_branches': 'first', 'n_endpoints': 'first', 'n_branch_points': 'first', 'skeleton_id': 'first'})

# display in single dataframe
grouped
branch_length n_branches n_endpoints n_branch_points skeleton_id
skeleton_id
1 7.071068 1 2 0 1
2 865.498700 25 11 13 2
3 4.242641 1 2 0 3
4 11.313708 1 2 0 4
5 35.355339 1 2 0 5
6 22.627417 1 2 0 6
7 185.261977 9 6 4 7
8 28.284271 1 2 0 8
9 2.828427 1 2 0 9
10 0.000000 0 0 0 10
11 9.899495 1 2 0 11
12 118.793939 3 3 1 12
13 1.414214 1 2 0 13
14 0.000000 0 0 0 14
15 24.041631 1 2 0 15