NeuronList math

CatmaidNeuronList implement some of the basic arithmetic and comparison operators that you might know from standard lists or numpy.arrays. Most this should be fairly intuitive (I hope) but there are a few things you should be aware of. The following examples will illustrate that:

As per usual, we need to get some neurons first (I’m assuming you’ve already imported and setup pymaid):

nl = pymaid.get_neurons('annotation:glomerulus DA1 right')
nl.head()
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 57316 ML 2863105 2863104 5222 439 149 157 63 1109.886700 NA True
1 PN glomerulus DA1 57382 ML 57381 7730 360 153 162 71 1215.920600 NA True
2 PN glomerulus DA1 61222 AJ 61221 7875 534 135 140 26 1182.642823 NA True
3 PN glomerulus DA1 57354 GA 57353 4898 327 90 95 52 1113.156682 NA True
4 PN glomerulus DA1 57324 LK JSL 57323 4585 438 120 127 59 1035.099284 NA True

Comparisons

The == operator compares two elements:

1 == 1
True
2 == 1
False

For CatmaidNeuron this is done by comparing the neurons’ morphologies (somas, root nodes, cable length, …) and meta data (skeleton ID, name, …).

n1 = nl[0]
n2 = nl[0]
n1 == n2
True
n1 = nl[0]
n2 = nl[1]
n1 == n2
False

For CatmaidNeuronList, we do the same comparison pairwise between neurons in both neuronlists - so order matters!.

nl == nl
True
nl == nl[:-1]
False
nl[[0, 1, 2]] == nl[[2, 1, 0]]
False

This is safe against copying but making any changes to the neurons will cause inequality:

n1 = nl[0]
n2 = n1.copy()
n1 == n2
True
n1 = nl[0]
n2 = n1.reroot(nl[0].tags['ends'][0], inplace=False)
n1 == n2
False

You can also ask if a neuron is in a given CatmaidNeuronList:

n1 = nl[0]
n1 in nl
True
n1 in nl[1:]
False

This also works with skeleton IDs

n1.skeleton_id in nl
True
n1.skeleton_id in nl[1:]
False

Addition

To merge two lists in Python, you can simply add them:

a = [1]
b = [3]
a + b
[1, 3]

CatmaidNeuronList works exactly the same:

a = nl[0]
b = nl[[1, 2]]
a + b
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 57382 ML 57381 7729 360 153 162 71 1215.920599 NA True
1 AL.L(DA1) -{mALT}-> CAL.L-LH.L 2379518 PN022 D... 2379517 4657 411 86 90 31 836.067253 NA True
2 PN glomerulus DA1 57312 LK 57311 4882 429 157 164 105 1182.102458 NA True

This also works on with two single CatmaidNeuron! You can use that to combine them into a list:

a = nl[0]
b = nl[1]
a + b
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 57316 ML 2863105 2863104 5222 439 149 157 63 1109.88670 NA True
1 AL.L(DA1) -{mALT}-> CAL.L-LH.L 2319458 PN036 D... 2319457 10209 964 431 458 90 1747.51171 NA True

Note

If you want to combine two CatmaidNeurons into a single neuron instead of creating a neuronlist, check out pymaid.stitch_neurons().

Substraction

To remove an item from a Python list, you would call the .pop() method:

a = [1, 2, 3]
b = 2
a.pop(b)
a
[1, 2]

CatmaidNeuronList lets you simply use substraction:

a = nl[[0, 1, 2]]
b = nl[2]
a - b
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 57382 ML 57381 7729 360 153 162 71 1215.920599 NA True
1 AL.L(DA1) -{mALT}-> CAL.L-LH.L 2379518 PN022 D... 2379517 4657 411 86 90 31 836.067253 NA True

Bitwise AND

To find the intersection between two lists, you would use sets and the & operator:

a = set([0, 1, 2])
b = set([2, 3, 4])
a & b
{2}

CatmaidNeuronList work similarly:

a = nl[[0, 1, 2]]
b = nl[[2, 3, 4]]
a & b
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 57312 LK 57311 4882 429 157 164 105 1182.102458 NA True

All of the above also work with skeleton IDs as one of the operators

a = nl[[0, 1, 2]]
b = nl[[2, 3, 4]]
a & b.skeleton_id
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 57312 LK 57311 4882 429 157 164 105 1182.102458 NA True

Multiplication and Division

So far, all operations have led to changes in the structure of the CatmaidNeuronList. Multiplication and division are different! If you multiply/divide a CatmaidNeuron or CatmaidNeuronList by a number, you will change the coordinates of nodes and connectors (plus node radii):

n = nl[0]
n.nodes.head()
treenode_id parent_id creator_id x y z radius confidence type
0 3046710 32963981 53 442883 212802 44240 -1 5 slab
1 32963981 3046707 150 442931 212892 44040 -1 5 slab
2 652935 652934 22 444126 151826 216240 -1 5 slab
3 3245741 3245737 61 414617 243177 52400 3451 5 end
4 3042776 27298300 53 436753 225519 38000 -1 5 slab
n2 = n / 1000
n2.nodes.head()
treenode_id parent_id creator_id x y z radius confidence type
0 3046710 32963981 53 442.883 212.802 44.24 -0.001 5 slab
1 32963981 3046707 150 442.931 212.892 44.04 -0.001 5 slab
2 652935 652934 22 444.126 151.826 216.24 -0.001 5 slab
3 3245741 3245737 61 414.617 243.177 52.40 3.451 5 end
4 3042776 27298300 53 436.753 225.519 38.00 -0.001 5 slab

The main use of this is to convert units from e.g. nm to um.

Dealing with unequal neuron objects

As we demonstrated earlier, making changes to CatmaidNeuron/Lists will cause comparisons to fail. This also propagates into substractions and bitwise comparisons:

n1 = nl[0]
n1 in nl
True
n2 = n1.reroot(nl[0].tags['ends'][0], inplace=False)
n2 in nl
False
nl & n1
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 57316 ML 2863105 2863104 5222 439 149 157 63 1109.8867 NA True
nl & n2
WARNING : Skeleton IDs overlap but neuron not identical! Bitwise cancelled! Try using .skeleton_id instead. (pymaid)

See how the comparison fails because we’ve made changes? The same happens if you tried nl - n2.

As mentioned in the warning, the workaround is to use the skeleton ID instead:

n2.skeleton_id in nl
True
nl & n2.skeleton_id
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 57316 ML 2863105 2863104 5222 439 149 157 63 1109.8867 NA True