diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index de87c2afaa44..f2a7280af553 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -396,6 +396,28 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, # scaled data A_scaled = np.empty(A.shape, dtype=scaled_dtype) A_scaled[:] = A + # clip scaled data around norm if necessary. + # This is necessary for big numbers at the edge of + # float64's ability to represent changes. Applying + # a norm first would be good, but ruins the interpolation + # of over numbers. + if self.norm.vmin is not None and self.norm.vmax is not None: + dv = (np.float64(self.norm.vmax) - + np.float64(self.norm.vmin)) + vmid = self.norm.vmin + dv / 2 + newmin = vmid - dv * 1.e7 + if newmin < a_min: + newmin = None + else: + a_min = np.float64(newmin) + newmax = vmid + dv * 1.e7 + if newmax > a_max: + newmax = None + else: + a_max = np.float64(newmax) + if newmax is not None or newmin is not None: + A_scaled = np.clip(A_scaled, newmin, newmax) + A_scaled -= a_min # a_min and a_max might be ndarray subclasses so use # asscalar to ensure they are scalars to avoid errors @@ -614,7 +636,11 @@ def set_data(self, A): """ # check if data is PIL Image without importing Image if hasattr(A, 'getpixel'): - self._A = pil_to_array(A) + if A.mode == 'L': + # greyscale image, but our logic assumes rgba: + self._A = pil_to_array(A.convert('RGBA')) + else: + self._A = pil_to_array(A) else: self._A = cbook.safe_masked_invalid(A, copy=True) diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers_real.png b/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers_real.png new file mode 100644 index 000000000000..ce3404488ebb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers_real.png differ diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 16be520e325f..26e3b4a7ea26 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -511,6 +511,18 @@ def test_nonuniformimage_setnorm(): im.set_norm(plt.Normalize()) +@needs_pillow +def test_jpeg_2d(): + # smoke test that mode-L pillow images work. + imd = np.ones((10, 10), dtype='uint8') + for i in range(10): + imd[i, :] = np.linspace(0.0, 1.0, 10) * 255 + im = Image.new('L', (10, 10)) + im.putdata(imd.flatten()) + fig, ax = plt.subplots() + ax.imshow(im) + + @needs_pillow def test_jpeg_alpha(): plt.figure(figsize=(1, 1), dpi=300) @@ -855,7 +867,18 @@ def test_imshow_bignumbers(): img = np.array([[1, 2, 1e12],[3, 1, 4]], dtype=np.uint64) pc = ax.imshow(img) pc.set_clim(0, 5) - plt.show() + + +@image_comparison(baseline_images=['imshow_bignumbers_real'], + remove_text=True, style='mpl20', + extensions=['png']) +def test_imshow_bignumbers_real(): + # putting a big number in an array of integers shouldn't + # ruin the dynamic range of the resolved bits. + fig, ax = plt.subplots() + img = np.array([[2., 1., 1.e22],[4., 1., 3.]]) + pc = ax.imshow(img) + pc.set_clim(0, 5) @pytest.mark.parametrize(