Skip to content

Commit f9614fe

Browse files
committed
Merge pull request #415 from matthew-brett/viewer-tiny-edits
MRG: small docstring and import machinery edits Rewrite docstrings, including numpy docstring standard fixes, and a couple of typos (ah saggital, it looks right, but...). Stash conditional import of matplotlib at ``__init__`` to avoid having to repeat it in later methods.
2 parents 3f873a7 + e015699 commit f9614fe

File tree

1 file changed

+28
-26
lines changed

1 file changed

+28
-26
lines changed

nibabel/viewers.py

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,55 +14,59 @@
1414

1515

1616
class OrthoSlicer3D(object):
17-
"""Orthogonal-plane slicer.
17+
""" Orthogonal-plane slice viewer.
1818
19-
OrthoSlicer3d expects 3-dimensional data, and by default it creates a
20-
figure with 3 axes, one for each slice orientation.
19+
OrthoSlicer3d expects 3- or 4-dimensional array data. It treats
20+
4D data as a sequence of 3D spatial volumes, where a slice over the final
21+
array axis gives a single 3D spatial volume.
22+
23+
For 3D data, the default behavior is to create a figure with 3 axes, one
24+
for each slice orientation of the spatial volume.
2125
2226
Clicking and dragging the mouse in any one axis will select out the
2327
corresponding slices in the other two. Scrolling up and
2428
down moves the slice up and down in the current axis.
2529
26-
OrthoSlicer3d also supports 4-dimensional data, where multiple
27-
3-dimensional volumes are stacked along the last axis. For 4-dimensional
28-
data the fourth figure axis can be used to control which 3-dimensional
29-
volume is displayed. Alternatively, the - key can be used to decrement the
30-
displayed volume and the + or = keys can be used to increment it.
30+
For 4D data, the fourth figure axis can be used to control which
31+
3D volume is displayed. Alternatively, the ``-`` key can be used to
32+
decrement the displayed volume and the ``+`` or ``=`` keys can be used to
33+
increment it.
3134
3235
Example
3336
-------
3437
>>> import numpy as np
35-
>>> a = np.sin(np.linspace(0,np.pi,20))
36-
>>> b = np.sin(np.linspace(0,np.pi*5,20))
37-
>>> data = np.outer(a,b)[..., np.newaxis]*a
38+
>>> a = np.sin(np.linspace(0, np.pi, 20))
39+
>>> b = np.sin(np.linspace(0, np.pi*5, 20))
40+
>>> data = np.outer(a, b)[..., np.newaxis] * a
3841
>>> OrthoSlicer3D(data).show() # doctest: +SKIP
3942
"""
4043
# Skip doctest above b/c not all systems have mpl installed
44+
4145
def __init__(self, data, affine=None, axes=None, title=None):
4246
"""
4347
Parameters
4448
----------
4549
data : array-like
4650
The data that will be displayed by the slicer. Should have 3+
4751
dimensions.
48-
affine : array-like or None
52+
affine : array-like or None, optional
4953
Affine transform for the data. This is used to determine
50-
how the data should be sliced for plotting into the saggital,
54+
how the data should be sliced for plotting into the sagittal,
5155
coronal, and axial view axes. If None, identity is assumed.
5256
The aspect ratio of the data are inferred from the affine
5357
transform.
5458
axes : tuple of mpl.Axes or None, optional
5559
3 or 4 axes instances for the 3 slices plus volumes,
5660
or None (default).
57-
title : str or None
61+
title : str or None, optional
5862
The title to display. Can be None (default) to display no
5963
title.
6064
"""
61-
# Nest imports so that matplotlib.use() has the appropriate
62-
# effect in testing
63-
plt, _, _ = optional_package('matplotlib.pyplot')
64-
mpl_img, _, _ = optional_package('matplotlib.image')
65-
mpl_patch, _, _ = optional_package('matplotlib.patches')
65+
# Use these late imports of matplotlib so that we have some hope that
66+
# the test functions are the first to set the matplotlib backend. The
67+
# tests set the backend to something that doesn't require a display.
68+
self._plt = plt = optional_package('matplotlib.pyplot')[0]
69+
mpl_patch = optional_package('matplotlib.patches')[0]
6670
self._title = title
6771
self._closed = False
6872

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

199203
# actually set data meaningfully
200204
self._position = np.zeros(4)
201-
self._position[3] = 1. # convenience for affine multn
205+
self._position[3] = 1. # convenience for affine multiplication
202206
self._changing = False # keep track of status to avoid loops
203207
self._links = [] # other viewers this one is linked to
204-
plt.draw()
208+
self._plt.draw()
205209
for fig in self._figs:
206210
fig.canvas.draw()
207211
self._set_volume_index(0, update_slices=False)
@@ -220,16 +224,14 @@ def __repr__(self):
220224
def show(self):
221225
"""Show the slicer in blocking mode; convenience for ``plt.show()``
222226
"""
223-
plt, _, _ = optional_package('matplotlib.pyplot')
224-
plt.show()
227+
self._plt.show()
225228

226229
def close(self):
227230
"""Close the viewer figures
228231
"""
229232
self._cleanup()
230-
plt, _, _ = optional_package('matplotlib.pyplot')
231233
for f in self._figs:
232-
plt.close(f)
234+
self._plt.close(f)
233235

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

0 commit comments

Comments
 (0)