Documentation

Visualisation

We show you how to visualise the data you are working with

27 Dec 2021
!pip install vfb-connect --upgrade
# Import libs and initialise API objects
from vfb_connect.cross_server_tools import VfbConnect
import pandas as pd

vc = VfbConnect()  

import pymaid
import navis

# Needed because deepnote doesn't support fancy progress bars yet
navis.set_pbars(jupyter=False) 
pymaid.set_pbars(jupyter=False)

# Connect to the VFB CATMAID server hosting the FAFB data
rm = pymaid.connect_catmaid(server="https://fafb.catmaid.virtualflybrain.org/",  
                            api_token=None, max_threads=10)

# Test call to see if connection works 
print(f'Server is running CATMAID version {rm.catmaid_version}')
WARNING: Could not load OpenGL library.
INFO  : Global CATMAID instance set. Caching is ON. (pymaid)
Server is running CATMAID version 2020.02.15-905-g93a969b37

Plotting

navis lets you plot neurons in 2d using matplotlib (nice for figures), and in 3d using either plotly when in a notebook environment like Deepnote or using a vispy-based 3D viewer when using a Python terminal. The vispy solution won’t work in Deepnote so we will focus on matplotlib’s 2d and plotly for 3d.

# We'll use a FAFB neuron, retrieved using navis as an example
n = pymaid.get_neurons(16) # retrieves a CatMaid neuron object with skeleton id = 16 (See the Mapping notebook for how to find )
n
INFO  : Cached data used. Use `pymaid.clear_cache()` to clear. (pymaid)
INFO  : Cached data used. Use `pymaid.clear_cache()` to clear. (pymaid)

typeCatmaidNeuron
nameUniglomerular mALT VA6 adPN 017 DB
id16
n_nodes16840
n_connectors2158
n_branches1172
n_leafs1230
cable_length4003103.232861
soma[2941309]
units1 nanometer
# We can plot this in 2D
navis.plot2d(n)

navis.plot2d(m)
(<Figure size 432x432 with 1 Axes>, <Axes3DSubplot:>)

png

# Or 3D
navis.plot3d(n)

Navigation:

  • left click and drag to rotate (select “Orbital rotation” above the legend to make your life easier)
  • mousewheel to zoom
  • middle-mouse + drag to translate
  • click legend items (single or double) to hide/unhide

Customization:

The above plots are very basic examples but there are a ton of ways to tweak things to your liking. For a full list of parameters check out the docs for plot2d and plot3d. (Hint - you can view documentation by floating over a method name in Deepnote)

Let’s for example change the colors. In general, colors can be:

a string - e.g. “red” or just “r” an rgb/rgba tuple - e.g. (1, 0, 0) for red

navis.plot3d(n, color='red')

Excercise

Float over the

# CATMAID neuron objects include connectors (synapses)  here pre-(red) and postsynapses (blue).
navis.plot3d(n, width=1000, connectors=True, color='k') #

Now let’s try an example with multiple neurons

# Pulling (annotations on) neurons from a single dataset on CATMAID

bates = pymaid.find_neurons(annotations='Paper: Bates and Schlegel et al 2020') 
# Viewing first 10 neurons:
bates[0:10]
INFO  : Found 583 neurons matching the search parameters (pymaid)

typenameskeleton_idn_nodesn_connectorsn_branchesn_leafscable_lengthsomaunits
0CatmaidNeuronUniglomerular mALT DA1 lPN 57316 2863105 ML2863104NANANANANANA1 nanometer
1CatmaidNeuronUniglomerular mALT DA3 adPN 57350 HG57349NANANANANANA1 nanometer
.................................
8CatmaidNeuronMultiglomerular mlALT vPN DP1m+DM3+DP1l+1 LTS ...3813399NANANANANANA1 nanometer
9CatmaidNeuronUniglomerular lALT VP1m l2PN 65701 AJ ECM11524119NANANANANANA1 nanometer
# Plotting multiple neurons, we get a default multi-color pallete

bates[0:10].plot3d(hover_name=True)

What if we want to use color to group neurons in some way?

The following example illustrates colouring by lineage, where lineage is derived from standardised neuron names on FAFB CATMAID

da1

