-
Notifications
You must be signed in to change notification settings - Fork 261
ENH: Add image_like function for SpatialImages #300
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 very much for this. A previous request that I didn't follow up on was to have a function or method called 'image_like' which accepts an image as a template followed by data, optionally affine, header, extra. That would be rather general, so your code could be:
What do you think? |
That could work. Personally, I use the map inline a lot, so I'll most likely still have something like this in my own code:
But whatever seems most fitting for how nibabel does things is fine with me. I also have a somewhat common pattern of performing folds (or Right now, for instance, I use the following:
What would be ideal would be something like:
And similarly, the existing function might be rewritten:
|
Oh, should note that I'm considering the version of |
Went ahead and created Just want to point out that this same function could have (at least) three interfaces:
I implemented the first. The code for the second would be identical, except for an indent and changing I think I prefer the first or second, so that its use wouldn't depend on the image having been assigned to a variable or its class being known in advance, but since the functionality is so close to an existing function, it seemed worth noting. |
In general this does seem a good idea. One issue is that nibabel does not insist for every supported format that:
For example your Thinking aloud, how about:
? |
I like this, as it gives a simple interface while taking advantage of existing behavior. I'll push what I think you're saying. I'm not sure how to implement this in the subclasses you mention, but I could start by overriding
|
Sorry to be slow to comment on this one. My slowness, as usual, is due to mental fog when thinking through the API problems. Now I do think about it, I'm thinking that we need a new
In this case, images that can't do this (like MINC or PAR / REC) can just refuse:
What do you think? |
Sorry to be slow to respond. I'm not so much opposed to this idea as not quite understanding the reasoning. Could you elaborate a little? (Apologies for asking you to elaborate your thought process >2 weeks later.) Is this "Let's not mess with What should Finally, it looks like the
Or possibly a separate flag could be defined, rather than overriding the method. Anyway, my goal here is the |
55e9878
to
91f760e
Compare
3ec0328
to
68de03c
Compare
@effigies is this something you'd like to push forward on? If so, I've read through the comments and code and I'd be happy to iterate on it with you. |
Sure, but it needs some thinking through. My goal when I started this was to put in an How to implement that while working with the existing structures is the question. Iterating through a few PRs with you and Matthew has given me a better idea of how things work, but I haven't taken the time to re-think this PR in that context. Swapping new Possibly this would make sense to incorporate into the data-access (e.g. volumetric/surface) interfaces we were discussing in #360? Because the decisions about how a class should expose data should be very closely related to the ones needed to swap in a new array entirely. |
What I understood from above is: if each image declares the x/y/z/t axes, then this is straightforward (even for MINC and PAR/REC). I don't think it's wise to assume axes; it may be implementation-dependent on each image class. Heck, some classes under consideration may contain more than one image! So, better to declare those explicitly, I think. And I think, from an informatics point of view, declaring axes explicitly is a big win; if those axes are implicit (and from the discussion above I believe they are), then informatics code has to actually check the image type. Edit:
While there could be another interface (or mixin) for something like this, I suggest aiming at
Same here. I still feel very tentative in the things I suggest, but this is my best idea on my current understanding. |
68de03c
to
5f286dd
Compare
I've rebased this. To clarify my comments from #372, you actually wouldn't use I'm not quite following the axis discussion. Are you thinking that this should produce an image in the image format's "preferred" axis order? While that seems like a valid option for Let me know what you think. |
I am honestly a little baffled over my previous comments; I can't find any references to x/y/z/t axes elsewhere, but I swear I was responding to previous comments about it. My memory traces fade faster than I'd hope :) I'm taking some time to read through the docs a bit more deeply, given my misunderstanding at #372, so that I can think through this (very light-weight) code and why it may not work in some instances. Hope to comment soon. |
04f036f
to
3dc37f4
Compare
To be specific about why this does not work in general - consider this:
The first dimension in this data array is time. Now if I do:
I can run So we need to either let people shoot themselves in the foot in this way, or maybe do something like keep the axis information with the data, so that the |
Wrapping axis information could start getting messy, but here's a halfway measure: Check that the dimensions of the data object match those of the starting image in the spatial directions. The class knows about its own spatial axes, but there's no need to infect raw numpy arrays with this information. There's a possibility of a situation where The primary pattern is retaining metadata for within-format analysis pipelines:
I'm perfectly happy to add documentation to make clear that using it as a conversion routine is not recommended. |
3dc37f4
to
9edb6bd
Compare
☔ The latest upstream changes (presumably #404) made this pull request unmergeable. Please resolve the merge conflicts. |
Codecov Report
@@ Coverage Diff @@
## master #300 +/- ##
==========================================
+ Coverage 88.38% 88.38% +<.01%
==========================================
Files 188 188
Lines 24008 24016 +8
Branches 4254 4254
==========================================
+ Hits 21219 21227 +8
Misses 2102 2102
Partials 687 687
Continue to review full report at Codecov.
|
0306b6b
to
facd122
Compare
facd122
to
81619e5
Compare
☔ The latest upstream changes (presumably #550) made this pull request unmergeable. Please resolve the merge conflicts. |
I often find myself just wanting to apply a function to data in an MGHImage or Nifti1Image without discarding the headers and just using x.get_data().
I've implemented this map as a separate function, but it could easily be a method in SpatialImage, allowing subclasses to be more particular about their mapping strategy. Basic test shows that mapping (+1) to an image containing zeros results in all ones.
Is this a thing people would find useful? I'm sure there's more work to be done to integrate it properly into the nibabel framework, but figured I'd start with a proof-of-concept.