# Visualization of 3D and 4D image data: problem with spacing between subplots in grid plot

Dear matplotlib users,

I have to visualize 3 and 4 dimensional images and overlay on top some data
(e.g. masks, tracking results, etc). I need a solution to explore (e.g.
visualize inline in IPython) and to present my results (e.g. insert pdf
into slides). I wrote a few functions using matplotlib and I can plot a
sequence of projections of 3-D volumes:

[image: Inline image 1]

However, as you can see there is a problem with spacing near projections
which makes the plot look not so nice. In ideal case I would like to have
the same spacing between x- and y-projections and corresponding
z-projection. I spend quite a lot of time trying to figure out how to do
that with matplotlib APIs, but I still haven't found a solution. I would
highly appreciate if you could help.

I also posted this question on stackoverflow:
http://stackoverflow.com/questions/34124267/visualize-3d-and-4d-image-data-in-python

My full code is also available on Github:
https://github.com/DSamuylov/imagend

Minimal code to reproduce the problem is bellow.

Best regards,
Denis

import mathimport numpy as npimport matplotlib.cm as cmimport
matplotlib.pyplot as pltimport matplotlib.gridspec as gridspec

def project_image_stack(img, figwidth=3, axes=None):
dim = len(img.shape)
assert dim == 3
n_slices, n_h, n_w = img.shape

figheight = (figwidth)*np.float64(n_h + n_slices)/(n_w + n_slices)

z_proj = np.mean(img, axis=0)
y_proj = np.mean(img, axis=1)
x_proj = np.mean(img, axis=2).T

if axes is None:
# Create figure
fig = plt.figure(figsize=(figwidth, figheight))
gs = gridspec.GridSpec(2, 2, width_ratios=[n_w, n_slices],
height_ratios=[n_h, n_slices])
gs.update(wspace=0.05, hspace=0.05, bottom=0, top=1, left=0, right=1)
# Create axes:
else:
assert len(axes) == 3
fig = None
ax_z, ax_y, ax_x = axes
# z projection:
ax_z.imshow(z_proj, interpolation='nearest', cmap=cm.gray, aspect=1)
ax_z.set_xlim([-0.5, n_w - 0.5])
ax_z.set_ylim([n_h - 0.5, -0.5])
ax_z.axis('off')
# y projection:
ax_y.imshow(y_proj, interpolation='nearest', cmap=cm.gray, aspect=1)
ax_y.set_xlim([-0.5, n_w-0.5])
ax_y.set_ylim([n_slices-0.5, -0.5])
ax_y.axis('off')
# x projection:
ax_x.imshow(x_proj, interpolation='nearest', cmap=cm.gray, aspect=1)
ax_x.set_xlim([-0.5, n_slices-0.5])
ax_x.set_ylim([n_h-0.5, -0.5])
ax_x.axis('off')

return fig, (ax_z, ax_y, ax_x)

def project_image_sequence(img_sequence, subfigwidth=3, ncol=5):
dim = len(img_sequence.shape)
assert dim == 4
n_frames, n_slices, n_h, n_w = img_sequence.shape

frames = range(0, n_frames)
n_subfig = len(frames)

# Initialize parameters
nrow = int(math.ceil(float(n_subfig)/ncol))
height_subfig = (n_h + n_slices)*np.float64(subfigwidth)/(n_w + n_slices)

# Initialize the figure
fig = plt.figure(figsize=(subfigwidth*ncol, height_subfig*nrow))

# Initialize the layout
gs_master = gridspec.GridSpec(nrow, ncol)
gs_master.update(bottom=0, top=1, left=0, right=1)

# Magic for every (sub-)gridspec:
wspace = 0.05 # [in]
hspace = wspace*float(n_w + n_slices)/(n_h + n_slices)

axes = []
for i in range(nrow):
for j in range(ncol):
ind = i*ncol + j
if ind >= n_subfig:
break

gs = gridspec.GridSpecFromSubplotSpec(
2, 2,
width_ratios=[n_w, n_slices],
height_ratios=[n_h, n_slices],
subplot_spec=gs_master[i, j],
wspace=wspace, hspace=hspace,
)

ax_z = plt.Subplot(fig, gs[0, 0])
ax_z.set_title('frame={}'.format(frames[ind]))
ax_y = plt.Subplot(fig, gs[1, 0], sharex=ax_z)
ax_x = plt.Subplot(fig, gs[0, 1], sharey=ax_z)

project_image_stack(img_sequence[frames[ind]],
axes=[ax_z, ax_y, ax_x])
axes.append((ax_z, ax_y, ax_x))
return fig, axes

if __name__ == "__main__":
image_sequence = np.random.rand(5, 20, 30, 40)
fig, axes = project_image_sequence(image_sequence)
fig.savefig("min_example.png", bbox_inches='tight')
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20151207/b70efaef/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sequence_of_projections.png
Type: image/png
Size: 41734 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20151207/b70efaef/attachment-0001.png>