-
Notifications
You must be signed in to change notification settings - Fork 262
BF: if voxel order in header is lowercase, .trk can't load #590
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
Conversation
Thanks a lot for this - @MarcCote - any reason we should insist on lower-case voxel orientations? @kesshijordan - any chance of adding a test? |
Thanks, @matthew-brett. Sure, though do you know how to fix the travis failures, above? The spacing on the arrays disagrees on expected vs got (though the numbers match) in the DOC_DOC_TEST=1 builds. |
Codecov Report
@@ Coverage Diff @@
## master #590 +/- ##
==========================================
- Coverage 94.58% 94.46% -0.12%
==========================================
Files 177 177
Lines 25533 24949 -584
Branches 2813 2661 -152
==========================================
- Hits 24150 23569 -581
Misses 908 908
+ Partials 475 472 -3
Continue to review full report at Codecov.
|
Thanks, @effigies @matthew-brett I added a test comparing the trackvis to rasmm affines between two simulated trk files (voxel order las and LAS). I put it in the test_load_file_with_wrong_information() set. Is that fine? |
@matthew-brett no, there is no reason why we couldn't support both. That said, shouldn't we fix that in |
Good point - lower case should be OK for the axis codes in orientations.py ... |
@matthew-brett and @MarcCote : I moved the change to |
nibabel/orientations.py
Outdated
@@ -349,6 +349,7 @@ def axcodes2ornt(axcodes, labels=None): | |||
[ 0., -1.], | |||
[ 2., 1.]]) | |||
""" | |||
axcodes = axcodes.upper() |
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.
According to the docsring, axcodes
is a tuple not a str. So, .upper()
does not exist.
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.
Thanks; I hadn't noticed that : ) It fixed my loading issue because the .trk files I'm trying to load have orientation stored as a string, but that does break on tuples. I exchanged that line for a loop that generates an upper-case tuple from either a string or a tuple (see below). How's this?
upper_str = []
for c in axcodes:
upper_str.append(c.upper())
axcodes = tuple(upper_str)
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.
How about the following?
axcodes = tuple(c.upper() for c in axcodes)
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.
Thanks, @effigies
Sorry to push more work on you, but do you think you could quickly add some test cases to nibabel/nibabel/tests/test_orientations.py Lines 278 to 314 in ee4ce2a
Something like: lia_ornt = [[0, -1], [2, -1], [1, 1]]
for lia_axcodes in ('LIA', 'lia', ('L', 'I', 'A'), ('l', 'i', 'a')):
assert_array_equal(axcodes2ornt(lia_axcodes), lia_ornt) |
nibabel/orientations.py
Outdated
@@ -349,6 +349,9 @@ def axcodes2ornt(axcodes, labels=None): | |||
[ 0., -1.], | |||
[ 2., 1.]]) | |||
""" | |||
|
|||
axcodes = tuple(c.upper() for c in axcodes) |
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 breaking on labels is not None
. Probably the least disruptive approach is to move this into the if labels is None
branch immediately below.
My reasoning is that, if somebody's passing labels, they'll also be passing axis codes with labels selected from that set. (The alternative would be to also apply .upper()
to the labels, but I don't like the smell of that.)
Hi @kesshijordan, just checking in. I think this is very nearly ready, if you have a few minutes. If you're swamped, I can submit a PR to your branch with my suggested changes. |
Hi, @effigies. Thanks for checking in; I've been swamped but I have a bit of time now. I'll submit changes soon. |
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.
Thanks for your work on this. I think this final fix should get the tests working.
nibabel/orientations.py
Outdated
@@ -349,7 +349,9 @@ def axcodes2ornt(axcodes, labels=None): | |||
[ 0., -1.], | |||
[ 2., 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.
Just for a clean diff, could you remove this empty line?
nibabel/orientations.py
Outdated
if labels is None: | ||
axcodes = tuple(c.upper() for c in axcodes) |
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.
Looks like we did not consider c is None
. Maybe update this to:
axcodes = tuple(c.upper() if c is not None else None for c in axcodes)
Absolutely. Thanks for all the pointers, @effigies. I have made those corrections and resubmitted. |
Looks ready to me. @MarcCote @matthew-brett any further comments? |
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.
At least we should document that the labels / codes are not case sensitive...
@@ -350,6 +350,7 @@ def axcodes2ornt(axcodes, labels=None): | |||
[ 2., 1.]]) | |||
""" | |||
if labels is None: | |||
axcodes = tuple(c.upper() if c is not None else None for c in axcodes) |
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.
Should this be run only when labels is None
?
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.
Yes. Unless the labels themselves are also to be filtered. See #590 (comment).
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.
Doesn't that smell off though - to be case insensitive only when the labels are not specified?
I guess the ideal would be to be case insensitive only for codes labels in LRAPIS
.
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 see, so the issue is if someone passes an alternative default ordering of the normal codes, but not custom labels, we want the overall behavior to be unchanged. I was under the impression that the only time you wanted to specify labels would be to use some custom labeling.
Then yeah, that might make sense. What if it becomes:
if labels is None:
labels = list(zip('LPI', 'RAS'))
# Enable case-insensitive axis codes for standard direction labels
if set(elem for pair in labels for elem in pair) == set('LRAPIS'):
axcodes = tuple(...)
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.
@matthew-brett Can you please confirm whether I've summarized your concern and proposed a reasonable solution? If so, I think we can get this fix in pretty soon.
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.
Sorry to be a bit imprecise.
Now I think about this more, it still seems ugly to me to special case for characters LRAPIS
. Why these and not other codes? For example, what if someone uses F
and B
for front and back? Wouldn't they expect the same behavior?
I've very sorry to keep changing, but can't we go back to expecting upper case for the codes from the caller, and, in particular, fixing this in the trackvis caller rather than here?
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.
@matthew-brett would it make sense to put in a "header format check" that returns a more informative error? That way the user can see why the load is failing and modify the header themself?
@kesshijordan - I've made an alternative PR, as a suggestion. It's got your initial changes, plus (I think) some code to give a more informative error, as you suggested above. Is that OK with you? |
Sorry - the PR is linked below, but for completeness - #600 |
That sounds good, @matthew-brett. Thanks! |
☔ The latest upstream changes (presumably #600) made this pull request unmergeable. Please resolve the merge conflicts. |
@kesshijordan - OK to close this one? |
Yes, I'm good with the changes of #600. |
Yes, @matthew-brett. Okay to close this one. |
If the voxel_order field of the header is lowercase in a track file (this is the case when I re-save streamlines using trackvis on my mac: Trackvis Version 0.6.1 (Build 2017.01.17) Public), it will not load using the new nib.streamlines.load because axcodes2ornt returns nan's when given a lower case voxel order.