# A few tools for downloading the data
from io import StringIO
import requests
from neuron_morphology.swc_io import morphology_from_swc
from neuron_morphology.feature_extractor.data import Data
def data_from_url(morphology_url):
morphology_swc = StringIO(requests.get(morphology_url).text)
# Feature functions expect a Data object - in this case just a wrapper for a Morphology
# If we were working with additional data (say, layer annotations) we would store these here as well
return Data(morphology_from_swc(morphology_swc))
# fetch a published reconstruction
test_data = data_from_url("http://celltypes.brain-map.org/api/v2/well_known_file_download/491120375")
more_test_data = data_from_url("http://celltypes.brain-map.org/api/v2/well_known_file_download/692297222")
import matplotlib.pyplot as plt
nodes = test_data.morphology.nodes()
x = [node['x'] for node in nodes]
y = [node['y'] for node in nodes]
z = [node['z'] for node in nodes]
fig, ax = plt.subplots(1, 2)
ax[0].scatter(x, y, s=0.1)
ax[1].scatter(z, y, s=0.1)
See the features subpackage for the full list.
from neuron_morphology.features.branching.bifurcations import num_outer_bifurcations
num_outer_bifurcations
# we can call this just like any function
num_outer_bifurcations(test_data)
You can look in default features for a list of the features that are run by default.
from neuron_morphology.feature_extractor.feature_extractor import FeatureExtractor
from neuron_morphology.features.dimension import dimension
from neuron_morphology.features.intrinsic import num_branches, num_tips
# a utility for flattening outputs
from neuron_morphology.feature_extractor.utilities import unnest
features = [
num_outer_bifurcations,
dimension,
num_branches,
num_tips
]
# make a pipeline
results = (
FeatureExtractor()
.register_features(features)
.extract(test_data)
.results
)
unnest(results)
... or other parameters
from neuron_morphology.feature_extractor.feature_specialization import NEURITE_SPECIALIZATIONS, AxonSpec
from neuron_morphology.feature_extractor.marked_feature import specialize
print(f"marks: {AxonSpec.marks}")
print(f"kwargs: {AxonSpec.kwargs}")
axon_num_branches = specialize(num_branches, {AxonSpec}) # note that this is a set!
unnest(
FeatureExtractor()
.register_features([axon_num_branches])
.extract(test_data)
.results
)
Running on an axon is not super interesting, we can pass in a whole set of specializations, such as the built-in NEURITE_SPECIALIZATIONS to distribute a calculation across many parameter values.
NEURITE_SPECIALIZATIONS
across_neurites = [specialize(feature, NEURITE_SPECIALIZATIONS) for feature in features]
# this syntax is (almost) equivalent to the above pipeline, but we keep the extractor around
extractor = FeatureExtractor()
extractor.register_features(across_neurites)
run = extractor.extract(test_data)
across_neurite_results = run.results
unnest(across_neurite_results)
# ... by keeping the extractor we can re-use it on new data
run_two = extractor.extract(more_test_data)
unnest(run_two.results)
from neuron_morphology.feature_extractor.mark import Mark
from neuron_morphology.feature_extractor.marked_feature import marked
IsGlobal = Mark.factory("IsGlobal")
IsTrivial = Mark.factory("IsTrivial")
class DoesMath(Mark):
""" This feature involves math! Documenting your marks can be handy.
"""
@marked(IsGlobal)
@marked(IsTrivial)
def num_nodes(data: Data) -> int:
"""Count the nodes!
"""
return len(data.morphology.nodes)
num_nodes
# we can also mark an existing function
num_nodes = marked(DoesMath)(num_nodes)
num_nodes