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):
[1]:
nl = pymaid.get_neurons('annotation:glomerulus DA1 right')
nl.head()
[1]:
| 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:
[2]:
1 == 1
[2]:
True
[3]:
2 == 1
[3]:
False
For CatmaidNeuron this is done by comparing the neurons’ morphologies (somas, root nodes, cable length, …) and meta data (skeleton ID, name, …).
[4]:
n1 = nl[0]
n2 = nl[0]
n1 == n2
[4]:
True
[5]:
n1 = nl[0]
n2 = nl[1]
n1 == n2
[5]:
False
For CatmaidNeuronList, we do the same comparison pairwise between neurons in both neuronlists - so order matters!.
[6]:
nl == nl
[6]:
True
[7]:
nl == nl[:-1]
[7]:
False
[8]:
nl[[0, 1, 2]] == nl[[2, 1, 0]]
[8]:
False
This is safe against copying but making any changes to the neurons will cause inequality:
[9]:
n1 = nl[0]
n2 = n1.copy()
n1 == n2
[9]:
True
[10]:
n1 = nl[0]
n2 = n1.reroot(nl[0].tags['ends'][0], inplace=False)
n1 == n2
[10]:
False
You can also ask if a neuron is in a given CatmaidNeuronList:
[11]:
n1 = nl[0]
n1 in nl
[11]:
True
[12]:
n1 in nl[1:]
[12]:
False
This also works with skeleton IDs
[13]:
n1.skeleton_id in nl
[13]:
True
[14]:
n1.skeleton_id in nl[1:]
[14]:
False
Addition¶
To merge two lists in Python, you can simply add them:
[15]:
a = [1]
b = [3]
a + b
[15]:
[1, 3]
CatmaidNeuronList works exactly the same:
[16]:
a = nl[0]
b = nl[[1, 2]]
a + b
[16]:
| 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:
[17]:
a = nl[0]
b = nl[1]
a + b
[17]:
| 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:
[18]:
a = [1, 2, 3]
b = 2
a.pop(b)
a
[18]:
[1, 2]
CatmaidNeuronList lets you simply use substraction:
[19]:
a = nl[[0, 1, 2]]
b = nl[2]
a - b
[19]:
| 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:
[20]:
a = set([0, 1, 2])
b = set([2, 3, 4])
a & b
[20]:
{2}
CatmaidNeuronList work similarly:
[21]:
a = nl[[0, 1, 2]]
b = nl[[2, 3, 4]]
a & b
[21]:
| 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
[22]:
a = nl[[0, 1, 2]]
b = nl[[2, 3, 4]]
a & b.skeleton_id
[22]:
| 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):
[23]:
n = nl[0]
n.nodes.head()
[23]:
| 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 |
[24]:
n2 = n / 1000
n2.nodes.head()
[24]:
| 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:
[25]:
n1 = nl[0]
n1 in nl
[25]:
True
[26]:
n2 = n1.reroot(nl[0].tags['ends'][0], inplace=False)
n2 in nl
[26]:
False
[27]:
nl & n1
[27]:
| 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 |
[28]:
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:
[29]:
n2.skeleton_id in nl
[29]:
True
[30]:
nl & n2.skeleton_id
[30]:
| 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 |