typenameskeleton_idn_nodesn_connectorsn_branchesn_leafscable_lengthsomaunits
0CatmaidNeuronUniglomerular mALT DA1 lPN 57316 2863105 ML286310467744702802921.522065e+06[3245741]1 nanometer
1CatmaidNeuronUniglomerular mALT DA1 lPN 57354 GA5735369853702252361.539364e+06[3254736]1 nanometer
.................................
15CatmaidNeuronUniglomerular mALT DA1 lPN 57312 LK5731155434632112191.364103e+06[3059181]1 nanometer
16CatmaidNeuronUniglomerular mALT DA1 lPN 57324 LK JSL5732362234812562681.483462e+06[3251355]1 nanometer
# On CATMAID, we need to know something about the structure of names and parse them to get types:

import re 
prog = re.compile("Uniglomerular(.*?) DA1 ") 

# Match all neuron names in `bates` against that pattern
is_da1 = list(map(lambda x: prog.match(x) != None, bates.name))

# Subset list of neurons
da1 = bates[is_da1]
da1.head()

typenameskeleton_idn_nodesn_connectorsn_branchesn_leafscable_lengthsomaunits
0CatmaidNeuronUniglomerular mALT DA1 lPN 57316 2863105 ML286310467744702802921522064.513255[3245741]1 nanometer
1CatmaidNeuronUniglomerular mALT DA1 lPN 57354 GA5735369853702252361539364.300882[3254736]1 nanometer
2CatmaidNeuronUniglomerular mALT DA1 lPN 57382 ML57381NANANANANANA1 nanometer
3CatmaidNeuronUniglomerular mlALT DA1 vPN mlALTed Milk 23348...2334841NANANANANANA1 nanometer
4CatmaidNeuronUniglomerular mALT DA1 lPN PN021 2345090 DB RJVR2345089NANANANANANA1 nanometer
# Add lineage attribute to all da1 neurons based on regex against name
for n in da1:
    # Split name into components and keep only the tract
    n.lineage = n.name.split(' ')[3]    

import seaborn as sns
import numpy as np 

# Get all unique lineages (we expect only two)
lineages = np.unique(da1.lineage) 

# Generate a color per lineage
lin_cmap = dict(zip(lineages, sns.color_palette('muted', len(lineages))))

# Make a dictionary mapping skid to colour appropriate to lineage
lineage_map = dict(zip(da1.id, da1.lineage)) 
neuron_cmap = {i: lin_cmap[l] for i, l in lineage_map.items()}

navis.plot3d(da1, color=neuron_cmap, legend_group=lineage_map, hover_name=True, width=1000)

We can do the same thing using VFB, looking up the relevant terms on the web site and then using these to categorise CATMAID neurons

# With VFB, we can query by type

from vfb_connect.cross_server_tools import gen_short_form # TODO - make this arg on oc.get_instances

def vfb_type_2_skids(vfb_type):
    # Get IDs (short_forms) for instances of type
    da1_from_vfb = map(gen_short_form, vc.oc.get_instances(vfb_type, query_by_label=True))
    # Find which neurons are in catmaid_fafb and return 
    da1_skid_lookup = vc.neo_query_wrapper.vfb_id_2_xrefs(da1_from_vfb, db='catmaid_fafb', reverse_return=True)
    # Convert skids to ints 
    da1_skids = da1_skid_lookup.keys()
    return list(da1_skids)

da1_fafb = vfb_type_2_skids("'adult antennal lobe projection neuron DA1'")
Running query: FBbt:00048096
Query URL: http://owl.virtualflybrain.org/kbs/vfb/instances?object=FBbt%3A00048096&prefixes=%7B%22FBbt%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FFBbt_%22%2C+%22RO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FRO_%22%2C+%22BFO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FBFO_%22%7D&direct=False
Query results: 31
/root/venv/lib/python3.7/site-packages/vfb_connect/neo/query_wrapper.py:279: UserWarning:

