-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor dendrogram #780
Refactor dendrogram #780
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My (fast) first pass looks good, but I need to read it more carefully. Can you post an example of the output?
neurom/view/_dendrogram.py
Outdated
|
||
segments = neurom_section.points | ||
segment_lengths = np.linalg.norm( | ||
np.subtract(segments[:-1, COLS.XYZ], segments[1:, COLS.XYZ]), axis=1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
np.subtract(segments[:-1, COLS.XYZ], segments[1:, COLS.XYZ]), axis=1) | |
np.diff(segments[:COLS.XYZ], axis=0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wonder if we can use the segment_lengths
statistic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean to save it as a property? this.segments_lengths = segment_lengths
? Currently I don't see any usage for it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean use the function that does this already neurom/fst/_neuritefunc.py
, but called using get()
instead of directly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok. I will do the changes after all suggestions have been made.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I couldn't reuse segments_lengths
function because it is for neurites. I have sections. Please look neurom/fst/_neuritefunc.py#L204.
Example outputs. You can see that dendrogram became wider. It's because I've added a horizontal padding. Probably I should remove it for backward compatibility. Also I put the leftmost section at (0, 0). This way no dendrogram is on negative X axis. This change I would insist to keep. Before refactor:After refactor: |
Cool, looks great.
|
neurom/view/_dendrogram.py
Outdated
if dendrogram_root is None: | ||
dendrogram_root = self | ||
dendrogram_root.processed_section_ids = [] | ||
if neurom_section.id in dendrogram_root.processed_section_ids: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use an assert for these kind of checks.
Also, is this necessary? I'm not sure how a cycle would happen - without the check, the dendrogram_root
param wouldn't be necessary, and I think the logic would look neater?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the previous version we had sys.setrecursionlimit(max_depth)
. I thought to replace this recursion limit with the cycles check. If the recursion limit didn't target cycles validation then I will remove my cycles check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only major issue left to discuss. I would be happy to remove the cycles check but it would be nice to have a guarantee that we can't receive a cycled Neurite tree. Otherwise we need this check. I don't know where else to put it because we need this check per dendrogram tree instance. So each dendrogram node needs an access to the dendrogram tree instance. dendrogram_root
is this tree instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wizmer Do we check that the loaded morphology does is not cycled? By the loaded morphology I mean neurom.load_neuron('morph.swc')
. I don't see that we do it but I might overlooked it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the structure of the file disallows cycles. For SWC, we don't support non-connected components, so I think that's where it wouldn't load properly. I can't remember for h5.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the sys.setrecursionlimit(max_depth)
was for validation, but probably because without it it would crash for neurites with too many descendents.
I just tried on SWC with the following file and NeuroM did not complain although it should have, scary:
1 1 0 0 0 1. -1
2 3 0 0 0 1. 1
3 3 0 5 0 1. 2
4 3 -5 5 0 0. 3
5 3 6 5 0 0. 3
6 2 0 0 0 1. 6 # <-- cyclic point
7 2 0 -4 0 1. 6
8 2 6 -4 0 0. 7
9 2 -5 -4 0 0. 7
The mut_morphio
branch already raises on this file so I don't know if it's worth an implementation.
neurom/view/_dendrogram.py
Outdated
if isinstance(neuron, Neurite): | ||
return Dendrogram(neuron.root_node) | ||
SomaSection = namedtuple('NeuromSection', ['id', 'type', 'children', 'points']) | ||
soma_section = SomaSection( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a way to do this with having a 'fake' soma section? I'm thinking that Dendrogram()
could check the type, and then create the 'fake' data inline, instead of it being bundled into an object here, and basically decomposed in the __init__
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-run the notebook in tutorial/neurom_tutorial.ipynb
so that it displays the new-style dendrogram.
neurom/view/dendrogram.py
Outdated
) | ||
if dendrogram_root is None: | ||
dendrogram_root = self | ||
dendrogram_root.processed_section_ids = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dendrogram_root.processed_section_ids = [] | |
self.processed_section_ids = [] |
to emphasize on the fact that the processed_section_ids you're setting is the one of the current object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I would keep dendrogram
to emphasize that there is a tree head and self
is this head now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dropped the cycles check because it is implemented in mut_morphio
branch and the NeuroM core is a more appropriate place for this check.
neurom/view/_dendrogram.py
Outdated
if dendrogram_root is None: | ||
dendrogram_root = self | ||
dendrogram_root.processed_section_ids = [] | ||
if neurom_section.id in dendrogram_root.processed_section_ids: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the sys.setrecursionlimit(max_depth)
was for validation, but probably because without it it would crash for neurites with too many descendents.
I just tried on SWC with the following file and NeuroM did not complain although it should have, scary:
1 1 0 0 0 1. -1
2 3 0 0 0 1. 1
3 3 0 5 0 1. 2
4 3 -5 5 0 0. 3
5 3 6 5 0 0. 3
6 2 0 0 0 1. 6 # <-- cyclic point
7 2 0 -4 0 1. 6
8 2 6 -4 0 0. 7
9 2 -5 -4 0 0. 7
The mut_morphio
branch already raises on this file so I don't know if it's worth an implementation.
@wizmer I ran it and it worked fine. If you see a problem please say it directly. |
It works, but the picture of the dendrogram cell #6 is the one from the old algo, so I just re-run this cell and update the notebook. |
Refactored dendrogram in order to add synapses to it later. Will be a separate PR.