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 |