The following IDs do not match DB &/or id_type constraints: {'VFB_0010121x', 'VFB_00101203', 'VFB_0010122z', 'VFB_00101202', 'VFB_jrchjtdd', 'VFB_jrchjtdg', 'VFB_00101201', 'VFB_0010122p', 'VFB_0010124l', 'VFB_00101205', 'VFB_jrchjtde', 'VFB_0010123b', 'VFB_jrchjtda', 'VFB_0010122y', 'VFB_jrchjtdc', 'VFB_00101204', 'VFB_00101199', 'VFB_0010124e', 'VFB_0010122k', 'VFB_00104624', 'VFB_jrchjtdh', 'VFB_jrchjtdb', 'VFB_00102297', 'VFB_00101200', 'VFB_jrchjtdf', 'VFB_00102763', 'VFB_0010126e', 'VFB_00102294', 'VFB_00104629', 'VFB_0010122m', 'VFB_00103943'}
# Inspect subclasses:
pd.DataFrame.from_records(vc.get_subclasses("'adult antennal lobe projection neuron DA1'", summary=True))
Running query: FBbt:00048096
Query URL: http://owl.virtualflybrain.org/kbs/vfb/subclasses?object=FBbt%3A00048096&prefixes=%7B%22FBbt%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FFBbt_%22%2C+%22RO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FRO_%22%2C+%22BFO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FBFO_%22%7D&direct=False
Query results: 2

labelsymbolidtagsparents_labelparents_id
0adult antennal lobe projection neuron DA1 lPNDA1_lPNFBbt_00067363Entity|Neuron|Adult|Anatomy|Nervous_system|Cel...adult lateral horn input neuron|adult mushroom...FBbt_00049427|FBbt_00047957|FBbt_00067350|FBbt...
1adult antennal lobe projection neuron DA1 vPNDA1_vPNFBbt_00067372Entity|GABAergic|Adult|Anatomy|Nervous_system|...mediolateral antennal lobe tract projection ne...FBbt_00007445|FBbt_00007228|FBbt_00048096
# Get skids for DA1_lPNs and DA1_vPNs
da1_l_fafb = vfb_type_2_skids("'DA1_lPN'")
da1_v_fafb = vfb_type_2_skids("'DA1_vPN'")

is_da1 = list(map(lambda x: x in da1_fafb, bates.skeleton_id))
da1 = bates[is_da1]
Running query: FBbt:00067363
Query URL: http://owl.virtualflybrain.org/kbs/vfb/instances?object=FBbt%3A00067363&prefixes=%7B%22FBbt%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FFBbt_%22%2C+%22RO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FRO_%22%2C+%22BFO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FBFO_%22%7D&direct=False
Query results: 22
/root/venv/lib/python3.7/site-packages/vfb_connect/neo/query_wrapper.py:279: UserWarning:

The following IDs do not match DB &/or id_type constraints: {'VFB_00101203', 'VFB_00101202', 'VFB_0010122z', 'VFB_jrchjtdd', 'VFB_jrchjtdg', 'VFB_00101201', 'VFB_0010122p', 'VFB_0010124l', 'VFB_00101205', 'VFB_jrchjtde', 'VFB_0010123b', 'VFB_jrchjtda', 'VFB_0010122y', 'VFB_jrchjtdc', 'VFB_00101204', 'VFB_00101199', 'VFB_0010124e', 'VFB_0010122k', 'VFB_jrchjtdb', 'VFB_00101200', 'VFB_jrchjtdf', 'VFB_0010126e'}

Running query: FBbt:00067372
Query URL: http://owl.virtualflybrain.org/kbs/vfb/instances?object=FBbt%3A00067372&prefixes=%7B%22FBbt%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FFBbt_%22%2C+%22RO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FRO_%22%2C+%22BFO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FBFO_%22%7D&direct=False
Query results: 9
/root/venv/lib/python3.7/site-packages/vfb_connect/neo/query_wrapper.py:279: UserWarning:

The following IDs do not match DB &/or id_type constraints: {'VFB_00103943', 'VFB_jrchjtdh', 'VFB_0010121x', 'VFB_00102763', 'VFB_00104624', 'VFB_00102294', 'VFB_00104629', 'VFB_0010122m', 'VFB_00102297'}
# Generate a palette 
palette = sns.color_palette('muted', 2)
# Make a dictionary 
lin_cmap = { 'lPN': palette[0], 'vPN': palette[1]}
# Make a dictionary with key = skid & value = color by lineage
lineage_map = {n: 'lPN' for n in da1_l_fafb}
lineage_map.update({n: 'vPN' for n in da1_v_fafb})

neuron_cmap = {n: lin_cmap[l] for n, l in lineage_map.items()}

navis.plot3d(da1, color=neuron_cmap, hover_name=True, legend_group=lineage_map, width=1000)

Using VFB templates and data to plot neurons from multiple sources in a single template space.

VFB allows us to pull neurons from multiple sources and display them in a single template space

You can browse the various templates available on the VFB site, or get a summary:

pd.DataFrame.from_records(vc.neo_query_wrapper.get_templates(summary=True))

