Skip to content

RF: small docstring and import machinery edits #415

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 28 additions & 26 deletions nibabel/viewers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,55 +14,59 @@


class OrthoSlicer3D(object):
"""Orthogonal-plane slicer.
""" Orthogonal-plane slice viewer.

OrthoSlicer3d expects 3-dimensional data, and by default it creates a
figure with 3 axes, one for each slice orientation.
OrthoSlicer3d expects 3- or 4-dimensional array data. It treats
4D data as a sequence of 3D spatial volumes, where a slice over the final
array axis gives a single 3D spatial volume.

For 3D data, the default behavior is to create a figure with 3 axes, one
for each slice orientation of the spatial volume.

Clicking and dragging the mouse in any one axis will select out the
corresponding slices in the other two. Scrolling up and
down moves the slice up and down in the current axis.

OrthoSlicer3d also supports 4-dimensional data, where multiple
3-dimensional volumes are stacked along the last axis. For 4-dimensional
data the fourth figure axis can be used to control which 3-dimensional
volume is displayed. Alternatively, the - key can be used to decrement the
displayed volume and the + or = keys can be used to increment it.
For 4D data, the fourth figure axis can be used to control which
3D volume is displayed. Alternatively, the ``-`` key can be used to
decrement the displayed volume and the ``+`` or ``=`` keys can be used to
increment it.

Example
-------
>>> import numpy as np
>>> a = np.sin(np.linspace(0,np.pi,20))
>>> b = np.sin(np.linspace(0,np.pi*5,20))
>>> data = np.outer(a,b)[..., np.newaxis]*a
>>> a = np.sin(np.linspace(0, np.pi, 20))
>>> b = np.sin(np.linspace(0, np.pi*5, 20))
>>> data = np.outer(a, b)[..., np.newaxis] * a
>>> OrthoSlicer3D(data).show() # doctest: +SKIP
"""
# Skip doctest above b/c not all systems have mpl installed

def __init__(self, data, affine=None, axes=None, title=None):
"""
Parameters
----------
data : array-like
The data that will be displayed by the slicer. Should have 3+
dimensions.
affine : array-like or None
affine : array-like or None, optional
Affine transform for the data. This is used to determine
how the data should be sliced for plotting into the saggital,
how the data should be sliced for plotting into the sagittal,
coronal, and axial view axes. If None, identity is assumed.
The aspect ratio of the data are inferred from the affine
transform.
axes : tuple of mpl.Axes or None, optional
3 or 4 axes instances for the 3 slices plus volumes,
or None (default).
title : str or None
title : str or None, optional
The title to display. Can be None (default) to display no
title.
"""
# Nest imports so that matplotlib.use() has the appropriate
# effect in testing
plt, _, _ = optional_package('matplotlib.pyplot')
mpl_img, _, _ = optional_package('matplotlib.image')
mpl_patch, _, _ = optional_package('matplotlib.patches')
# Use these late imports of matplotlib so that we have some hope that
# the test functions are the first to set the matplotlib backend. The
# tests set the backend to something that doesn't require a display.
self._plt = plt = optional_package('matplotlib.pyplot')[0]
mpl_patch = optional_package('matplotlib.patches')[0]
self._title = title
self._closed = False

Expand Down Expand Up @@ -198,10 +202,10 @@ def __init__(self, data, affine=None, axes=None, title=None):

# actually set data meaningfully
self._position = np.zeros(4)
self._position[3] = 1. # convenience for affine multn
self._position[3] = 1. # convenience for affine multiplication
self._changing = False # keep track of status to avoid loops
self._links = [] # other viewers this one is linked to
plt.draw()
self._plt.draw()
for fig in self._figs:
fig.canvas.draw()
self._set_volume_index(0, update_slices=False)
Expand All @@ -220,16 +224,14 @@ def __repr__(self):
def show(self):
"""Show the slicer in blocking mode; convenience for ``plt.show()``
"""
plt, _, _ = optional_package('matplotlib.pyplot')
plt.show()
self._plt.show()

def close(self):
"""Close the viewer figures
"""
self._cleanup()
plt, _, _ = optional_package('matplotlib.pyplot')
for f in self._figs:
plt.close(f)
self._plt.close(f)

def _cleanup(self):
"""Clean up before closing"""
Expand Down Expand Up @@ -377,7 +379,7 @@ def _set_position(self, x, y, z, notify=True):
for ii, (size, idx) in enumerate(zip(self._sizes, idxs)):
self._data_idx[ii] = max(min(int(round(idx)), size - 1), 0)
for ii in range(3):
# saggital: get to S/A
# sagittal: get to S/A
# coronal: get to S/L
# axial: get to A/L
data = np.take(self._current_vol_data, self._data_idx[ii],
Expand Down