-
Notifications
You must be signed in to change notification settings - Fork 530
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
ENH: Pacify DeprecationWarnings caused by nibabel 3 pre-release #3099
Conversation
d87adf4
to
d00267f
Compare
Codecov Report
@@ Coverage Diff @@
## master #3099 +/- ##
==========================================
- Coverage 67.79% 67.78% -0.01%
==========================================
Files 295 295
Lines 39310 39304 -6
Branches 5181 5178 -3
==========================================
- Hits 26651 26644 -7
Misses 11951 11951
- Partials 708 709 +1
Continue to review full report at Codecov.
|
cc86dc5
to
4ceba42
Compare
@@ -664,7 +662,7 @@ def _run_interface(self, runtime): | |||
) | |||
|
|||
components, filter_basis, metadata = compute_noise_components( | |||
imgseries.get_data(), | |||
imgseries.get_fdata(dtype=np.float32), |
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 specifically verify that the desired behavior here would be to compute noise components on float32 data... float64 would be very large, but this data is presumably floating point, so using the dataobj interface seems needlessly cumbersome.
) | ||
|
||
mask_images = self._process_masks(mask_images, imgseries.get_data()) | ||
mask_images = self._process_masks(mask_images, imgseries.dataobj) |
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 moved the array coercion to _process_masks
, since the data may not be used.
6768734
to
dc50f92
Compare
This is ready for some quite tedious review. Sorry. |
This really should get a second pair of eyes. It's a lot of changes. |
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.
Took another look with fresh eyes. Some proposed changes. Went ahead and cleaned up NUMPY_MMAP
(see #3112) while I was at it.
I will commit the changes that are obviously needed. If someone would like to review, feel free to accept or reject the others.
maskdata = np.logical_not(np.logical_or(maskdata == 0, np.isnan(maskdata))) | ||
|
||
session_datas = [ | ||
[ | ||
nb.load(fname, mmap=NUMPY_MMAP).get_data()[maskdata].reshape(-1, 1) | ||
nb.load(fname, mmap=NUMPY_MMAP).get_fdata()[maskdata].reshape(-1, 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.
To control memory usage:
nb.load(fname, mmap=NUMPY_MMAP).get_fdata()[maskdata].reshape(-1, 1) | |
nb.load(fname).get_fdata(dtype=np.float32)[maskdata].reshape(-1, 1) |
origdata1 = np.logical_and( | ||
nii1.get_data() != 0, np.logical_not(np.isnan(nii1.get_data())) | ||
) | ||
origdata1 = np.asanyarray(nii1.dataobj) |
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 looks like we're finding a mask of a volume of real values, so I would probably go with fdata. The slight potential memory advantage of dataobj
doesn't justify ugliness IMO.
origdata1 = np.asanyarray(nii1.dataobj) | |
origdata1 = nii1.get_fdata(dtype=np.float32) |
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.
the next line is origdata1 != 0
, which may not work for float.
nipype/algorithms/metrics.py
Outdated
nii1.get_data() != 0, np.logical_not(np.isnan(nii1.get_data())) | ||
) | ||
origdata1 = np.asanyarray(nii1.dataobj) | ||
origdata1 = (origdata1 != 0) & ~np.isnan(origdata1) | ||
cog_t = np.array(center_of_mass(origdata1.copy())).reshape(-1, 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.
Not used again, so hard to see why a copy is needed.
cog_t = np.array(center_of_mass(origdata1.copy())).reshape(-1, 1) | |
cog_t = np.array(center_of_mass(origdata1)).reshape(-1, 1) |
origdata2 = np.logical_and( | ||
nii2.get_data() != 0, np.logical_not(np.isnan(nii2.get_data())) | ||
) | ||
origdata2 = np.asanyarray(nii2.dataobj) |
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.
Again:
origdata2 = np.asanyarray(nii2.dataobj) | |
origdata2 = nii2.get_fdata(dtype=np.float32) |
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.
the next line is origdata2 != 0
, which may not work for float.
else: | ||
return np.mean(min_dist_matrix) | ||
|
||
def _eucl_max(self, nii1, nii2): | ||
from scipy.spatial.distance import cdist | ||
|
||
origdata1 = nii1.get_data() | ||
origdata1 = np.asanyarray(nii1.dataobj) |
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.
origdata1 = np.asanyarray(nii1.dataobj) | |
origdata1 = nii1.get_fdata(dtype=np.float32) |
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.
ok, now i'm confused why this function uses get_fdata
, but the previous one (_eucl_mean
) uses dataobj
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 criterion here was whether something appeared to be targeting integer values.
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.
roger!
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.
the next line is origdata1 == 0
, which may not work for float.
@satra For context, the semantics are:
|
@satra Should I interpret 👍 as "go ahead and commit" and no response as not to commit? |
@effigies - i think it looks good to me after your semantics explanation. i have not gotten a chance to fully go through it. if you would like me to i can do it tomorrow. |
I would prefer if somebody fully went through it. The suggestions I made are optional, but I generally tried to justify them. If you agree with the justifications, please merge them. If not, just resolve the conversations. |
@effigies - i cannot merge them - i tried yesterday - it's because i don't have write access to your nipype repo. |
Oh weird, did they change the policy on that? Should I merge the thumbs-upped? |
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.
overall looks great. i left a few comments with float point comparisons. especially for those situations it seems we should convert to something where the inequality or equality holds.
does nibabel have a helper to change a float to an int that takes range into account? or we could do np.round(img).astype(np.int32)
nipype/algorithms/confounds.py
Outdated
mask = img.get_data() > 0 | ||
np.logical_or(mask, img.get_data() > 0, mask) | ||
mask = img.get_fdata() > 0 | ||
np.logical_or(mask, img.get_fdata() > 0, mask) |
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.
a note that this may not be a good comparison for floating point data.
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.
and there are a few places in this function where it happens. it's likely not a big difference in the context of this function.
origdata2 = np.logical_not(np.logical_or(origdata2 == 0, np.isnan(origdata2))) | ||
|
||
if isdefined(self.inputs.mask_volume): | ||
maskdata = nb.load(self.inputs.mask_volume).get_data() | ||
maskdata = np.asanyarray(nb.load(self.inputs.mask_volume).dataobj) |
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.
the next line is maskdata == 0
, which may not work for float.
origdata1 = np.logical_not(np.logical_or(origdata1 == 0, np.isnan(origdata1))) | ||
origdata2 = nii2.get_data() | ||
origdata2 = np.asanyarray(nii2.dataobj) |
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.
the next line is origdata2 == 0
, which may not work for float.
else: | ||
return np.mean(min_dist_matrix) | ||
|
||
def _eucl_max(self, nii1, nii2): | ||
from scipy.spatial.distance import cdist | ||
|
||
origdata1 = nii1.get_data() | ||
origdata1 = np.asanyarray(nii1.dataobj) |
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.
the next line is origdata1 == 0
, which may not work for float.
origdata2 = np.logical_and( | ||
nii2.get_data() != 0, np.logical_not(np.isnan(nii2.get_data())) | ||
) | ||
origdata2 = np.asanyarray(nii2.dataobj) |
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.
the next line is origdata2 != 0
, which may not work for float.
origdata1 = np.logical_and( | ||
nii1.get_data() != 0, np.logical_not(np.isnan(nii1.get_data())) | ||
) | ||
origdata1 = np.asanyarray(nii1.dataobj) |
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.
the next line is origdata1 != 0
, which may not work for float.
Selecting dtype=float32 for loading full time series
Not that I know of. It's hard to think of a general solution that doesn't get so parameterized that explicitly describing what you want with numpy doesn't make more sense. Anyway, post-3.0 the easy way will be something like: |
fbf853c
to
8e44223
Compare
@satra Thanks for the review. This is ready for merge, IMO. |
ccc8dc2
to
fcbaad8
Compare
go for it, once it clears tests. |
Summary
Updated Travis on master to actually install pre-release dependencies. Starting on deprecation warnings.
I would appreciate a careful review. In general,
np.[as[any]]array(niimg.dataobj)
is the more conservative change, keepingget_data()
functionality, except for caching. When floats obviously make more sense, I'm switching toget_fdata()
. We may want to specifydtype=np.float32
in these cases.I'm also in passing removing unnecessary loading of data blocks, such as
get_data().shape
orget_data().ndim
.List of changes proposed in this PR (pull-request)
get_data()
Acknowledgment