Skip to content

Note

Click here to download the full example code

Skeletons#

This tutorial will show you how to load and save skeletons.

Skeletons are probably the most common representation of neurons and are stored as a series of connected nodes (the "skeleton"). In NAVis, skeletons are represented by the navis.TreeNeuron class.

You can either construct these manually (see bottom of this page) or use one of the built-in functions to them from one of the various file formats:

Note

NAVis has dedicated interfaces for loading skeletons from remote data sources (e.g. the MICrONS, neuromorpho, Virtual Fly Brain or Janelia hemibrain datasets). These are covered in separate tutorials.

If you have light-level microscopy data, you might also be interested in the tutorial on skeletons from light-level data.

From SWC files#

SWC is a common format for storing neuron skeletons. Thus NAVis provides functions to both read and write SWC files. To demo these, we will be using supplemental data from Bates, Schlegel et al. (Current Biology, 2020). If you want to follow along, please download Supplemental Data S1 (link). If you do, make sure to adjust the filepaths in the examples according to where you saved it to.

I extracted the archive with the supplemental data inside my downloads folder.

It contains a bunch of CSV files with meta data but the important file for us is the "skeletons_swc.zip". Now you could extract that zip archive too but NAVis can actually read directly from (and write to) zip files!

import navis
skeletons = navis.read_swc(
    'mmc2/skeletons_swc.zip',
    include_subdirs=True
)
skeletons
<class 'navis.core.neuronlist.NeuronList'> containing 480 neurons (3.7MiB)
type name id n_nodes n_connectors n_branches n_leafs cable_length soma units created_at origin file
0 navis.TreeNeuron af245389-3c04-4a9c-983e-a0cc95546942 af245389-3c04-4a9c-983e-a0cc95546942 11634 None 600 611 2.899338e+06 None 1 dimensionless 2024-10-24 11:20:45.396844 mmc2/skeletons_swc.zip af245389-3c04-4a9c-983e-a0cc95546942.swc
1 navis.TreeNeuron a6f13d47-997e-4934-8f1c-e6fd54ab7241 a6f13d47-997e-4934-8f1c-e6fd54ab7241 1670 None 24 25 6.282917e+05 None 1 dimensionless 2024-10-24 11:20:45.386339 mmc2/skeletons_swc.zip a6f13d47-997e-4934-8f1c-e6fd54ab7241.swc
... ... ... ... ... ... ... ... ... ... ... ... ... ...
478 navis.TreeNeuron a76da20e-43ff-4e0f-a455-a1cca325ffb7 a76da20e-43ff-4e0f-a455-a1cca325ffb7 14782 None 663 673 2.714858e+06 None 1 dimensionless 2024-10-24 11:20:47.091387 mmc2/skeletons_swc.zip a76da20e-43ff-4e0f-a455-a1cca325ffb7.swc
479 navis.TreeNeuron 90db0156-7aa0-42e1-a1ad-162a3c2168e9 90db0156-7aa0-42e1-a1ad-162a3c2168e9 6256 None 367 371 1.229948e+06 None 1 dimensionless 2024-10-24 11:20:47.087623 mmc2/skeletons_swc.zip 90db0156-7aa0-42e1-a1ad-162a3c2168e9.swc

Let's say you are looking at a huge collection of SWC files and you only want to sample a few of them:

Load only the first 10 skeletons

sample = navis.read_swc(
    './mmc2/skeletons_swc.zip',
    include_subdirs=True,
    limit=10
)
sample
<class 'navis.core.neuronlist.NeuronList'> containing 11 neurons (1.1MiB)
type name id n_nodes n_connectors n_branches n_leafs cable_length soma units created_at origin file
0 navis.TreeNeuron af245389-3c04-4a9c-983e-a0cc95546942 af245389-3c04-4a9c-983e-a0cc95546942 11634 None 600 611 2.899338e+06 None 1 dimensionless 2024-10-24 11:20:47.348590 mmc2/skeletons_swc.zip af245389-3c04-4a9c-983e-a0cc95546942.swc
1 navis.TreeNeuron a6f13d47-997e-4934-8f1c-e6fd54ab7241 a6f13d47-997e-4934-8f1c-e6fd54ab7241 1670 None 24 25 6.282917e+05 None 1 dimensionless 2024-10-24 11:20:47.356971 mmc2/skeletons_swc.zip a6f13d47-997e-4934-8f1c-e6fd54ab7241.swc
... ... ... ... ... ... ... ... ... ... ... ... ... ...
9 navis.TreeNeuron f2c2d64e-531b-4df8-94a9-52bdefa365b5 f2c2d64e-531b-4df8-94a9-52bdefa365b5 2694 None 112 115 8.098384e+05 None 1 dimensionless 2024-10-24 11:20:47.438263 mmc2/skeletons_swc.zip f2c2d64e-531b-4df8-94a9-52bdefa365b5.swc
10 navis.TreeNeuron 9f0f8e35-dac0-46d5-9947-de46871fe4ea 9f0f8e35-dac0-46d5-9947-de46871fe4ea 0 None 0 0 0.000000e+00 None 1 dimensionless 2024-10-24 11:20:47.444403 mmc2/skeletons_swc.zip 9f0f8e35-dac0-46d5-9947-de46871fe4ea.swc

We can also point navis.read_swc() at single files instead of folders or zip archives:

For this I extraced the skeletons_swc.zip archive

s = navis.read_swc('./mmc2/swc/CENT/11519759.swc')
s
type navis.TreeNeuron
name 11519759
n_nodes 14782
n_connectors None
n_branches 663
n_leafs 673
cable_length 2714858.25
soma None
units 1 dimensionless
created_at 2024-10-24 11:20:47.476533
origin mmc2/swc/CENT/11519759.swc
file 11519759.swc

