Skip to content

Commit d92f161

Browse files
committed
Merge pull request matplotlib#6422 from efiring/image_copy_data
BUG: copy image data so it can't be modified prior to drawing
2 parents 1081385 + 88db38b commit d92f161

File tree

3 files changed

+59
-12
lines changed

3 files changed

+59
-12
lines changed

lib/matplotlib/cbook.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,8 +1516,8 @@ def issubclass_safe(x, klass):
15161516
return False
15171517

15181518

1519-
def safe_masked_invalid(x):
1520-
x = np.asanyarray(x)
1519+
def safe_masked_invalid(x, copy=False):
1520+
x = np.array(x, subok=True, copy=copy)
15211521
try:
15221522
xm = np.ma.masked_invalid(x, copy=False)
15231523
xm.shrink_mask()

lib/matplotlib/image.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ def set_data(self, A):
442442
if hasattr(A, 'getpixel'):
443443
self._A = pil_to_array(A)
444444
else:
445-
self._A = cbook.safe_masked_invalid(A)
445+
self._A = cbook.safe_masked_invalid(A, copy=True)
446446

447447
if (self._A.dtype != np.uint8 and
448448
not np.can_cast(self._A.dtype, np.float)):
@@ -798,9 +798,9 @@ def set_data(self, x, y, A):
798798
colormapped, or a (M,N,3) RGB array, or a (M,N,4) RGBA
799799
array.
800800
"""
801-
x = np.asarray(x, np.float32)
802-
y = np.asarray(y, np.float32)
803-
A = cbook.safe_masked_invalid(A)
801+
x = np.array(x, np.float32)
802+
y = np.array(y, np.float32)
803+
A = cbook.safe_masked_invalid(A, copy=True)
804804
if len(x.shape) != 1 or len(y.shape) != 1\
805805
or A.shape[0:2] != (y.shape[0], x.shape[0]):
806806
raise TypeError("Axes don't match array shape")
@@ -887,7 +887,8 @@ def __init__(self, ax,
887887
# it needs to be remade if the bbox or viewlim change,
888888
# so caching does help with zoom/pan/resize.
889889
self.update(kwargs)
890-
self.set_data(x, y, A)
890+
if A is not None:
891+
self.set_data(x, y, A)
891892

892893
def make_image(self, magnification=1.0):
893894
if self._A is None:
@@ -938,15 +939,15 @@ def draw(self, renderer, *args, **kwargs):
938939
self.stale = False
939940

940941
def set_data(self, x, y, A):
941-
A = cbook.safe_masked_invalid(A)
942+
A = cbook.safe_masked_invalid(A, copy=True)
942943
if x is None:
943944
x = np.arange(0, A.shape[1]+1, dtype=np.float64)
944945
else:
945-
x = np.asarray(x, np.float64).ravel()
946+
x = np.array(x, np.float64).ravel()
946947
if y is None:
947948
y = np.arange(0, A.shape[0]+1, dtype=np.float64)
948949
else:
949-
y = np.asarray(y, np.float64).ravel()
950+
y = np.array(y, np.float64).ravel()
950951

951952
if A.shape[:2] != (y.size-1, x.size-1):
952953
print(A.shape)
@@ -1044,7 +1045,8 @@ def get_extent(self):
10441045

10451046
def set_data(self, A):
10461047
"""Set the image array."""
1047-
cm.ScalarMappable.set_array(self, cbook.safe_masked_invalid(A))
1048+
cm.ScalarMappable.set_array(self,
1049+
cbook.safe_masked_invalid(A, copy=True))
10481050
self.stale = True
10491051

10501052
def set_array(self, A):

lib/matplotlib/tests/test_image.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
from matplotlib.testing.decorators import (image_comparison,
1414
knownfailureif, cleanup)
15-
from matplotlib.image import BboxImage, imread, NonUniformImage
15+
from matplotlib.image import (BboxImage, imread, NonUniformImage,
16+
AxesImage, FigureImage, PcolorImage)
1617
from matplotlib.transforms import Bbox
1718
from matplotlib import rcParams
1819
import matplotlib.pyplot as plt
@@ -463,6 +464,50 @@ def test_nonuniformimage_setnorm():
463464
im.set_norm(plt.Normalize())
464465

465466

467+
@cleanup
468+
def test_nonuniformimage_setdata():
469+
ax = plt.gca()
470+
im = NonUniformImage(ax)
471+
x = np.arange(3, dtype=np.float64)
472+
y = np.arange(4, dtype=np.float64)
473+
z = np.arange(12, dtype=np.float64).reshape((4, 3))
474+
im.set_data(x, y, z)
475+
x[0] = y[0] = z[0, 0] = 9.9
476+
assert im._A[0, 0] == im._Ax[0] == im._Ay[0] == 0, 'value changed'
477+
478+
479+
@cleanup
480+
def test_axesimage_setdata():
481+
ax = plt.gca()
482+
im = AxesImage(ax)
483+
z = np.arange(12, dtype=np.float64).reshape((4, 3))
484+
im.set_data(z)
485+
z[0, 0] = 9.9
486+
assert im._A[0, 0] == 0, 'value changed'
487+
488+
489+
@cleanup
490+
def test_figureimage_setdata():
491+
fig = plt.gcf()
492+
im = FigureImage(fig)
493+
z = np.arange(12, dtype=np.float64).reshape((4, 3))
494+
im.set_data(z)
495+
z[0, 0] = 9.9
496+
assert im._A[0, 0] == 0, 'value changed'
497+
498+
499+
@cleanup
500+
def test_pcolorimage_setdata():
501+
ax = plt.gca()
502+
im = PcolorImage(ax)
503+
x = np.arange(3, dtype=np.float64)
504+
y = np.arange(4, dtype=np.float64)
505+
z = np.arange(6, dtype=np.float64).reshape((3, 2))
506+
im.set_data(x, y, z)
507+
x[0] = y[0] = z[0, 0] = 9.9
508+
assert im._A[0, 0] == im._Ax[0] == im._Ay[0] == 0, 'value changed'
509+
510+
466511
@cleanup
467512
def test_minimized_rasterized():
468513
# This ensures that the rasterized content in the colorbars is

0 commit comments

Comments
 (0)