NBLAST is a method to quantify morphological similarity. Here we show you how to use it to programatically classify neurons by morphology.


NBLAST (Costa et al., 2016) is a method to quantify morphological similarity. It works on “dotprops” which represent neurons as tangent vectors. For each tangent vector in the query neuron, NBLAST finds the closest tangent vector in the target neuron and calculates a score from the distance between and the dotproduct of the two vectors. The final NBLAST score is the sum over all query-target vector pairs. Typically, this score is normalized to a self-self comparison (i.e. a perfect match would be 1).


VFB computes NBLAST scores for all (?) neurons in its database. So if all you want is a list of similar neurons, it’s fastest (and easiest) to get those directly from VFB.

# Import libs and initialise API objects
from vfb_connect.cross_server_tools import VfbConnect
import navis.interfaces.neuprint as neu

import pandas as pd
import navis


vc = VfbConnect()
client = neu.Client('https://neuprint.janelia.org', dataset='hemibrain:v1.1')

First let’s write a little function to grab VFB neurons and turn them into navis neurons. This is modified from vc.neo_query_wrapper.get_images.

import requests
from tqdm import tqdm

def get_vfb_neurons(vfb_ids, template='JRC2018Unisex'):
    """Load neurons from VFB as navis.TreeNeurons."""
    vfb_ids = list(navis.utils.make_iterable(vfb_ids))
    inds = vc.neo_query_wrapper.get_anatomical_individual_TermInfo(short_forms=vfb_ids)
    nl = []
    # Note: queries should be parallelized in the future 
    # -> for pymaid I use request-futures which works really well
    for i in tqdm(inds, desc='Loading VFB neurons', leave=False):        
        if not ('has_image' in i['term']['core']['types']):
        label = i['term']['core']['label']
        image_matches = [x['image'] for x in i['channel_image']]
        if not image_matches:
        for imv in image_matches:
            if imv['template_anatomy']['label'] == template:
                r = requests.get(imv['image_folder'] + '/volume.swc')
                ### Slightly dodgy warning - could mask network errors
                if not r.ok:
                    warnings.warn("No '%s' file found for '%s'." % (image_type, label))

                # `id` should ideally be unique but that's not enforced
                n = navis.TreeNeuron(r.text, name=label, id=i['term']['core']['short_form'])   

                # This registers attributes that you want to show in the summary
                # alternatively we could have a generic attribute like so:
                # n.template = template
                n._register_attr("template", template, temporary=False)

                # I assume all available templates are in microns?
                # @Robbie -do we have this metadata on templates?  If not, we should add ASAP.
                n.units = '1 micron'

    return navis.NeuronList(nl)
# Search for similar neurons using the VFB ID of an ellipsoid body neuron in FAFB
# We got that ID from a search on the VFB website
similar_to_EPG6L1 = vc.get_similar_neurons('VFB_001012ay')

id NBLAST_score label types source_id accession_in_source
0 VFB_jrchjtk6 0.525 EPG(PB08)_L6 - 541870397 [EB-PB 1 glomerulus-D/Vgall neuron] neuprint_JRC_Hemibrain_1point1 541870397
1 VFB_jrchjtk8 0.524 EPG(PB08)_L6 - 912601268 [EB-PB 1 glomerulus-D/Vgall neuron] neuprint_JRC_Hemibrain_1point1 912601268
2 VFB_jrchjtkb 0.504 EPG(PB08)_L6 - 788794171 [EB-PB 1 glomerulus-D/Vgall neuron] neuprint_JRC_Hemibrain_1point1 788794171
3 VFB_jrchjtji 0.481 EL(EQ5)_L - 1036753721 [EBw.AMP.s-Dga-s.b neuron] neuprint_JRC_Hemibrain_1point1 1036753721
# Read those neurons from VFB 
query = get_vfb_neurons('VFB_001012ay')
matches = get_vfb_neurons(similar_to_EPG6L1.id.values)

type name id n_nodes n_connectors n_branches n_leafs cable_length soma units template
0 navis.TreeNeuron EPG(PB08)_L6 - 912601268 VFB_jrchjtk8 9819 None 1000 1015 2211.292188 None 1 micron JRC2018Unisex
1 navis.TreeNeuron EL(EQ5)_L - 1036753721 VFB_jrchjtji 13864 None 1942 1974 3403.311508 [1] 1 micron JRC2018Unisex
2 navis.TreeNeuron EPG(PB08)_L6 - 788794171 VFB_jrchjtkb 9651 None 962 987 2125.364857 None 1 micron JRC2018Unisex
3 navis.TreeNeuron EPG(PB08)_L6 - 541870397 VFB_jrchjtk6 11042 None 1099 1127 2432.101351 [1] 1 micron JRC2018Unisex
# Define colors such that query is black 
import seaborn as sns 
colors = ['k'] + sns.color_palette('muted', len(matches))

navis.plot3d([query, matches], color=colors)