From 3fbfb6af4c89e87f3283eee1929ebdb3ff89589b Mon Sep 17 00:00:00 2001 From: Matthew Brett Date: Tue, 5 Jun 2018 21:44:03 +0100 Subject: [PATCH 1/2] DOC: use get_fdata in docs We will soonish deprecate get_data, so remove from the docs now, so as not to trip up new users. --- doc/source/coordinate_systems.rst | 4 +- doc/source/devel/modified_images.rst | 6 +-- doc/source/gettingstarted.rst | 2 +- doc/source/images_and_memory.rst | 62 +++++++++++------------ doc/source/neuro_radio_conventions.rst | 2 +- doc/source/nibabel_images.rst | 39 ++++++++++---- doc/source/old/examples.txt | 14 ++--- doc/source/old/orientation.txt | 2 +- doc/source/scripts/make_coord_examples.py | 6 +-- 9 files changed, 75 insertions(+), 62 deletions(-) diff --git a/doc/source/coordinate_systems.rst b/doc/source/coordinate_systems.rst index a45488012d..1576eceb95 100644 --- a/doc/source/coordinate_systems.rst +++ b/doc/source/coordinate_systems.rst @@ -34,7 +34,7 @@ We can load up the EPI image to get the image data array: >>> import nibabel as nib >>> epi_img = nib.load('downloads/someones_epi.nii.gz') - >>> epi_img_data = epi_img.get_data() + >>> epi_img_data = epi_img.get_fdata() >>> epi_img_data.shape (53, 61, 33) @@ -64,7 +64,7 @@ and look at slices in the three axes: :context: >>> anat_img = nib.load('downloads/someones_anatomy.nii.gz') - >>> anat_img_data = anat_img.get_data() + >>> anat_img_data = anat_img.get_fdata() >>> anat_img_data.shape (57, 67, 56) >>> show_slices([anat_img_data[28, :, :], diff --git a/doc/source/devel/modified_images.rst b/doc/source/devel/modified_images.rst index 6230f5bb11..5b6e203a42 100644 --- a/doc/source/devel/modified_images.rst +++ b/doc/source/devel/modified_images.rst @@ -77,10 +77,10 @@ flag when anyone asks for the data, on the basis that the user may then do something to the data and you can't know if they have:: img = nibabel.load('some_image.nii') - data = img.get_data() + data = img.get_fdata() data[:] = 0 img2 = nibabel.load('some_image.nii') - assert not np.all(img2.get_data() == img.get_data()) + assert not np.all(img2.get_fdata() == img.get_fdata()) The image consists of the data, the affine and a header. In order to keep track of the header and affine, we could cache them when loading @@ -96,7 +96,7 @@ When we need to know whether the image object and image file correspond, we could check the current header and current affine (the header may be separate from the affine for an SPM Analyze image) against their cached copies, if they are the same and the 'dirty' flag has not been set by a previous call to -``get_data()``, we know that the image file does correspond to the image +``get_fdata()``, we know that the image file does correspond to the image object. This may be OK for small bits of memory like the affine and the header, diff --git a/doc/source/gettingstarted.rst b/doc/source/gettingstarted.rst index 9502c09d7c..3e328a5209 100644 --- a/doc/source/gettingstarted.rst +++ b/doc/source/gettingstarted.rst @@ -66,7 +66,7 @@ This information is available without the need to load anything of the main image data into the memory. Of course there is also access to the image data as a NumPy_ array ->>> data = img.get_data() +>>> data = img.get_fdata() >>> data.shape (128, 96, 24, 2) >>> type(data) diff --git a/doc/source/images_and_memory.rst b/doc/source/images_and_memory.rst index 02688156e0..2ff0de14c5 100644 --- a/doc/source/images_and_memory.rst +++ b/doc/source/images_and_memory.rst @@ -19,17 +19,17 @@ disk. Nibabel does not load the image array from the proxy when you ``load`` the image. It waits until you ask for the array data. The standard way to ask -for the array data is to call the ``get_data()`` method: +for the array data is to call the ``get_fdata()`` method: ->>> data = img.get_data() +>>> data = img.get_fdata() >>> data.shape (128, 96, 24, 2) -We also saw in :ref:`proxies-caching` that this call to ``get_data()`` will +We also saw in :ref:`proxies-caching` that this call to ``get_fdata()`` will (by default) load the array data into an internal image cache. The image -returns the cached copy on the next call to ``get_data()``: +returns the cached copy on the next call to ``get_fdata()``: ->>> data_again = img.get_data() +>>> data_again = img.get_fdata() >>> data is data_again True @@ -64,7 +64,7 @@ in cache, and True when it is in cache: >>> img = nib.load(example_file) >>> img.in_memory False ->>> data = img.get_data() +>>> data = img.get_fdata() >>> img.in_memory True @@ -73,10 +73,10 @@ True Using ``uncache`` ***************** -As y'all know, the proxy image has the array in cache, ``get_data()`` returns +As y'all know, the proxy image has the array in cache, ``get_fdata()`` returns the cached array: ->>> data_again = img.get_data() +>>> data_again = img.get_fdata() >>> data_again is data # same array returned from cache True @@ -85,34 +85,34 @@ You can uncache a proxy image with the ``uncache()`` method: >>> img.uncache() >>> img.in_memory False ->>> data_once_more = img.get_data() +>>> data_once_more = img.get_fdata() >>> data_once_more is data # a new copy read from disk False ``uncache()`` has no effect if the image is an array image, or if the cache is already empty. -You need to be careful when you modify arrays returned by ``get_data()`` on +You need to be careful when you modify arrays returned by ``get_fdata()`` on proxy images, because ``uncache`` will then change the result you get back -from ``get_data()``: +from ``get_fdata()``: >>> proxy_img = nib.load(example_file) ->>> data = proxy_img.get_data() # array cached and returned +>>> data = proxy_img.get_fdata() # array cached and returned >>> data[0, 0, 0, 0] -0 +0.0 >>> data[0, 0, 0, 0] = 99 # modify returned array ->>> data_again = proxy_img.get_data() # return cached array +>>> data_again = proxy_img.get_fdata() # return cached array >>> data_again[0, 0, 0, 0] # cached array modified -99 +99.0 So far the proxy image behaves the same as an array image. ``uncache()`` has no effect on an array image, but it does have an effect on the returned array of a proxy image: >>> proxy_img.uncache() # cached array discarded from proxy image ->>> data_once_more = proxy_img.get_data() # new copy of array loaded +>>> data_once_more = proxy_img.get_fdata() # new copy of array loaded >>> data_once_more[0, 0, 0, 0] # array modifications discarded -0 +0.0 ************* Saving memory @@ -126,8 +126,8 @@ use the ``uncache()`` method: >>> img.uncache() -Use the array proxy instead of ``get_data()`` -============================================= +Use the array proxy instead of ``get_fdata()`` +============================================== The ``dataobj`` property of a proxy image is an array proxy. We can ask the proxy to return the array directly by passing ``dataobj`` to the numpy @@ -145,25 +145,25 @@ This also works for array images, because ``np.asarray`` returns the array: >>> type(data_array) <... 'numpy.ndarray'> -If you want to avoid caching you can avoid ``get_data()`` and always use +If you want to avoid caching you can avoid ``get_fdata()`` and always use ``np.asarray(img.dataobj)``. -Use the ``caching`` keyword to ``get_data()`` -============================================= +Use the ``caching`` keyword to ``get_fdata()`` +============================================== -The default behavior of the ``get_data()`` function is to always fill the +The default behavior of the ``get_fdata()`` function is to always fill the cache, if it is empty. This corresponds to the default ``'fill'`` value to the ``caching`` keyword. So, this: >>> proxy_img = nib.load(example_file) ->>> data = proxy_img.get_data() # default caching='fill' +>>> data = proxy_img.get_fdata() # default caching='fill' >>> proxy_img.in_memory True is the same as this: >>> proxy_img = nib.load(example_file) ->>> data = proxy_img.get_data(caching='fill') +>>> data = proxy_img.get_fdata(caching='fill') >>> proxy_img.in_memory True @@ -171,21 +171,21 @@ Sometimes you may want to avoid filling the cache, if it is empty. In this case, you can use ``caching='unchanged'``: >>> proxy_img = nib.load(example_file) ->>> data = proxy_img.get_data(caching='unchanged') +>>> data = proxy_img.get_fdata(caching='unchanged') >>> proxy_img.in_memory False ``caching='unchanged'`` will leave the cache full if it is already full. ->>> data = proxy_img.get_data(caching='fill') +>>> data = proxy_img.get_fdata(caching='fill') >>> proxy_img.in_memory True ->>> data = proxy_img.get_data(caching='unchanged') +>>> data = proxy_img.get_fdata(caching='unchanged') >>> proxy_img.in_memory True -See the :meth:`get_data() docstring -` for more detail. +See the :meth:`get_fdata() docstring +` for more detail. ********************** Saving time and memory @@ -202,7 +202,7 @@ For example, let us say you only wanted the second volume from the example dataset. You could do this: >>> proxy_img = nib.load(example_file) ->>> data = proxy_img.get_data() +>>> data = proxy_img.get_fdata() >>> data.shape (128, 96, 24, 2) >>> vol1 = data[..., 1] diff --git a/doc/source/neuro_radio_conventions.rst b/doc/source/neuro_radio_conventions.rst index f88c31ddf8..a9a51ab2c2 100644 --- a/doc/source/neuro_radio_conventions.rst +++ b/doc/source/neuro_radio_conventions.rst @@ -101,7 +101,7 @@ showing the middle slice of :download:`an image [ 0. , 2.75, 0. , -91. ], [ 0. , 0. , 2.75, -91. ], [ 0. , 0. , 0. , 1. ]]) - >>> img_data = img.get_data() + >>> img_data = img.get_fdata() >>> a_slice = img_data[:, :, 28] >>> # Need transpose to put first axis left-right, second bottom-top >>> plt.imshow(a_slice.T, cmap="gray", origin="lower") # doctest: +SKIP diff --git a/doc/source/nibabel_images.rst b/doc/source/nibabel_images.rst index ffdef7fbdd..559a6b1094 100644 --- a/doc/source/nibabel_images.rst +++ b/doc/source/nibabel_images.rst @@ -220,21 +220,38 @@ False Getting the image data the easy way =================================== -For either type of image (array or proxy) you can always get the data with -the :meth:`get_data() ` method. +For either type of image (array or proxy) you can always get the data with the +:meth:`get_fdata() ` method. -For the array image, ``get_data()`` just returns the data array: +For the array image, ``get_fdata()`` just returns the data array, if it's already the required floating point type (default 64-bit float). If it isn't that type, ``get_fdata()`` casts it to one: ->>> image_data = array_img.get_data() +>>> image_data = array_img.get_fdata() >>> image_data.shape (2, 3, 4) ->>> image_data is array_data +>>> image_data.dtype == np.dtype(np.float64) True -For the proxy image, the ``get_data()`` method fetches the array data from +The cast to floating point means the array is not the one attached to the image: + +>>> image_data is array_img.dataobj +False + +Here's an image backed by a floating point array: + +>>> farray_img = nib.Nifti1Image(image_data.astype(np.float64), affine) +>>> farray_data = farray_img.get_fdata() +>>> farray_data.dtype == np.dtype(np.float64) +True + +There was no cast, so the array returned is exactly the array attached to the image: + +>>> image_data is array_img.dataobj +False + +For the proxy image, the ``get_fdata()`` method fetches the array data from disk using the proxy, and returns the array. ->>> image_data = img.get_data() +>>> image_data = img.get_fdata() >>> image_data.shape (128, 96, 24, 2) @@ -249,12 +266,12 @@ Proxies and caching =================== You may not want to keep loading the image data off disk every time -you call ``get_data()`` on a proxy image. By default, when you call -``get_data()`` the first time on a proxy image, the image object keeps a -cached copy of the loaded array. The next time you call ``img.get_data()``, +you call ``get_fdata()`` on a proxy image. By default, when you call +``get_fdata()`` the first time on a proxy image, the image object keeps a +cached copy of the loaded array. The next time you call ``img.get_fdata()``, the image returns the array from cache rather than loading it from disk again. ->>> data_again = img.get_data() +>>> data_again = img.get_fdata() The returned data is the same (cached) copy we returned before: diff --git a/doc/source/old/examples.txt b/doc/source/old/examples.txt index b84f5441bf..19a44d9cb0 100644 --- a/doc/source/old/examples.txt +++ b/doc/source/old/examples.txt @@ -108,7 +108,7 @@ previously created in a separate file. First, we open the file: Now we select the first ten volumes and store them to another file, while preserving as much header information as possible - >>> nim2 = nib.Nifti1Image(nim.get_data()[..., :10], + >>> nim2 = nib.Nifti1Image(nim.get_fdata()[..., :10], ... nim.get_affine(), ... nim.header) >>> print nim2.header['dim'] @@ -127,7 +127,7 @@ Linear detrending of timeseries (SciPy module is required for this example) =========================================================================== Let's load another 4d NIfTI file and perform a linear detrending, by fitting -a straight line to the timeseries of each voxel and substract that fit from +a straight line to the timeseries of each voxel and subtract that fit from the data. Although this might sound complicated at first, thanks to the excellent SciPy module it is just a few lines of code. For this example we will first create a NIfTI image with just a single voxel and 50 timepoints @@ -139,15 +139,11 @@ will first create a NIfTI image with just a single voxel and 50 timepoints >>> print nim.header['dim'] [ 4 1 1 1 50 1 1 1] -Depending on the datatype of the input image the detrending process might -change the datatype from integer to float. As operations that change the -(binary) size of the NIfTI image are not supported, we need to make a copy -of the data and later create a new NIfTI image. Remember that the array has the -time axis as its first dimension (in contrast to the NIfTI file where it is -the 4th). +Remember that the array has the time axis as its first dimension (in contrast +to the NIfTI file where it is the 4th). >>> from scipy import signal - >>> data_detrended = signal.detrend(nim.get_data(), axis=0) + >>> data_detrended = signal.detrend(nim.get_fdata(), axis=0) Finally, create a new NIfTI image using header information from the original source image. diff --git a/doc/source/old/orientation.txt b/doc/source/old/orientation.txt index 4efbe73db1..ef231f7e95 100644 --- a/doc/source/old/orientation.txt +++ b/doc/source/old/orientation.txt @@ -85,7 +85,7 @@ the affine after loading, as in:: img = nibabel.load('some_image.img') aff = img.get_affine() x_flipper = np.diag([-1,1,1,1]) - lr_img = nibabel.Nifti1Image(img.get_data, np.dot(x_flipper, aff), img.header) + lr_img = nibabel.Nifti1Image(img.get_fdata(), np.dot(x_flipper, aff), img.header) Affines for Analyze, SPM analyze, and NIFTI ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/scripts/make_coord_examples.py b/doc/source/scripts/make_coord_examples.py index 790c8b7671..9079cea141 100644 --- a/doc/source/scripts/make_coord_examples.py +++ b/doc/source/scripts/make_coord_examples.py @@ -50,7 +50,7 @@ t1_img, t2_img = imgs # Make fake localizer -data = t1_img.get_data() +data = t1_img.get_fdata() n_x, n_y, n_z = img.shape mid_x = round(n_x / 2) @@ -171,7 +171,7 @@ def vx2mm(pts): # resample, preserving affine epi_cmap = nca.vox2mni(epi_vox2mm) epi = rsm.resample(t2_img, epi_cmap, np.eye(4), epi_vox_shape) -epi_data = epi.get_data() +epi_data = epi.get_fdata() # Do the same kind of thing for the anatomical scan anat_vox_sizes = [2.75, 2.75, 2.75] anat_scale = npl.inv(np.diag(anat_vox_sizes + [1])) @@ -183,7 +183,7 @@ def vx2mm(pts): [data.shape[0], anat_x_len, anat_y_len], anat_vox_sizes)) anat_cmap = nca.vox2mni(anat_vox2mm) anat = rsm.resample(t1_img, anat_cmap, np.eye(4), anat_vox_shape) -anat_data = anat.get_data() +anat_data = anat.get_fdata() save_plot() nipy.save_image(epi, 'someones_epi.nii.gz', dtype_from='uint8') From a021905b5b6d3e23940978ea91b616d29655c3f2 Mon Sep 17 00:00:00 2001 From: Matthew Brett Date: Fri, 8 Jun 2018 16:04:59 +0100 Subject: [PATCH 2/2] BF: fix example for get_fdata and array images Float64 array images return the array from get_fdata, with default input arguements, but other data types return the array cast to float64. Tests will fail before merge of fix in https://github.com/nipy/nibabel/pull/638 . --- doc/source/nibabel_images.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/source/nibabel_images.rst b/doc/source/nibabel_images.rst index 559a6b1094..f14debcc93 100644 --- a/doc/source/nibabel_images.rst +++ b/doc/source/nibabel_images.rst @@ -243,10 +243,11 @@ Here's an image backed by a floating point array: >>> farray_data.dtype == np.dtype(np.float64) True -There was no cast, so the array returned is exactly the array attached to the image: +There was no cast, so the array returned is exactly the array attached to the +image: ->>> image_data is array_img.dataobj -False +>>> farray_data is farray_img.dataobj +True For the proxy image, the ``get_fdata()`` method fetches the array data from disk using the proxy, and returns the array.