Skip to content

Commit 4d47d5a

Browse files
committed
FIX: Clean up code
1 parent ba1243e commit 4d47d5a

File tree

3 files changed

+60
-23
lines changed

3 files changed

+60
-23
lines changed

nibabel/spatialimages.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ def __getitem__(self):
663663
"array data with `img.dataobj[slice]` or "
664664
"`img.get_data()[slice]`")
665665

666-
def plot(self):
666+
def orthoview(self):
667667
"""Plot the image using OrthoSlicer3D
668668
669669
Returns
@@ -677,5 +677,5 @@ def plot(self):
677677
consider using viewer.show() (equivalently plt.show()) to show
678678
the figure.
679679
"""
680-
return OrthoSlicer3D(self.get_data(), self.get_affine(),
680+
return OrthoSlicer3D(self.dataobj, self.affine,
681681
title=self.get_filename())

nibabel/tests/test_viewers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def test_viewer():
4848
v._on_mouse(nt('event', 'xdata ydata inaxes button')(0.5, 0.5, ax, 1))
4949
v._on_mouse(nt('event', 'xdata ydata inaxes button')(0.5, 0.5, None, None))
5050
v.set_volume_idx(1)
51+
v.cmap = 'hot'
5152

5253
# decrement/increment volume numbers via keypress
5354
v.set_volume_idx(1) # should just pass
@@ -75,11 +76,13 @@ def test_viewer():
7576
# other cases
7677
fig, axes = plt.subplots(1, 4)
7778
plt.close(fig)
78-
v1 = OrthoSlicer3D(data, pcnt_range=[0.1, 0.9], axes=axes)
79+
v1 = OrthoSlicer3D(data, axes=axes)
7980
aff = np.array([[0, 1, 0, 3], [-1, 0, 0, 2], [0, 0, 2, 1], [0, 0, 0, 1]],
8081
float)
8182
v2 = OrthoSlicer3D(data, affine=aff, axes=axes[:3])
83+
# bad data (not 3+ dim)
8284
assert_raises(ValueError, OrthoSlicer3D, data[:, :, 0, 0])
85+
# bad affine (not 4x4)
8386
assert_raises(ValueError, OrthoSlicer3D, data, affine=np.eye(3))
8487
assert_raises(TypeError, v2.link_to, 1)
8588
v2.link_to(v1)

nibabel/viewers.py

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import numpy as np
99
import weakref
1010

11+
from .affines import voxel_sizes
1112
from .optpkg import optional_package
1213
from .orientations import aff2axcodes, axcodes2ornt
1314

@@ -37,29 +38,25 @@ class OrthoSlicer3D(object):
3738
>>> OrthoSlicer3D(data).show() # doctest: +SKIP
3839
"""
3940
# Skip doctest above b/c not all systems have mpl installed
40-
def __init__(self, data, affine=None, axes=None, cmap='gray',
41-
pcnt_range=(1., 99.), figsize=(8, 8), title=None):
41+
def __init__(self, data, affine=None, axes=None, title=None):
4242
"""
4343
Parameters
4444
----------
45-
data : ndarray
45+
data : array-like
4646
The data that will be displayed by the slicer. Should have 3+
4747
dimensions.
48-
affine : array-like | None
48+
affine : array-like or None
4949
Affine transform for the data. This is used to determine
5050
how the data should be sliced for plotting into the saggital,
5151
coronal, and axial view axes. If None, identity is assumed.
5252
The aspect ratio of the data are inferred from the affine
5353
transform.
54-
axes : tuple of mpl.Axes | None, optional
54+
axes : tuple of mpl.Axes or None, optional
5555
3 or 4 axes instances for the 3 slices plus volumes,
5656
or None (default).
57-
cmap : str | instance of cmap, optional
58-
String or cmap instance specifying colormap.
59-
pcnt_range : array-like, optional
60-
Percentile range over which to scale image for display.
61-
figsize : tuple
62-
Figure size (in inches) to use if axes are None.
57+
title : str or None
58+
The title to display. Can be None (default) to display no
59+
title.
6360
"""
6461
# Nest imports so that matplotlib.use() has the appropriate
6562
# effect in testing
@@ -75,21 +72,21 @@ def __init__(self, data, affine=None, axes=None, cmap='gray',
7572
if np.iscomplexobj(data):
7673
raise TypeError("Complex data not supported")
7774
affine = np.array(affine, float) if affine is not None else np.eye(4)
78-
if affine.ndim != 2 or affine.shape != (4, 4):
75+
if affine.shape != (4, 4):
7976
raise ValueError('affine must be a 4x4 matrix')
8077
# determine our orientation
81-
self._affine = affine.copy()
78+
self._affine = affine
8279
codes = axcodes2ornt(aff2axcodes(self._affine))
8380
self._order = np.argsort([c[0] for c in codes])
8481
self._flips = np.array([c[1] < 0 for c in codes])[self._order]
8582
self._flips = list(self._flips) + [False] # add volume dim
86-
self._scalers = np.abs(self._affine).max(axis=0)[:3]
83+
self._scalers = voxel_sizes(self._affine)
8784
self._inv_affine = np.linalg.inv(affine)
8885
# current volume info
8986
self._volume_dims = data.shape[3:]
9087
self._current_vol_data = data[:, :, :, 0] if data.ndim > 3 else data
9188
self._data = data
92-
vmin, vmax = np.percentile(data, pcnt_range)
89+
self._clim = np.percentile(data, (1., 99.))
9390
del data
9491

9592
if axes is None: # make the axes
@@ -111,7 +108,7 @@ def __init__(self, data, affine=None, axes=None, cmap='gray',
111108
# <-- R <-- t -->
112109

113110
fig, axes = plt.subplots(2, 2)
114-
fig.set_size_inches(figsize, forward=True)
111+
fig.set_size_inches((8, 8), forward=True)
115112
self._axes = [axes[0, 0], axes[0, 1], axes[1, 0], axes[1, 1]]
116113
plt.tight_layout(pad=0.1)
117114
if self.n_volumes <= 1:
@@ -132,14 +129,14 @@ def __init__(self, data, affine=None, axes=None, cmap='gray',
132129
r = [self._scalers[self._order[2]] / self._scalers[self._order[1]],
133130
self._scalers[self._order[2]] / self._scalers[self._order[0]],
134131
self._scalers[self._order[1]] / self._scalers[self._order[0]]]
135-
self._sizes = [self._data.shape[o] for o in self._order]
132+
self._sizes = [self._data.shape[order] for order in self._order]
136133
for ii, xax, yax, ratio, label in zip([0, 1, 2], [1, 0, 0], [2, 2, 1],
137134
r, ('SAIP', 'SLIR', 'ALPR')):
138135
ax = self._axes[ii]
139136
d = np.zeros((self._sizes[yax], self._sizes[xax]))
140-
im = self._axes[ii].imshow(d, vmin=vmin, vmax=vmax, aspect=1,
141-
cmap=cmap, interpolation='nearest',
142-
origin='lower')
137+
im = self._axes[ii].imshow(
138+
d, vmin=self._clim[0], vmax=self._clim[1], aspect=1,
139+
cmap='gray', interpolation='nearest', origin='lower')
143140
self._ims.append(im)
144141
vert = ax.plot([0] * 2, [-0.5, self._sizes[yax] - 0.5],
145142
color=(0, 1, 0), linestyle='-')[0]
@@ -240,6 +237,11 @@ def _cleanup(self):
240237
for link in list(self._links): # make a copy before iterating
241238
self._unlink(link())
242239

240+
def draw(self):
241+
"""Redraw the current image"""
242+
for fig in self._figs:
243+
fig.canvas.draw()
244+
243245
@property
244246
def n_volumes(self):
245247
"""Number of volumes in the data"""
@@ -250,6 +252,38 @@ def position(self):
250252
"""The current coordinates"""
251253
return self._position[:3].copy()
252254

255+
@property
256+
def figs(self):
257+
"""A tuple of the figure(s) containing the axes"""
258+
return tuple(self._figs)
259+
260+
@property
261+
def cmap(self):
262+
"""The current colormap"""
263+
return self._cmap
264+
265+
@cmap.setter
266+
def cmap(self, cmap):
267+
for im in self._ims:
268+
im.set_cmap(cmap)
269+
self._cmap = cmap
270+
self.draw()
271+
272+
@property
273+
def clim(self):
274+
"""The current color limits"""
275+
return self._clim
276+
277+
@clim.setter
278+
def clim(self, clim):
279+
clim = np.array(clim, float)
280+
if clim.shape != (2,):
281+
raise ValueError('clim must be a 2-element array-like')
282+
for im in self._ims:
283+
im.set_clim(clim)
284+
self._clim = tuple(clim)
285+
self.draw()
286+
253287
def link_to(self, other):
254288
"""Link positional changes between two canvases
255289

0 commit comments

Comments
 (0)