# Reshaping, 4D to 2D#

See also: Reshaping 4D images to 2D arrays.

```
import numpy as np
```

## Revision on 3D#

We often find ourselves doing complicated reshape operations when we are dealing with images. For example, we may find ourselves reshaping the first few dimensions, but leaving the last intact.

Let’s start with a familiar 3D array:

```
arr_3d = np.reshape(np.arange(24), (2, 3, 4))
arr_3d
```

```
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
```

As ever, Numpy shows us the array by *row*, where each row is a 3 by 4 slab of
columns by plane. Here is a picture of the same array represented as planes
of 2D row by column arrays:

Notice that Numpy has filled in the 3D array in the order *last* axis to *first* axis, therefore:

plane, then

column, then

row.

Now imagine that we want to reshape only the first two dimensions, leaving the last the same. This will take us from an array of shape (2, 3, 4), to an array of shape (6, 4). The procedure is the same for all reshapes in NumPy. NumPy makes an output array shape (6, 4), then takes each element over the last dimension in the input, and fills the last dimension of the output, moves one across on the second dimension of the input, then fills a line in the first dimension of the output, and so on.

```
arr_2d = np.reshape(arr_3d, (6, 4))
arr_2d
```

```
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]])
```

Notice how Numpy has filled out the two-dimensional array - by *getting* the data in the order *last* axis to *first* axis, so:

plane, then

column, then

row

It therefore *gets* the original `np.arange(24)`

array, and then *sets* the
data into the new array in the order last axis to first, therefore:

column, then

row.

See also: Reshaping and three-dimensional arrays.

## To 4D#

This kind of operation is commonly used on image data arrays. Here we have
a 4D array from an fMRI run (`ds114_sub009_t2r1.nii`

):

```
# Fetch the data file to this computer.
import nipraxis
bold_fname = nipraxis.fetch_file('ds114_sub009_t2r1.nii')
# Show the filename
bold_fname
```

```
'/home/runner/.cache/nipraxis/0.5/ds114_sub009_t2r1.nii'
```

```
import nibabel as nib
img = nib.load(bold_fname)
data = img.get_fdata()
data.shape
```

```
(64, 64, 30, 173)
```

We can think of the 4D array as a sequence of 3D volumes:

```
vol_shape = data.shape[:-1]
vol_shape
```

```
(64, 64, 30)
```

To get the number of voxels in the volume, we can use the `np.prod`

function on the shape. `np.prod`

is like `np.sum`

, but instead of adding
the elements, it multiplies them:

```
n_voxels = np.prod(vol_shape)
n_voxels
```

```
122880
```

Then we can reshape the array to 2D, with voxels on the first axis, and time (volume) on the second.

```
voxel_by_time = np.reshape(data, (n_voxels, data.shape[-1]))
voxel_by_time.shape
```

```
(122880, 173)
```

This is a useful operation when we want to apply some processing on all voxels, without regard to their relative spatial position.