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

Skip to content

Commit 5fbddef

Browse files
committed
Update caching logic for Images
1 parent 773bfe1 commit 5fbddef

2 files changed

Lines changed: 45 additions & 22 deletions

File tree

lib/matplotlib/_data_containers/_helpers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,8 @@ def _get_graph(ax):
4242
aliases=(("parent", "axes"),),
4343
)
4444
return implicit_graph
45+
46+
47+
def check_container(artist, container_cls, operation="This operation"):
48+
if not isinstance(artist._container, container_cls):
49+
raise TypeError(f"{operation} is not available with a custom container class")

lib/matplotlib/image.py

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
# the image namespace
2424
from matplotlib._image import * # noqa: F401, F403
2525
from ._data_containers.description import Desc
26-
from ._data_containers._helpers import _get_graph
26+
from ._data_containers._helpers import _get_graph, check_container
2727
import matplotlib.artist as martist
2828
import matplotlib.colorizer as mcolorizer
2929
from matplotlib.backend_bases import FigureCanvasBase
@@ -347,21 +347,38 @@ def __init__(self, ax,
347347
np.array([0.,1.]),
348348
np.array([[]]),
349349
)
350+
self.__query = None
350351
self._imcache = None
351352

352353
self._internal_update(kwargs)
353354

355+
@property
356+
def _query(self):
357+
if self.__query is not None:
358+
return self.__query
359+
return self._container.query(_get_graph(self.axes))[0]
360+
361+
def _cache_query(self):
362+
self.__query = self._container.query(_get_graph(self.axes))[0]
363+
354364
@property
355365
def _image_array(self):
356-
return self._container.query(_get_graph(self.axes))[0]["image"]
366+
return self._query["image"]
357367

358368
@property
359369
def _A(self):
360370
return self._image_array
361371

362372
@_A.setter
363373
def _A(self, val):
364-
return
374+
if val is None:
375+
# This case is needed for the transition because
376+
# ColorizingArtist sets `_A = None` during init
377+
return
378+
check_container(self, ImageContainer, "Setting _A")
379+
self._container.image = self._normalize_image_array(val)
380+
self._imcache = None
381+
self.stale = True
365382

366383
def set_container(self, container):
367384
self._container = container
@@ -379,7 +396,11 @@ def __str__(self):
379396

380397
def __getstate__(self):
381398
# Save some space on the pickle by not saving the cache.
382-
return {**super().__getstate__(), "_imcache": None}
399+
return {
400+
**super().__getstate__(),
401+
"_imcache": None,
402+
"_ImageBase__query": None,
403+
}
383404

384405
def get_size(self):
385406
"""Return the size of the image as tuple (numrows, numcols)."""
@@ -689,6 +710,8 @@ def draw(self, renderer):
689710
if not self.get_visible():
690711
self.stale = False
691712
return
713+
# Update the cached version of the query
714+
self._cache_query()
692715
# for empty images, there is nothing to draw!
693716
if self.get_array().size == 0:
694717
self.stale = False
@@ -781,11 +804,9 @@ def set_data(self, A):
781804
----------
782805
A : array-like or `PIL.Image.Image`
783806
"""
784-
if not isinstance(self._container, ImageContainer):
785-
raise TypeError("Cannot use 'set_data' on custom container types")
807+
check_container(self, ImageContainer, "'set_data'")
786808
if isinstance(A, PIL.Image.Image):
787809
A = pil_to_array(A) # Needed e.g. to apply png palette.
788-
# self._A = self._normalize_image_array(A)
789810
self._container.image = self._normalize_image_array(A)
790811
self._imcache = None
791812
self.stale = True
@@ -1013,7 +1034,7 @@ def get_window_extent(self, renderer=None):
10131034
return bbox.transformed(self.get_transform())
10141035

10151036
def make_image(self, renderer, magnification=1.0, unsampled=False):
1016-
q, _ = self._container.query(_get_graph(self.axes))
1037+
q = self._query
10171038
x1, x2 = q["x"]
10181039
y1, y2 = q["y"]
10191040

@@ -1053,8 +1074,7 @@ def set_extent(self, extent, **kwargs):
10531074
state is not changed, so a subsequent call to `.Axes.autoscale_view`
10541075
will redo the autoscaling in accord with `~.Axes.dataLim`.
10551076
"""
1056-
if not isinstance(self._container, ImageContainer):
1057-
raise TypeError("Cannot use 'set_extent' on custom container types")
1077+
check_container(self, ImageContainer, "'set_extent'")
10581078

