Sholl analysis in Skan#
Skan provides a function to perform Sholl analysis, which counts the number of processes crossing circular (2D) or spherical (3D) shells from a given center point. Commonly, the center point is the soma, or cell body, of a neuron, but the method can be used to compare general skeleton structures when a root or center point is defined.
%matplotlib inline
%config InlineBackend.figure_format='retina'
import matplotlib.pyplot as plt
import numpy as np
import zarr
neuron = np.asarray(zarr.open('example-data/neuron.zarr.zip'))
fig, ax = plt.subplots()
ax.imshow(neuron, cmap='gray')
ax.scatter(57, 54)
ax.set_axis_off()
plt.show()
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
Input In [2], in <cell line: 4>()
1 import numpy as np
2 import zarr
----> 4 neuron = np.asarray(zarr.open('example-data/neuron.zarr.zip'))
6 fig, ax = plt.subplots()
7 ax.imshow(neuron, cmap='gray')
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/zarr/convenience.py:82, in open(store, mode, **kwargs)
78 path = kwargs.get('path')
79 # handle polymorphic store arg
80 # we pass storage options explicitly, since normalize_store_arg might construct
81 # a store if the input is a fsspec-compatible URL
---> 82 _store: BaseStore = normalize_store_arg(
83 store, storage_options=kwargs.pop("storage_options", {}), mode=mode
84 )
85 path = normalize_storage_path(path)
87 if mode in {'w', 'w-', 'x'}:
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/zarr/storage.py:118, in normalize_store_arg(store, storage_options, mode)
116 raise ValueError("storage_options passed with non-fsspec path")
117 if store.endswith('.zip'):
--> 118 return ZipStore(store, mode=mode)
119 elif store.endswith('.n5'):
120 from zarr.n5 import N5Store
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/site-packages/zarr/storage.py:1506, in ZipStore.__init__(self, path, compression, allowZip64, mode, dimension_separator)
1503 self.mutex = RLock()
1505 # open zip file
-> 1506 self.zf = zipfile.ZipFile(path, mode=mode, compression=compression,
1507 allowZip64=allowZip64)
File /opt/hostedtoolcache/Python/3.9.12/x64/lib/python3.9/zipfile.py:1248, in ZipFile.__init__(self, file, mode, compression, allowZip64, compresslevel, strict_timestamps)
1246 while True:
1247 try:
-> 1248 self.fp = io.open(file, filemode)
1249 except OSError:
1250 if filemode in modeDict:
FileNotFoundError: [Errno 2] No such file or directory: '/home/runner/work/skan/skan/doc/examples/example-data/neuron.zarr.zip'
This is the skeletonized image of a neuron. The cell body, or soma, has been manually annotated by a researcher based on the source image. We can use the function skan.sholl_analysis to count the crossings of concentric circles, centered on the cell body, by the cell’s processes.
import pandas as pd
from skan import Skeleton, sholl_analysis
# make the skeleton object
skeleton = Skeleton(neuron)
# define the neuron center/soma
center = np.array([54, 57])
# define radii at which to measure crossings
radii = np.arange(4, 45, 4)
# perform sholl analysis
center, radii, counts = sholl_analysis(
skeleton, center=center, shells=radii
)
table = pd.DataFrame({'radius': radii, 'crossings': counts})
table
We can visualize this using functions from skan.draw and matplotlib.
from skan import draw
# make two subplots
fig, (ax0, ax1) = plt.subplots(nrows=1, ncols=2, figsize=(8, 4))
# draw the skeleton
draw.overlay_skeleton_2d_class(
skeleton, skeleton_colormap='viridis_r', vmin=0, axes=ax0
)
# draw the shells
draw.sholl_shells(center, radii, axes=ax0)
# fiddle with plot visual aspects
ax0.autoscale_view()
ax0.set_facecolor('black')
ax0.set_ylim(75, 20)
ax0.set_xlim(20, 80)
ax0.set_aspect('equal')
# in second subplot, plot the Sholl analysis
ax1.plot('radius', 'crossings', data=table)
ax1.set_xlabel('radius')
ax1.set_ylabel('crossings')
plt.show()