Morphological Analyses
**********************
This section should give you an impression of how to access and compute morphological properties of neurons. You will note that most of this uses `navis `_ functions. ``CatmaidNeuron/Lists`` are fully compatible with ``navis`` and you should most definitely check out tutorials on its docs.
Basic properties
================
Many basic parameters are readily accessible through attributes of :class:`~pymaid.CatmaidNeuron` or :class:`~pymaid.CatmaidNeuronList`:
.. code:: ipython3
import pymaid
import matplotlib.pyplot as plt
rm = pymaid.CatmaidInstance('server_url', 'api_token', 'http_user', 'http_password')
nl = pymaid.get_neurons('annotation:glomerulus DA1 right excitatory')
# Access single attribute: e.g. cable lengths [um]
nl.cable_length
.. parsed-literal::
INFO : Global CATMAID instance set. (pymaid.fetch)
INFO : Looking for Annotation(s): glomerulus DA1 right excitatory (pymaid.fetch)
INFO : Found 8 skeletons with matching annotation(s) (pymaid.fetch)
.. parsed-literal::
array([1591.51982146, 1182.10245803, 1035.09925403, 1113.15667872,
1215.92059396, 1182.6479815 , 1059.72905251, 1109.88615456])
.. code:: ipython3
# .. or get a full summary as pandas DataFrame
df = nl.summary()
df.head()
.. raw:: html
|
neuron_name |
skeleton_id |
n_nodes |
n_connectors |
n_branch_nodes |
n_end_nodes |
open_ends |
cable_length |
review_status |
soma |
| 0 |
PN glomerulus DA1 27296 BH |
27295 |
9969 |
463 |
211 |
218 |
58 |
1590.676589 |
NA |
True |
| 1 |
PN glomerulus DA1 57312 LK |
57311 |
4874 |
421 |
156 |
163 |
105 |
1180.597489 |
NA |
True |
| 2 |
PN glomerulus DA1 57324 LK JSL |
57323 |
4585 |
434 |
120 |
127 |
59 |
1035.076857 |
NA |
True |
| 3 |
PN glomerulus DA1 57354 GA |
57353 |
4895 |
324 |
90 |
95 |
52 |
1113.156676 |
NA |
True |
| 4 |
PN glomerulus DA1 57382 ML |
57381 |
7727 |
357 |
153 |
162 |
71 |
1215.920594 |
NA |
True |
Rerooting, resampling, simplifying
==================================
``navis`` lets you perform (virtual) surgery on neurons. Many of the base functions are also accessible directly via :class:`~pymaid.CatmaidNeuron` and :class:`~pymaid.CatmaidNeuronList` methods. E.g. :func:`pymaid.CatmaidNeuronList.resample` is simply calling :func:`navis:navis.resample_neuron`.
Examples continue from above code.
.. code:: ipython3
# Reroot a single neuron to its soma
nl[0].soma
.. parsed-literal::
3005291
.. code:: ipython3
# .soma returns the treenode ID of the soma (if existing) and can be used to reroot
nl[0].reroot(nl[0].soma, inplace=True)
.. code:: ipython3
# You can also perform this operation on the entire CatmaidNeuronList
nl.reroot(nl.soma, inplace=True)
Above code is equivalent to:
.. code:: ipython3
import navis
navis.reroot_skeleton(nl, nl.soma, inplace=True)
We will be using the shortcut (e.g. ``nl.reroot``) and the actual function (e.g. ``navis.reroot_skeleton``) interchangeably throughout the examples. This is not meant to be confusing but to be illustrative.
If you work with large lists you may want to down-/resample before e.g. plotting.
.. code:: ipython3
# Downsample by "skipping" N nodes (here: 10)
nl_downsampled = navis.downsample(nl, 10, inplace=False)
# More elaborate: resample to given resolution in nanometers (here: 1000nm = 1um)
nl_resampled = navis.resample_skeleton(nl, 1000, inplace=False)
.. code:: ipython3
import matplotlib.pyplot as plt
# Plot an original neuron first
fig, ax = navis.plot2d(nl[0], color='red')
# Shift the downsampled and resampled versions slightly and plot
n_ds = nl_downsampled[0].copy()
n_rs = nl_resampled[0].copy()
n_ds.nodes.x += 10000
n_rs.nodes.x += 20000
fig, ax = n_ds.plot2d(color='blue', ax=ax)
fig, ax = n_rs.plot2d(color='green', ax=ax)
plt.show()
.. image:: morph_analysis_files/morph_analysis_11_0.png
Looking closely, you will find that the downsampled (blue) and resampled (green) neurons are smoother.
.. important::
Note how we used ``inplace`` parameter when using the neuronlist's downsampling method?
This parameter works like in pandas: if ``True`` will perform the action on the neuronlist, if
``False`` will operate on and return a copy and leave the original neuronlist unchanged.
Cutting, pruning, pasting
=========================
Examples continue from above code.
.. code:: ipython3
# Cut a neuron in two using either a node ID or (in this case) a node tag
distal, proximal = navis.cut_skeleton(nl[0], cut_node='SCHLEGEL_LH')
# Plot neuron fragments
fig, ax = navis.plot2d(distal, color='red', method='2d', connectors=False)
fig, ax = navis.plot2d(proximal, color='blue', method='2d', connectors=False, ax=ax)
# Annotate cut point
cut_coords = distal.nodes.set_index('node_id').loc[ distal.root, ['x','y'] ].values[0]
ax.annotate('cut point', xy=(cut_coords[0], -cut_coords[1]),
xytext=(cut_coords[0], -cut_coords[1]-20000), va='center', ha='center',
arrowprops=dict(facecolor='black', shrink=0.01, width=1),
)
plt.show()
.. image:: morph_analysis_files/morph_analysis_14_0.png
Instead of cutting a neuron in two, we can also just prune bits off a neuron objects:
.. code:: ipython3
n = nl[0].prune_distal_to('SCHLEGEL_LH', inplace=False)
# Plot original neuron in black
fig, ax = nl[0].plot2d(color='black', method='2d', connectors=False, linestyle=(0, (5, 10)))
# Plot pruned neuron in red
fig, ax = n.plot2d(color='red', method='2d', connectors=False, ax=ax)
# Annotate cut point
ax.annotate('cut point', xy=(cut_coords[0], -cut_coords[1]),
xytext=(cut_coords[0], -cut_coords[1]-20000), va='center', ha='center',
arrowprops=dict(facecolor='black', shrink=0.01, width=1),
)
plt.show()
.. image:: morph_analysis_files/morph_analysis_16_0.png
.. code:: ipython3
# To undo, simply reload the neuron from server
nl[0].reload()
.. code:: ipython3
# These operations can also be performed on a collection of neurons
n = nl[:5].prune_distal_to('SCHLEGEL_LH', inplace=False)
# Plot original neurons in black
fig, ax = nl[:5].plot2d(color='black', method='2d', connectors=False, linestyle=(0, (5, 10)))
# Plot pruned neurons in red
fig, ax = n.plot2d(color='red', method='2d', connectors=False, ax=ax)
# Annotate cut point
ax.annotate('cut point', xy=(cut_coords[0], -cut_coords[1]),
xytext=(cut_coords[0], -cut_coords[1]-20000), va='center', ha='center',
arrowprops=dict(facecolor='black', shrink=0.01, width=1),
)
plt.show()
.. image:: morph_analysis_files/morph_analysis_18_0.png
.. code:: ipython3
# Again, let's undo
nl.reload()
nl.reroot(nl.soma)
.. code:: ipython3
# Something more sophisticated: pruning by strahler index
n = nl[:5].prune_by_strahler( to_prune = [1,2,3], inplace=False )
# Plot original neurons in black
fig, ax = nl[:5].plot2d(color='black', method='2d', connectors=False)
# Plot pruned neurons in red
fig, ax = n.plot2d(color='red', method='2d', connectors=False, ax=ax, linewidth=1.5)
# Annotate cut point
ax.annotate('cut point', xy=(cut_coords[0], -cut_coords[1]),
xytext=(cut_coords[0], -cut_coords[1]-20000), va='center', ha='center',
arrowprops=dict(facecolor='black', shrink=0.01, width=1),
)
plt.show()
.. image:: morph_analysis_files/morph_analysis_20_0.png
We can also intersect neurons with CATMAID volumes:
.. code:: ipython3
# Again, let's undo
nl.reload()
.. code:: ipython3
# Get a volume
lh = pymaid.get_volume('LH_R')
# Prune by volume
nl_lh = navis.in_volume(nl, lh, inplace=False)
.. code:: ipython3
# Set color of volume
lh['color'] = (250,250,250,.2)
# Plot neurons that have some cable left and the volume
fig, ax = navis.plot2d([nl_lh[nl_lh.cable_length > 10], lh],
method='3d',
connectors=False,
linewidth=2)
ax.dist=6
plt.show()
.. image:: morph_analysis_files/morph_analysis_24_0.png
And now go check out `navis `_!