labelsymbolidtagsparents_labelparents_iddata_sourceaccessiontemplatesdatasetlicense
0JRC2018UnisexVFB_00101567Entity|has_image|Adult|Anatomy|Nervous_system|...adult brainFBbt_00003624JRC2018https://creativecommons.org/licenses/by-nc-sa/...
1adult brain template JFRC2VFB_00017894Entity|VFB|Adult|Anatomy|Nervous_system|Indivi...adult brainFBbt_00003624Jenett2012https://creativecommons.org/licenses/by-nc-sa/...
2adult VNS template - Court2018VFB_00100000Entity|has_image|Adult|Anatomy|Ganglion|Indivi...adult ventral nerve cordFBbt_00004052Court2017https://creativecommons.org/licenses/by-sa/4.0...
3adult brain template Ito2014VFB_00030786Entity|VFB|Adult|Anatomy|Nervous_system|Indivi...adult brainFBbt_00003624BrainName_Ito_half_brainhttps://creativecommons.org/licenses/by-sa/4.0...
4JRC_FlyEM_HemibrainVFB_00101384Entity|has_image|Adult|Anatomy|Nervous_system|...adult brainFBbt_00003624Xu2020roihttps://creativecommons.org/licenses/by/4.0/le...
5JRC2018UnisexVNCVFB_00200000Entity|has_image|Adult|Anatomy|Ganglion|Indivi...adult ventral nerve cordFBbt_00004052JRC2018https://creativecommons.org/licenses/by-nc-sa/...
6L3 CNS template - Wood2018VFB_00049000Entity|has_image|Anatomy|Nervous_system|Indivi...embryonic/larval central nervous systemFBbt_00001919Truman2016https://creativecommons.org/licenses/by-sa/4.0...
7L1 larval CNS ssTEM - Cardona/JaneliaVFB_00050000Entity|has_image|Anatomy|Nervous_system|Indivi...embryonic/larval central nervous systemFBbt_00001919catmaid_l1emOhyama2015|Schlegel2016https://creativecommons.org/licenses/by-sa/4.0...
DA1_manifest = vc.get_images_by_type("'adult antennal lobe projection neuron DA1'", template = 'JRC2018Unisex', image_folder = 'DA1', stomp=True)
Running query: FBbt:00048096
Query URL: http://owl.virtualflybrain.org/kbs/vfb/instances?object=FBbt%3A00048096&prefixes=%7B%22FBbt%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FFBbt_%22%2C+%22RO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FRO_%22%2C+%22BFO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FBFO_%22%7D&direct=False
Query results: 31
/root/venv/lib/python3.7/site-packages/vfb_connect/neo/query_wrapper.py:220: UserWarning:

No 'swc' file found for 'ALv1_P02(DA1)_0_2018U'.
DA1_manifest[0:3]

labelsymbolidtagsparents_labelparents_iddata_sourceaccessiontemplatesdatasetlicensefilename
0Uniglomerular mALT DA1 lPN#L3 (FAFB:2345089)VFB_0010122pEntity|has_image|Adult|Anatomy|has_neuron_conn...adult antennal lobe projection neuron DA1 lPNFBbt_00067363catmaid_fafb2345089JRC2018UnisexBatesSchlegel2020https://creativecommons.org/licenses/by-sa/4.0...Uniglomerular_mALT_DA1_lPN_L3__FAFB_2345089_.swc
1Uniglomerular mALT DA1 lPN#R3 (FAFB:61221)VFB_00101204Entity|has_image|Adult|Anatomy|has_neuron_conn...adult antennal lobe projection neuron DA1 lPNFBbt_00067363catmaid_fafb61221adult brain template JFRC2|JRC2018UnisexZheng2018https://creativecommons.org/licenses/by-sa/4.0...Uniglomerular_mALT_DA1_lPN_R3__FAFB_61221_.swc
2Uniglomerular mALT DA1 lPN#L1 (FAFB:4207871)VFB_0010126eEntity|has_image|Adult|Anatomy|has_neuron_conn...adult antennal lobe projection neuron DA1 lPNFBbt_00067363catmaid_fafb4207871JRC2018UnisexBatesSchlegel2020https://creativecommons.org/licenses/by-sa/4.0...Uniglomerular_mALT_DA1_lPN_L1__FAFB_4207871_.swc

We can then plot the neurons, coloring by data_source

# Read skeletons from file
nl = navis.read_swc('DA1') 

