Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d100c42

Browse files
authored
Merge pull request #19368 from dstansby/resample-error
Raise warning and downsample if data given to _image.resample is too large
2 parents 80073f6 + 468b72c commit d100c42

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Large ``imshow`` images are now downsampled
2+
-------------------------------------------
3+
When showing an image using `~matplotlib.axes.Axes.imshow` that has more than
4+
:math:`2^{24}` columns or :math:`2^{23}` rows, the image will now be downsampled
5+
to below this resolution before being resampled for display by the AGG renderer.
6+
Previously such a large image would be shown incorrectly. To prevent this
7+
downsampling and the warning it raises, manually downsample your data before
8+
handing it to `~matplotlib.axes.Axes.imshow`

lib/matplotlib/image.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import logging
99
from pathlib import Path
10+
import warnings
1011

1112
import numpy as np
1213
import PIL.PngImagePlugin
@@ -166,7 +167,22 @@ def _resample(
166167
allocating the output array and fetching the relevant properties from the
167168
Image object *image_obj*.
168169
"""
169-
170+
# AGG can only handle coordinates smaller than 24-bit signed integers,
171+
# so raise errors if the input data is larger than _image.resample can
172+
# handle.
173+
msg = ('Data with more than {n} cannot be accurately displayed. '
174+
'Downsampling to less than {n} before displaying. '
175+
'To remove this warning, manually downsample your data.')
176+
if data.shape[1] > 2**23:
177+
warnings.warn(msg.format(n='2**23 columns'))
178+
step = int(np.ceil(data.shape[1] / 2**23))
179+
data = data[:, ::step]
180+
transform = Affine2D().scale(step, 1) + transform
181+
if data.shape[0] > 2**24:
182+
warnings.warn(msg.format(n='2**24 rows'))
183+
step = int(np.ceil(data.shape[0] / 2**24))
184+
data = data[::step, :]
185+
transform = Affine2D().scale(1, step) + transform
170186
# decide if we need to apply anti-aliasing if the data is upsampled:
171187
# compare the number of displayed pixels to the number of
172188
# the data pixels.

lib/matplotlib/tests/test_image.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,3 +1376,43 @@ def test_rgba_antialias():
13761376
# alternating red and blue stripes become purple
13771377
axs[3].imshow(aa, interpolation='antialiased', interpolation_stage='rgba',
13781378
cmap=cmap, vmin=-1.2, vmax=1.2)
1379+
1380+
1381+
# We check for the warning with a draw() in the test, but we also need to
1382+
# filter the warning as it is emitted by the figure test decorator
1383+
@pytest.mark.filterwarnings(r'ignore:Data with more than .* '
1384+
'cannot be accurately displayed')
1385+
@pytest.mark.parametrize('origin', ['upper', 'lower'])
1386+
@pytest.mark.parametrize(
1387+
'dim, size, msg', [['row', 2**23, r'2\*\*23 columns'],
1388+
['col', 2**24, r'2\*\*24 rows']])
1389+
@check_figures_equal(extensions=('png', ))
1390+
def test_large_image(fig_test, fig_ref, dim, size, msg, origin):
1391+
# Check that Matplotlib downsamples images that are too big for AGG
1392+
# See issue #19276. Currently the fix only works for png output but not
1393+
# pdf or svg output.
1394+
ax_test = fig_test.subplots()
1395+
ax_ref = fig_ref.subplots()
1396+
1397+
array = np.zeros((1, size + 2))
1398+
array[:, array.size // 2:] = 1
1399+
if dim == 'col':
1400+
array = array.T
1401+
im = ax_test.imshow(array, vmin=0, vmax=1,
1402+
aspect='auto', extent=(0, 1, 0, 1),
1403+
interpolation='none',
1404+
origin=origin)
1405+
1406+
with pytest.warns(UserWarning,
1407+
match=f'Data with more than {msg} cannot be '
1408+
'accurately displayed.'):
1409+
fig_test.canvas.draw()
1410+
1411+
array = np.zeros((1, 2))
1412+
array[:, 1] = 1
1413+
if dim == 'col':
1414+
array = array.T
1415+
im = ax_ref.imshow(array, vmin=0, vmax=1, aspect='auto',
1416+
extent=(0, 1, 0, 1),
1417+
interpolation='none',
1418+
origin=origin)

0 commit comments

Comments
 (0)