Skimage.io.imshow crashes when showing binary images

Hey scikit-image friends,

some of my teaching notebooks recently broke. Suddenly, the imshow function in scikit-image can’t show binary images anymore. Does anybody have an idea what we could do (change dependency versions? change code?) to make them run again?

Here is the code (and that’s the data):

from skimage.io import imshow, imread

image = imread("blobs.tif")

from skimage import filters
threshold = filters.threshold_otsu(image)

binary_image = image >= threshold

imshow(binary_image)

That error pops up in the last line:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-94950852c6d3> in <module>
      1 binary_image = image >= threshold
      2 
----> 3 imshow(binary_image)

~\miniconda3\envs\bio\lib\site-packages\skimage\io\_io.py in imshow(arr, plugin, **plugin_args)
    157     if isinstance(arr, str):
    158         arr = call_plugin('imread', arr, plugin=plugin)
--> 159     return call_plugin('imshow', arr, plugin=plugin, **plugin_args)
    160 
    161 

~\miniconda3\envs\bio\lib\site-packages\skimage\io\manage_plugins.py in call_plugin(kind, *args, **kwargs)
    205                                (plugin, kind))
    206 
--> 207     return func(*args, **kwargs)
    208 
    209 

~\miniconda3\envs\bio\lib\site-packages\skimage\io\_plugins\matplotlib_plugin.py in imshow(image, ax, show_cbar, **kwargs)
    148     import matplotlib.pyplot as plt
    149 
--> 150     lo, hi, cmap = _get_display_range(image)
    151 
    152     kwargs.setdefault('interpolation', 'nearest')

~\miniconda3\envs\bio\lib\site-packages\skimage\io\_plugins\matplotlib_plugin.py in _get_display_range(image)
     95         The name of the colormap to use.
     96     """
---> 97     ip = _get_image_properties(image)
     98     immin, immax = np.min(image), np.max(image)
     99     if ip.signed:

~\miniconda3\envs\bio\lib\site-packages\skimage\io\_plugins\matplotlib_plugin.py in _get_image_properties(image)
     53                           (immin < lo or immax > hi))
     54     low_data_range = (immin != immax and
---> 55                       is_low_contrast(image))
     56     unsupported_dtype = image.dtype not in dtypes._supported_types
     57 

~\miniconda3\envs\bio\lib\site-packages\skimage\exposure\exposure.py in is_low_contrast(image, fraction_threshold, lower_percentile, upper_percentile, method)
    649 
    650     dlimits = dtype_limits(image, clip_negative=False)
--> 651     limits = np.percentile(image, [lower_percentile, upper_percentile])
    652     ratio = (limits[1] - limits[0]) / (dlimits[1] - dlimits[0])
    653 

<__array_function__ internals> in percentile(*args, **kwargs)

~\miniconda3\envs\bio\lib\site-packages\numpy\lib\function_base.py in percentile(a, q, axis, out, overwrite_input, interpolation, keepdims)
   3816     if not _quantile_is_valid(q):
   3817         raise ValueError("Percentiles must be in the range [0, 100]")
-> 3818     return _quantile_unchecked(
   3819         a, q, axis, out, overwrite_input, interpolation, keepdims)
   3820 

~\miniconda3\envs\bio\lib\site-packages\numpy\lib\function_base.py in _quantile_unchecked(a, q, axis, out, overwrite_input, interpolation, keepdims)
   3935                         interpolation='linear', keepdims=False):
   3936     """Assumes that q is in [0, 1], and is an ndarray"""
-> 3937     r, k = _ureduce(a, func=_quantile_ureduce_func, q=q, axis=axis, out=out,
   3938                     overwrite_input=overwrite_input,
   3939                     interpolation=interpolation)

~\miniconda3\envs\bio\lib\site-packages\numpy\lib\function_base.py in _ureduce(a, func, **kwargs)
   3513         keepdim = (1,) * a.ndim
   3514 
-> 3515     r = func(a, **kwargs)
   3516     return r, keepdim
   3517 

~\miniconda3\envs\bio\lib\site-packages\numpy\lib\function_base.py in _quantile_ureduce_func(***failed resolving arguments***)
   4062         x_above = take(ap, indices_above, axis=0)
   4063 
-> 4064         r = _lerp(x_below, x_above, weights_above, out=out)
   4065 
   4066     # if any slice contained a nan, then all results on that slice are also nan

~\miniconda3\envs\bio\lib\site-packages\numpy\lib\function_base.py in _lerp(a, b, t, out)
   3959 def _lerp(a, b, t, out=None):
   3960     """ Linearly interpolate from a to b by a factor of t """
-> 3961     diff_b_a = subtract(b, a)
   3962     # asanyarray is a stop-gap until gh-13105
   3963     lerp_interpolation = asanyarray(add(a, diff_b_a*t, out=out))

TypeError: numpy boolean subtract, the `-` operator, is not supported, use the bitwise_xor, the `^` operator, or the logical_xor function instead.

Any hint is appreciated!

Best,
Robert

You should prefer:

import matplotlib.pyplot as plt

plt.imshow(image)

We will probably deprecate skimage.io.imshow in the not-too-distant future. The reason it exists is that a long time ago, matplotlib’s imshow defaulted to the jet colormap, which is terrible. Now that matplotlib defaults to viridis, it no longer has a reason to exist.

If you must get it to work for binary images, the trick is to revert your NumPy version to one before they deprecated bool_arr1 - bool_arr2. (I forget what number that is.) But as you can see, it was sort of a coincidence that skimage.io.imshow worked at all with binary images…

1 Like

Awesome @jni , I was aready suspecting that matplotlib is the right tool of choice here but wasn’t sure. Thanks for the light-speed support and have a great weekend!

Cheers,
Robert

Still, it sounds like something we can easily detect and fix; at least until we remove our own viewers.

2 Likes