.. -*- mode: rst -*- .. ex: set sts=4 ts=4 sw=4 et tw=79: ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### # # See COPYING file distributed along with the PyNIfTI package for the # copyright and license terms. # ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ******** Examples ******** The next sections contains some examples showing ways to use PyNIfTI to read and write imaging data from within Python to be able to process it with some random Python library. All examples assume that you have imported the PyNIfTI module by invoking: >>> from nifti import * Loading and saving NIfTI files ============================== First we will open the tiny example NIfTI file that is included in the PyNIfTI source tarball. No filename extension is necessary as libniftiio determines it automatically: >>> nim = NiftiImage('example4d') The filename is available via the 'filename' attribute: >>> print nim.filename example4d.nii.gz This indicates a compressed NIfTI image. If you want to save this image as an uncompressed image simply do: >>> nim.save('something.nii') The filetype is determined from the filename. If you want to save to gzipped ANALYZE file pairs instead the following would be an alternative to calling the ``save()`` with a new filename: >>> nim.setFilename('analyze.img.gz') >>> nim.save() Please see the documentation of :meth:`~nifti.image.NiftiImage.setFilename` to learn how the filetypes are determined from the filenames. NIfTI files from array data =========================== The next code snipped demonstrates how to create a 4d NIfTI image containing gaussian noise. First we need to import the NumPy module >>> import numpy as N Now we generate the noise dataset. Let's generate noise for 100 volumes with 16 slices and a 32x32 inplane matrix. >>> noise = N.random.randn(100,16,32,32) Please notice the order in which the dimensions are specified: (t, z, y, x). The datatype of the array is by default `float64`, which can be verified by: >>> noise.dtype dtype('float64') Converting this dataset into a NIfTI image is done by invoking the :class:`~nifti.image.NiftiImage` constructor with the noise dataset as argument: >>> nim = NiftiImage(noise) The relevant header information is extracted from the NumPy array. If you query the header information about the dimensionality of the image, it returns the desired values: >>> print nim.header['dim'] [4, 32, 32, 16, 100, 1, 1, 1] First value shows the number of dimensions in the datset: 4 (good, that's what we wanted). The following numbers are dataset size on the x, y, z, t, u, v, w axis (NIfTI files can handle up to 7 dimensions). Please notice, that the order of dimensions is now 'correct': We have 32x32 inplane resolution, 16 slices in z direction and 100 volumes. Also the datatype was set appropriately: >>> import nifti.clib as ncl >>> nim.header['datatype'] == ncl.NIFTI_TYPE_FLOAT64 True To save the noise file to disk, we can simply call the :meth:`~nifti.image.NiftiImage.save` method: >>> nim.save('noise.nii.gz') Select ROIs =========== Suppose you want to have the first ten volumes of the noise dataset we have previously created in a separate file. First, we open the file: >>> nim = NiftiImage('noise.nii.gz') Now we select the first ten volumes and store them to another file, while preserving as much header information as possible >>> nim2 = NiftiImage(nim.data[:10], nim.header) >>> nim2.save('part.hdr.gz') The :class:`~nifti.image.NiftiImage` constructor takes a dictionary with header information as an optional argument. Settings that are not determined by the array (e.g. size, datatype) are taken from the dictionary and stored to the new NIfTI image. 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 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 (basically a linear function with some noise): >>> nim = NiftiImage( ... (N.linspace(0,100) + N.random.randn(50)).reshape(50,1,1,1)) >>> nim.timepoints 50 >>> nim.volextent (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). >>> from scipy import signal >>> data_detrended = signal.detrend(nim.data, axis=0) Finally, create a new NIfTI image using header information from the original source image. >>> nim_detrended = NiftiImage( data_detrended, nim.header) Make a quick plot of a voxel's timeseries (matplotlib module is required) ========================================================================= Plotting is essential to get a 'feeling' for the data. The Matlab-style plotting via matplotlib_ make it really easy to plot something with (e.g. when running Python interactively via IPython_). Please note, that there are many other possibilities for plotting, e.g. R_ via RPy_ or Gnuplot_ via the `Gnuplot python bindings`_ .. _R: http://www.r-project.org .. _RPy: http://rpy.sourceforge.net However, using matplotlib is really easy. For this example we will plot the two timeseries from the previous example, i.e. the raw and the detrended one. First we import the pylab module: >>> import pylab as P Now we can easly plot both timeseries of the single voxel in our artifical image: >>> line1 = P.plot(nim.data[:, 0, 0, 0]) >>> line2 = P.plot(nim_detrended.data[:, 0, 0, 0,]) A `P.show()` call would render the plot on the screen. .. _Gnuplot python bindings: http://gnuplot-py.sourceforge.net .. _Gnuplot: http://www.gnuplot.info .. _IPython: http://ipython.scipy.org .. _matplotlib: http://matplotlib.sourceforge.net .. _Gnuplot demos: http://gnuplot.sourceforge.net/demo_4.3/index.html Show a slice of a 3d volume (Matplotlib module is required) =========================================================== This example demonstrates howto use the Matlab-style plotting of matplotlib_ to view a slice from a 3d volume. We will actually use a 4D image as data source and limit us to the first volume: >>> nim = NiftiImage('example4d') >>> volume = nim.data[0] If everything went fine, we can now view a slice (x,y): >>> xyplot = P.imshow(volume[16], ... interpolation='nearest', ... cmap=P.cm.gray) Again a call to the `P.show()` function would render the plot on the screen. When you want to have a look at a yz-slice, NumPy array magic comes into play. >>> yzplot = P.imshow(volume[::-1,:,18], ... interpolation='nearest', ... cmap=P.cm.gray) The ``::-1`` notation causes the z-axis to be flipped in the images. This makes a much nicer view, if the used example volume has the z-axis originally oriented upsidedown. Compute and display peristimulus signal timecourse of multiple conditions ========================================================================= Sometimes one wants to look at the signal timecourse of some voxel after a certain stimulation onset. An easy way would be to have some fMRI data viewer that displays a statistical map and one could click on some activated voxel and the peristimulus signal timecourse of some condition in that voxel would be displayed. This can easily be done by using ``pynifti_pst`` and ``FSLView``. ``pynifti_pst`` comes with a manpage that explains all options and arguments. Basically ``pynifti_pst`` needs a 4d image (e.g. an fMRI timeseries; possibly preprocessed/filtered) and some stimulus onset information. This information can either be given directly on the command line or is read from files. Additionally one can specify onsets as volume numbers or as onset times. ``pynifti_pst`` understands the FSL custom EV file format so one can easily use those files as input. An example call could look like this:: pynifti_pst --times --nvols 5 -p uf92.feat/filtered_func_data.nii.gz \ pst_cond_a.nii.gz uf92.feat/custom_timing_files/ev1.txt \ uf92.feat/custom_timing_files/ev2.txt This computes a peristimulus timeseries using the preprocessed fMRI from a FEAT output directory and two custom EV files that both together make up condition A. ``--times`` indicates that the EV files list onset times (not volume ids) and ``--nvols`` requests the mean peristimulus timecourse for 4 volumes after stimulus onset (5 including onset). ``-p`` recodes the peristimulus timeseries into percent signalchange, where the onset is always zero and any following value is the signal change with respect to the onset volume. .. figure:: pics/fslview_pst.png FSLView with ``pynifti_pst`` example. This call produces a simple 4d NIfTI image that can be loaded into FSLView as any other timeseries. The following call can be used to display an FSL zmap from the above results path on top of some anatomy. Additionally the peristimulus timeseries of two conditions are loaded. The figure shows how it could look like. One of the nice features of FSLView is that its timeseries window can remember selected curves, which can be useful to compare signal timecourses from different voxels (blue and green line in the figure).