From fac8fde9dca1b2c37f5615468944d44c6e826e19 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Mon, 15 Dec 2014 21:41:11 +1100 Subject: [PATCH] Overhaul matplotlib imshow plugin - images are displayed within their native dtype range, - unless they are outside of their range (e.g. a float image with values greater than 1) or they are of an unsupported dtype (e.g. a uint64 image), in which case the dynamic range of the display corresponds to the image range, - which is also done for images with extremely low contrast for their native range (e.g. float images in [1e-7, 5e-7]. In the latter two cases, a colorbar is also displayed and a warning is raised. Finally, we return the axes object on which the image is plotted, to enable further plotting in the matplotlib new OO style. --- skimage/io/_io.py | 2 +- skimage/io/_plugins/matplotlib_plugin.py | 41 +++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/skimage/io/_io.py b/skimage/io/_io.py index 06da7adb..646369bd 100644 --- a/skimage/io/_io.py +++ b/skimage/io/_io.py @@ -193,7 +193,7 @@ def show(): >>> import skimage.io as io >>> for i in range(4): - ... io.imshow(np.random.rand(50, 50)) + ... ax = io.imshow(np.random.rand(50, 50)) >>> io.show() # doctest: +SKIP ''' diff --git a/skimage/io/_plugins/matplotlib_plugin.py b/skimage/io/_plugins/matplotlib_plugin.py index 4aa0b7f1..a65f8cf0 100644 --- a/skimage/io/_plugins/matplotlib_plugin.py +++ b/skimage/io/_plugins/matplotlib_plugin.py @@ -1,9 +1,21 @@ +import numpy as np +import warnings import matplotlib.pyplot as plt +from skimage.util import dtype as dtypes def imshow(im, *args, **kwargs): """Show the input image and return the current axes. + Images are assumed to have standard range for their type. For + example, if a floating point image has values in [0, 0.5], the + most intense color will be gray50, not white, as would be the + default in matplotlib. + + In contrast, if the image exceeds the standard range, this + function defaults back to displaying exactly the range of the + input image. + Parameters ---------- im : array, shape (M, N[, 3]) @@ -19,9 +31,36 @@ def imshow(im, *args, **kwargs): """ if plt.gca().has_data(): plt.figure() + immin, immax = np.min(im), np.max(im) + supported_dtype = im.dtype in dtypes._supported_types + if supported_dtype: + lo, hi = dtypes.dtype_range[im.dtype.type] + if immin >= 0: + # display range starts at 0 for nonnegative images + lo = 0 + 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: + lo, hi = immin, immax kwargs.setdefault('interpolation', 'nearest') kwargs.setdefault('cmap', 'gray') - return plt.imshow(im, *args, **kwargs) + kwargs.setdefault('vmin', lo) + kwargs.setdefault('vmax', hi) + ax = plt.imshow(im, *args, **kwargs) + if not supported_dtype or out_of_range_float or low_dynamic_range: + ax.colorbar() + return ax imread = plt.imread show = plt.show