1.. -*- mode: rst -*- 2 3################################################## 4Relationship between images and io implementations 5################################################## 6 7******************** 8Summary and sign-off 9******************** 10 11These were some meditations about splitting the image into two API parts. 12 13The first part would be the lower level IO implementation. This part is 14rather like a fusion of the :class:`.Header` and :class:`.ArrayProxy` objects 15in current nibabel. It takes care of lower level details like i/o data dtype, 16shape, offset, and it might help with slicing to get the data. On top of that 17would be a high level interface implementing ``load``, ``save``, ``filename``, 18``data``. The top-level image also had the novel idea of a ``mode`` parameter 19which, if ``'r'``, would raise an error on attempting to ``save``. 20 21****** 22Images 23****** 24 25An image houses the association of the: 26 27* data array 28* affine 29* output space 30* metadata 31* mode 32 33These are straightforward attributes, and have no necessary relationship 34to stuff on disk. 35 36By ''disk'', we mean, file-like objects - not necessarily on disk. 37 38The *io implementation* manages the relationship of images and stuff on 39disk. 40 41Specifically, it manages ``load`` of images from disk, and ``save`` of 42images to disk. 43 44The user does not see the io implementation unless they ask to. In 45standard use of images they will not need to do this. 46 47****************** 48IO implementations 49****************** 50 51By use case. 52 53:: 54 55 Creating array image, saving 56 57 >>> import tempfile 58 >>> from nibabel.images import Image 59 >>> from nibabel import load, save 60 >>> fp, fname = tempfile.mkstemp('.nii') 61 >>> data = np.arange(24).reshape((2,3,4)) 62 >>> img = Image(data) 63 >>> img.filename is None 64 True 65 >>> img.save() 66 Traceback (most recent call last): 67 ... 68 ImageError: no filespec to save to 69 >>> save(img) 70 Traceback (most recent call last): 71 ... 72 ImageError: no filespec to save to 73 >>> img2 = save(img, 'some_image.nii') # type guessed from filename 74 >>> img2.filename == fname 75 True 76 >>> img.filename is None # still 77 True 78 >>> img.filename = 'some_filename.nii' # read only property 79 Traceback (most recent call last): 80 ... 81 AttributeError: can't set attribute 82 83 Load, futz, save 84 85 >>> img3 = load(fname, mode='r') 86 >>> img3.filename == fname 87 True 88 >>> np.all(img3.data == data) 89 True 90 >>> img3.data[0,0] = 99 91 >>> img3.save() 92 Traceback (most recent call last): 93 ... 94 ImageError: trying to write to read only image 95 >>> img3.mode = 'rw' 96 >>> img3.save() 97 >>> load(img4) 98 >>> img4.mode # 'r' is the default 99 'r' 100 >>> mod_data = data.copy() 101 >>> mod_data[0,0] = 99 102 >>> np.all(img4.data = mod_data) 103 True 104 105 Prepare image for later writing 106 107 >>> img5 = Image(np.zeros(2,3,4)) 108 >>> fp, fname2 = tempfile.mkstemp('.nii') 109 >>> img5.set_filespec(fname2) 110 >>> # then do some things to the image 111 >>> img5.save() 112 113 This is an example where you do need the io API 114 115 >>> from nibabel.ioimps import guessed_imp 116 >>> fp, fname3 = tempfile.mkstemp('.nii') 117 >>> ioimp = guessed_imp(fname3) 118 >>> ioimp.set_data_dtype(np.float64) 119 >>> ioimp.set_data_shape((2,3,4)) # set_data_shape method 120 >>> slice_def = (slice(None), slice(None), 0) 121 >>> ioimp.write_slice(data[slice_def], slice_def) # write_slice method 122 >>> slice_def = (2, 3, 1) 123 >>> ioimp.write_slice(data[slice_def], slice_def) # write_slice method 124 Traceback (most recent call last): 125 ... 126 ImageIOError: data write is not contiguous 127