# The neuron names correspond to the filenames
# To make it easier, we will manually add IDs from the manifest
ids = dict(zip(DA1_manifest.filename.map(lambda x: x.replace('.swc', '')).values,
               DA1_manifest.accession.values)) 
for n in nl:
    n.id = ids[n.name]

# Add data source 
ds = DA1_manifest.set_index('accession').data_source.to_dict()
for n in nl:
    n.source = ds[n.id]
source_cmap = dict(zip(np.unique(nl.source),
                       sns.color_palette('muted', len(np.unique(nl.source)))))

source_map = dict(zip(nl.id, nl.source))
neuron_cmap = {n.id: source_cmap[n.source] for n in nl}

navis.plot3d(nl, color=neuron_cmap, hover_name=True, legend_group=source_map, width=1000)

Adding volumes

VFB has regions of interest defined for every template. These can be browsed on our template ROI browser:

png

or the results of queries available from each template. The ROIs for JRC2018Unisex come from Janelia (the work of Kazonori Shinomiya) and align with domains on the Hemibrain following standard cross-registration.

# Hackish!
jrc2018u = trimesh.load_remote('https://github.com/schlegelp/navis-flybrains/raw/main/flybrains/meshes/JRC2018U.ply')
jrc2018u = navis.Volume(jrc2018u, color=(.85, .85, .85, .3), name='JRC2018U')
jrc2018u
<navis.Volume(name=JRC2018U, color=(0.85, 0.85, 0.85, 0.3), vertices.shape=(11943, 3), faces.shape=(24558, 3))>
# Get an image (obj volume) of the mushroom body calyx on JRC2018Unisex: 

SMP = vc.neo_query_wrapper.get_images(['VFB_00102170'], template = 'JRC2018Unisex', image_folder='SMP', image_type='obj', stomp=True) # TODO 
SMP

labelsymbolidtagsparents_labelparents_iddata_sourceaccessiontemplatesdatasetlicensefilename
0SMP on JRC2018Unisex adult brainVFB_00102170Entity|has_image|Adult|Anatomy|Nervous_system|...superior medial protocerebrumFBbt_00007055JRC2018UnisexJRC2018https://creativecommons.org/licenses/by-nc-sa/...SMP_on_JRC2018Unisex_adult_brain.obj
# Get an image (obj volume) of the mushroom body calyx on JRC2018Unisex: 

MB = vc.get_images_by_type("'VFB_00101567'", template = 'JRC2018Unisex', image_folder='MB', image_type='obj', stomp=True) # TODO 
MB
Running query: FBbt:00003685
Query URL: http://owl.virtualflybrain.org/kbs/vfb/instances?object=FBbt%3A00003685&prefixes=%7B%22FBbt%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FFBbt_%22%2C+%22RO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FRO_%22%2C+%22BFO%22%3A+%22http%3A%2F%2Fpurl.obolibrary.org%2Fobo%2FBFO_%22%7D&direct=False
Query results: 6

labelsymbolidtagsparents_labelparents_iddata_sourceaccessiontemplatesdatasetlicensefilename
0CA on JRC2018Unisex adult brainVFB_00102114Entity|has_image|Adult|Anatomy|Nervous_system|...calyx of adult mushroom bodyFBbt_00007385JRC2018UnisexJRC2018https://creativecommons.org/licenses/by-nc-sa/...CA_on_JRC2018Unisex_adult_brain.obj
# Plot this along with the neurons in the previous example
import trimesh

# TBA # discovery step

test = trimesh.load('SMP/SMP_on_JRC2018Unisex_adult_brain.obj')
mesh = navis.Volume(test)
mesh.color = (230, 230, 230, .2)
mesh.name = "SMP on JRC2018Unisex adult brain"
navis.plot3d([nl, mesh], color=neuron_cmap, hover_name=True, legend_group=source_map)
# Plot this along with the neurons in the previous example
import trimesh

# TBA # discovery step

#test = trimesh.load('MB/CA_on_JRC2018Unisex_adult_brain.obj')
#mesh = navis.Volume(test)
#mesh.color = (230, 230, 230, .2)
#mesh.name = "ME on JRC2018Unisex adult brain"
navis.plot3d([nl, jrc2018u], color=neuron_cmap, hover_name=True, legend_group=source_map)

Excercise

Choose some neurons to display and render by classification. Write some code based on the previous examples to achieve this.