\(\newcommand{L}[1]{\| #1 \|}\newcommand{VL}[1]{\L{ \vec{#1} }}\newcommand{R}[1]{\operatorname{Re}\,(#1)}\newcommand{I}[1]{\operatorname{Im}\, (#1)}\)

# Slice timing exercise¶

- For code template see:
`slice_timing_code.py`

; - For solution see: Slice timing exercise.

See: slice timing correction for the background to this exercise.

```
>>> #: Import common modules
>>> import numpy as np # the Python array package
>>> np.set_printoptions(precision=4, suppress=True) # print to 4 DP
>>> import matplotlib.pyplot as plt # the Python plotting package
>>> import nibabel as nib
```

```
>>> #: Set defaults for plotting
>>> plt.rcParams['image.cmap'] = 'gray'
>>> plt.rcParams['image.interpolation'] = 'nearest'
```

Load the image `ds114_sub009_t2r1.nii`

with nibabel. Get the data:

```
>>> #: Load the image 'ds114_sub009_t2r1.nii' with nibabel
>>> # Get the data array from the image
>>> import nibabel as nib
>>> img = nib.load('ds114_sub009_t2r1.nii')
>>> data = img.get_data()
>>> data.shape
(64, 64, 30, 173)
```

As you remember, the first volume in this dataset is a lot different from the rest, and this will mess up our interpolation in time.

So, we need to remove the first volume from the data first, using slicing:

```
>>> #: Remove the first volume by slicing
>>> fixed_data = data[..., 1:]
>>> fixed_data.shape
(64, 64, 30, 172)
```

We start off with example time-courses from the first and second slice.

Use slicing to get a z slice 0 time series for an example voxel at voxel coordinates (23, 19, 0).

Do the same for a z slice 1 time series from (23, 19, 1).

Plot these time series against volume number on the same graph:

```
>>> #- Slice out time series for voxel (23, 19, 0)
>>> #- Slice out time series for voxel (23, 19, 1)
>>> #- Plot both these time series against volume number, on the same graph
```

The scanner collected slices for these data in an “ascending interleaved” order. That is, the scanner first collected z slice 0, then z slice 2, up to z slice 28. It then went back to collect z slice 1, 3, 5 up to z slice 29.

That means the scanner started collecting slice 0 in each volume, at the beginning of the volume.

The TR (time to collect one volume) is 2.5 seconds.

```
>>> #: The time between scans
>>> TR = 2.5
```

Make a time vector, length 172, that corresponds to the start time in seconds of each volume. This also gives the slice 0 start times.

```
>>> #- Make time vector containing start times in second of each volume,
>>> #- relative to start of first volume.
>>> #- Call this `slice_0_times`
```

The scanner starts to collect z slice 1 exactly half way through the volume (half way through the TR). Make a new vector that is the start time of acquisition of slice 1.

```
>>> #- Make time vector containing start times in seconds of z slice 1,
>>> #- relative to start of first volume.
>>> #- Call this `slice_1_times`
```

Now plot the first 10 values for the slice 0 times, against the first 10 values of the slice 0 time series.

Do the same plot for the first 10 values of the slice 1 times, against the first 10 values of the slice 1 time series.

Use the `:+`

line marker for the plots to get the actual position of the
points, and dotted lines between them.

```
>>> #- Plot first 10 values of slice 0 times against first 10 of slice 0
>>> #- time series;
>>> #- Plot first 10 values of slice 1 times against first 10 of slice 1
>>> #- time series.
>>> #- Use ':+' marker
```

Import `InterpolatedUnivariateSpline`

from `scipy.interpolate`

. Make a new
linear (`k=1`

) interpolation object for slice 1, with the slice 1 times and
values.

```
>>> #- Import `InterpolatedUnivariateSpline` from `scipy.interpolate`
>>> #- Make a new linear (`k=1`) interpolation object for slice 1, with
>>> #- slice 1 times and values.
```

Call the object you got with the slice 0 times, to get the estimated time series values for slice 1, if slice 1 had been collected at the same time as slice 0:

```
>>> #- Call interpolator with `slice_0_times` to get estimated values
```

Repeat the plot of the first 10 values of the time series. This time, on the
same plot, add the estimated values for slice 1, if they had been collected at
the same time as slice 0. Use a black `x`

for the estimated points (marker
`'kx'`

):

```
>>> #- Plot first 10 values of slice 0 times against first 10 of slice 0
>>> #- time series;
>>> #- Plot first 10 values of slice 1 times against first 10 of slice 1
>>> #- time series;
>>> #- Plot first 10 values of slice 0 times against first 10 of
>>> #- interpolated slice 1 time series.
```

Use numpy to make a new copy of the data matrix. This will contain the slice time corrected values for all voxels. Copying the data matrix will give us the data we want for slice 0, because we want to keep the values for z slice 0 unchanged. We need to make a copy of the array to make sure we do not overwrite the original data.

```
>>> #- Copy old data to a new array
```

Loop over every x voxel coordinate, and then loop over every y voxel coordinate.

For each x, y voxel coordinate:

- extract the time series at this x, y coordinate for slice 1;
- make a linear interpolator object with the slice 1 times and the extracted time series;
- resample this interpolator at the slice 0 times;
- put this new resampled time series into the new data at the same position.

```
>>> #- loop over all x coordinate values
>>> #- loop over all y coordinate values
>>> #- extract the time series at this x, y coordinate for slice 1;
>>> #- make a linear interpolator object with the slice 1 times and the
>>> #- extracted time series;
>>> #- resample this interpolator at the slice 0 times;
>>> #- put this new resampled time series into the new data at the same
>>> #- position.
```

Now we need to do the same thing for all the z slices.

To do this, we want to construct an offset vector (call it `time_offset`

) of
length (number of z slices) such that adding the `time_offset[z]`

to the
acquisition time of the first slice will give us the time of acquisition of
slice `z`

. The next few steps are to get to that `time_offset`

vector.

First, make a new vector `acquisition_order`

that is length 30, where
`acquisition_order[i]`

is the order of acquisition of slice index `i`

. For
example, the first 4 elements of `acqusition_order`

should be 0, 15, 1, 16.

```
>>> #- Make acquisition_order vector, length 30, with values:
>>> #- 0, 15, 1, 16 ... 14, 29
```

Divide the acquisition order vector by number of slices, and multiply by the TR, to get the time offset for each z slice, relative to the start of the scan:

```
>>> #- Divide acquisition_order by number of slices, multiply by TR
```

Now we can do our whole slice time correction, for every slice.

For each z coordinate (slice index):

Make a time vector by adding the slice time offset for this slice, to the

`slice_0`

times. Call this the`slice_z_times`

vector;For each x coordinate:

For each y coordinate:

- extract the time series at this x, y, z coordinate;
- make a linear interpolator object with the
`slice_z_times`

and the extracted time series; - resample this interpolator at the slice 0 times;
- put this new resampled time series into the new data at the same position

```
>>> #- For each z coordinate (slice index):
>>> #- # Make `slice_z_times` vector for this slice
>>> #- ## For each x coordinate:
>>> #- ### For each y coordinate:
>>> #- #### extract the time series at this x, y, z coordinate;
>>> #- #### make a linear interpolator object with the `slice_z_times` and
>>> #- the extracted time series;
>>> #- #### resample this interpolator at the slice 0 times;
>>> #- #### put this new resampled time series into the new data at the
>>> #- same position
```

Congratulations - you have just done slice timing correction on this 4D image.