10591079
if extent is None:
10601080
sz = self.get_size()
@@ -1101,7 +1121,7 @@ def _update_autolims(self, xmin, xmax, ymin, ymax):
11011121

11021122
def get_extent(self):
11031123
"""Return the image extent as tuple (left, right, bottom, top)."""
1104-
q, _ = self._container.query(_get_graph(self.axes))
1124+
q = self._query
11051125
x = q["x"]
11061126
y = q["y"]
11071127
return x[0], x[-1], y[0], y[-1]
@@ -1176,7 +1196,7 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
11761196
if unsampled:
11771197
raise ValueError('unsampled not supported on NonUniformImage')
11781198

1179-
q, _ = self._container.query(_get_graph(self.axes))
1199+
q = self._query
11801200
Ax = q["x"]
11811201
Ay = q["y"]
11821202

@@ -1262,8 +1282,7 @@ def set_data(self, x, y, A):
12621282
(M, N) `~numpy.ndarray` or masked array of values to be
12631283
colormapped, or (M, N, 3) RGB array, or (M, N, 4) RGBA array.
12641284
"""
1265-
if not isinstance(self._container, NonUniformImageContainer):
1266-
raise TypeError("Cannot use 'set_data' on custom container types")
1285+
check_container(self, NonUniformImageContainer, "'set_data'")
12671286
A = self._normalize_image_array(A)
12681287
x = np.array(x, np.float32)
12691288
y = np.array(y, np.float32)
@@ -1308,7 +1327,7 @@ def set_cmap(self, cmap):
13081327

13091328
def get_cursor_data(self, event):
13101329
# docstring inherited
1311-
q, _ = self._container.query(_get_graph(self.axes))
1330+
q = self._query
13121331
Ax = q["x"]
13131332
Ay = q["y"]
13141333
A = q["image"]
@@ -1379,7 +1398,7 @@ def make_image(self, renderer, magnification=1.0, unsampled=False):
13791398
if unsampled:
13801399
raise ValueError('unsampled not supported on PcolorImage')
13811400

1382-
q, _ = self._container.query(_get_graph(self.axes))
1401+
q = self._query
13831402
Ax = q["x"]
13841403
Ay = q["y"]
13851404

@@ -1432,8 +1451,7 @@ def set_data(self, x, y, A):
14321451
- (M, N, 3): RGB array
14331452
- (M, N, 4): RGBA array
14341453
"""
1435-
if not isinstance(self._container, PcolorImageContainer):
1436-
raise TypeError("Cannot use 'set_data' on custom container types")
1454+
check_container(self, PcolorImageContainer, "'set_data'")
14371455
A = self._normalize_image_array(A)
14381456
x = np.arange(0., A.shape[1] + 1) if x is None else np.array(x, float).ravel()
14391457
y = np.arange(0., A.shape[0] + 1) if y is None else np.array(y, float).ravel()
@@ -1459,7 +1477,7 @@ def set_array(self, *args):
14591477

14601478
def get_cursor_data(self, event):
14611479
# docstring inherited
1462-
q, _ = self._container.query(_get_graph(self.axes))
1480+
q = self._query
14631481
Ax = q["x"]
14641482
Ay = q["y"]
14651483
A = q["image"]
@@ -1514,7 +1532,7 @@ def __init__(self, fig,
15141532

15151533
def get_extent(self):
15161534
"""Return the image extent as tuple (left, right, bottom, top)."""
1517-
q, _ = self._container.query(_get_graph(self.axes))
1535+
q = self._query
15181536
ox = q["x"]
15191537
oy = q["y"]
15201538
A = q["image"]
@@ -1525,7 +1543,7 @@ def get_extent(self):
15251543

15261544
def make_image(self, renderer, magnification=1.0, unsampled=False):
15271545
# docstring inherited
1528-
q, _ = self._container.query(_get_graph(self.axes))
1546+
q = self._query
15291547
ox = q["x"]
15301548
oy = q["y"]
15311549
A = q["image"]
@@ -1647,7 +1665,7 @@ def contains(self, mouseevent):
16471665

16481666
def make_image(self, renderer, magnification=1.0, unsampled=False):
16491667
# docstring inherited
1650-
q, _ = self._container.query(_get_graph(self.axes))
1668+
q = self._query
16511669
A = q["image"]
16521670

16531671
width, height = renderer.get_canvas_width_height()

0 commit comments

Comments
 (0)