You can even use URLs or FTP servers directly:

# From URL:
s = navis.read_swc('https://v2.virtualflybrain.org/data/VFB/i/jrch/jup2/VFB_00101567/volume.swc')
# From an FTP folder:
nl = navis.read_swc('ftp://download.brainlib.org:8811/biccn/zeng/pseq/morph/200526/', limit=3)


# !!! tip
#     [`read_swc`][navis.read_swc] is super flexible and can handle a variety of inputs (file names, folders, archives, URLs, etc.).
#     Importantly, it also let you customize which/how neurons are loaded. For example:
#      - the `limit` parameter can also be used to load only files matching a given pattern
#      - the `fmt` parameter lets you specify how to parse filenames into neuron names and ids
#     Many of the other `navis.read_*` functions share these features!

To SWC files#

Now let's say you have skeletons and you want to save them to disk. Easy!

# Write a single neuron:
navis.write_swc(s, './mmc2/my_neuron.swc')
# Write a whole list of skeletons to a folder and use the neurons' `name` property as filename:
navis.write_swc(sample, './mmc2/{neuron.name}.swc')
# Write directly to a zip file:
navis.write_swc(sample, './mmc2/skeletons.zip')
# Write directly to a zip file and use the neuron name as filename:
navis.write_swc(sample, './mmc2/{neuron.name}.swc@skeletons.zip')

See navis.write_swc for further details!

From NMX files#

NMX is a xml-based format used e.g. by pyKNOSSOS to store skeletons plus meta data. NAVis supports reading (but not writing) this format. If you want to follow along download this dataset by Wanner et al. (2016). Just like the SWCs, I extracted the archive to my downloads folder:

Read a single file

s = navis.read_nmx('./WannerAA201605_SkeletonsGlomeruli/Neuron_id0001.nmx')
s
type navis.TreeNeuron
name NML
id Neuron_id0001
n_nodes 3369
n_connectors None
n_branches 64
n_leafs 69
cable_length 151639.15625
soma None
units 1 dimensionless

Read all files in folder

nl = navis.read_nmx('./WannerAA201605_SkeletonsGlomeruli/')
nl
<class 'navis.core.neuronlist.NeuronList'> containing 1022 neurons (142.1MiB)
type name id n_nodes n_connectors n_branches n_leafs cable_length soma units
0 navis.TreeNeuron NML Neuron_id0877 5998 None 290 311 575677.250000 None 1 dimensionless
1 navis.TreeNeuron NML Neuron_id0576 5788 None 145 164 318812.000000 None 1 dimensionless
... ... ... ... ... ... ... ... ... ... ...
1020 navis.TreeNeuron NML Neuron_id0349 5154 None 39 44 103979.039062 None 1 dimensionless
1021 navis.TreeNeuron NML Neuron_id0781 5720 None 511 555 540873.125000 None 1 dimensionless
navis.plot2d(nl[:10], method='2d', radius=False)

tutorial io 00 skeletons

Out:

Plot neurons:   0%|          | 0/10 [00:00<?, ?it/s]

Plot neurons:  70%|#######   | 7/10 [00:00<00:00, 67.39it/s]


(<Figure size 640x480 with 1 Axes>, <Axes: xlabel='x', ylabel='y'>)

Note

If you encounter an error message while reading: NMX files don't always contain skeletons. If NAVis comes across one that can't be turned into a navis.TreeNeuron, it will skip the file and produce a warning.

From Neuroglancer#

Among other formats, neuroglancer supports a "precomputed" format for skeletons (see specs here. This binary format is more compact than uncompressed SWC files but is not used outside of neuroglancer as far as I know. That said: NAVis lets you read and write skeletons from/to precomputed format using navis.read_precomputed and navis.write_precomputed. Note that these functions work on both precomputed skeletons and meshes.

Manual construction#

What if you have some obscure data format for which NAVis does not have a read function? The data underlying a navis.TreeNeuron is a simple SWC table - so as long as you can produce that from your data, you can create your own skeletons.

Here's a quick & dirty example:

import pandas as pd

# Create a mock SWC table for a 2-node skeleton
swc = pd.DataFrame()
swc['node_id'] = [0, 1]
swc['parent_id'] = [-1, 0]   # negative indices indicate roots
swc['x'] = [0, 1]
swc['y'] = [0, 1]
swc['z'] = [0, 1]
swc['radius'] = 0

swc
node_id parent_id x y z radius
0 0 -1 0 0 0 0
1 1 0 1 1 1 0

This SWC can now be used to construct a TreeNeuron:

s = navis.TreeNeuron(swc, name='my_neuron', units='microns')
s
type navis.TreeNeuron
name my_neuron
n_nodes 2
n_connectors None
n_branches 0
n_leafs 1
cable_length 1.732051
soma None
units 1 micrometer

There are a few other ways to construct a navis.TreeNeuron (e.g. using a graph) - see the docstring for details.

Also note that all NAVis neurons can be stored to disk using pickle - see the pickling tutorial.

Hopefully the above has given you some entry points on how to load your data. See also the I/O API reference.

Please also keep in mind that you can also convert one neuron type into another - for example by skeletonizing MeshNeurons (see also the API reference on neuron conversion).

Total running time of the script: ( 1 minutes 15.090 seconds)

Download Python source code: tutorial_io_00_skeletons.py

Download Jupyter notebook: tutorial_io_00_skeletons.ipynb

Gallery generated by mkdocs-gallery