Overhaul imshow to clarify flow

This commit is contained in:
Juan Nunez-Iglesias
2015-01-15 22:25:41 +11:00
parent 30c522e706
commit 2bdd239496
+103 -30
View File
@@ -1,3 +1,4 @@
from collections import namedtuple
import numpy as np
import warnings
import matplotlib.pyplot as plt
@@ -9,6 +10,106 @@ _nonstandard_colormap = 'cubehelix'
_diverging_colormap = 'RdBu'
ImageProperties = namedtuple('ImageProperties',
['signed', 'out_of_range_float',
'low_dynamic_range', 'unsupported_dtype'])
def _get_image_properties(image):
"""Determine nonstandard properties of an input image.
Parameters
----------
image : array
The input image.
Returns
-------
ip : ImageProperties named tuple
The properties of the image:
- signed: whether the image has negative values.
- out_of_range_float: if the image has floating point data
outside of [-1, 1].
- low_dynamic_range: if the image is in the standard image
range (e.g. [0, 1] for a floating point image) but its
dynamic range would be too small to display with standard
image ranges.
- unsupported_dtype: if the image data type is not a
standard skimage type, e.g. ``numpy.uint64``.
"""
immin, immax = np.min(image), np.max(image)
imtype = image.dtype.type
try:
lo, hi = dtypes.dtype_range[imtype]
except KeyError:
lo, hi = immin, immax
signed = immin < 0
out_of_range_float = (np.issubdtype(image.dtype, np.float) and
(immin < lo or immax > hi))
low_dynamic_range = (immin != immax and
(float(immax - immin) / (hi - lo)) < (1. / 255))
unsupported_dtype = image.dtype not in dtypes._supported_types
ip = ImageProperties(signed, out_of_range_float,
low_dynamic_range, unsupported_dtype)
return ip
def _raise_warnings(image_properties):
"""Raise the appropriate warning for each nonstandard image type.
Parameters
----------
image_properties : ImageProperties named tuple
The properties of the considered image.
"""
ip = image_properties
if ip.unsupported_dtype:
warnings.warn("Non-standard image type; displaying image with "
"stretched contrast.")
if ip.low_dynamic_range:
warnings.warn("Low image dynamic range; displaying image with "
"stretched contrast.")
if ip.out_of_range_float:
warnings.warn("Float image out of standard range; displaying image "
"with stretched contrast.")
def _get_display_range(image):
"""Return the display range for a given set of image properties.
Parameters
----------
image : array
The input image.
Returns
-------
lo, hi : same type as immin, immax
The display range to be used for the input image.
cmap : string
The name of the colormap to use.
"""
ip = _get_image_properties(image)
immin, immax = np.min(image), np.max(image)
if ip.signed:
magnitude = max(abs(immin), abs(immax))
lo, hi = -magnitude, magnitude
cmap = _diverging_colormap
elif any(ip):
_raise_warnings(ip)
lo, hi = immin, immax
cmap = _nonstandard_colormap
else:
lo = 0
imtype = image.dtype.type
hi = dtypes.dtype_range[imtype][1]
cmap = _default_colormap
return lo, hi, cmap
def imshow(im, *args, **kwargs):
"""Show the input image and return the current axes.
@@ -37,41 +138,13 @@ def imshow(im, *args, **kwargs):
"""
if plt.gca().has_data():
plt.figure()
immin, immax = np.min(im), np.max(im)
lo, hi = immin, immax
cmap = _default_colormap
supported_dtype = im.dtype in dtypes._supported_types
if supported_dtype:
lo, hi = dtypes.dtype_range[im.dtype.type]
# for nonnegative float images, ensure lower bound is 0, not -1
if immin > 0:
lo = 0
# for signed images, show diverging colormap centered at 0
else:
cmap = _diverging_colormap
magnitude = max(-immin, abs(immax))
lo, hi = -magnitude, magnitude
else:
warnings.warn("Non-standard image type; displaying image with "
"stretched contrast.")
out_of_range_float = (np.issubdtype(im.dtype, np.float) and
(immin < lo or immax > hi))
if out_of_range_float:
warnings.warn("Float image out of standard range; displaying image "
"with stretched contrast.")
low_dynamic_range = (immin != immax and
(float(immax - immin) / (hi - lo)) < (1. / 255))
if low_dynamic_range:
warnings.warn("Low image dynamic range; displaying image with "
"stretched contrast.")
if not supported_dtype or out_of_range_float or low_dynamic_range:
cmap = _nonstandard_colormap
lo, hi, cmap = _get_display_range(im)
kwargs.setdefault('interpolation', 'nearest')
kwargs.setdefault('cmap', cmap)
kwargs.setdefault('vmin', lo)
kwargs.setdefault('vmax', hi)
ax_im = plt.imshow(im, *args, **kwargs)
if not supported_dtype or out_of_range_float or low_dynamic_range:
if cmap != _default_colormap:
plt.colorbar()
return ax_im