diff --git a/data_prototype/artist.py b/data_prototype/artist.py index 9426c52..2776888 100644 --- a/data_prototype/artist.py +++ b/data_prototype/artist.py @@ -1,4 +1,5 @@ from bisect import insort +from collections import OrderedDict from typing import Sequence from contextlib import contextmanager @@ -33,6 +34,8 @@ def __init__( **{"x": np.asarray([0, 1]), "y": np.asarray([0, 1])} ) + self._caches = {} + def draw(self, renderer, graph: Graph) -> None: return @@ -119,6 +122,31 @@ def pick(self, mouseevent, graph: Graph | None = None): # which do not have an axes property but children might a.pick(mouseevent, graph) + def _get_dynamic_graph(self, query): + return Graph([]) + + def _query_and_eval(self, container, requires, graph, cacheset=None): + g = graph + self._graph + query, q_cache_key = container.query(g) + g = g + self._get_dynamic_graph(query) + g_cache_key = g.cache_key() + cache_key = (g_cache_key, q_cache_key) + + cache = None + if cacheset is not None: + cache = self._caches.setdefault(cacheset, OrderedDict()) + if cache_key in cache: + return cache[cache_key] + + conv = g.evaluator(container.describe(), requires) + ret = conv.evaluate(query) + + if cache is not None: + cache[cache_key] = ret + # TODO prune + + return ret + class CompatibilityArtist: """A compatibility shim to ducktype as a classic Matplotlib Artist. diff --git a/data_prototype/conversion_edge.py b/data_prototype/conversion_edge.py index 2a09cc1..20adc9f 100644 --- a/data_prototype/conversion_edge.py +++ b/data_prototype/conversion_edge.py @@ -418,3 +418,12 @@ def __add__(self, other: Graph) -> Graph: aother = {k: v for k, v in other._aliases} aliases = tuple((aself | aother).items()) return Graph(self._edges + other._edges, aliases) + + def cache_key(self): + """A cache key representing the graph. + + Current implementation is a new UUID, that is to say uncachable. + """ + import uuid + + return str(uuid.uuid4()) diff --git a/data_prototype/patches.py b/data_prototype/patches.py index daf50d8..4d6eb46 100644 --- a/data_prototype/patches.py +++ b/data_prototype/patches.py @@ -7,10 +7,9 @@ from .wrappers import ProxyWrapper, _stale_wrapper -from .containers import DataContainer - from .artist import Artist, _renderer_group from .description import Desc +from .containers import DataContainer from .conversion_edge import Graph, CoordinateEdge, DefaultEdge @@ -19,7 +18,7 @@ def __init__(self, container, edges=None, **kwargs): super().__init__(container, edges, **kwargs) scalar = Desc((), "display") # ... this needs thinking... - edges = [ + def_edges = [ CoordinateEdge.from_coords("xycoords", {"x": "auto", "y": "auto"}, "data"), CoordinateEdge.from_coords("codes", {"codes": "auto"}, "display"), CoordinateEdge.from_coords("facecolor", {"color": Desc(())}, "display"), @@ -34,12 +33,11 @@ def __init__(self, container, edges=None, **kwargs): DefaultEdge.from_default_value("alpha_def", "alpha", scalar, 1), DefaultEdge.from_default_value("hatch_def", "hatch", scalar, None), ] - self._graph = self._graph + Graph(edges) + self._graph = self._graph + Graph(def_edges) def draw(self, renderer, graph: Graph) -> None: if not self.get_visible(): return - g = graph + self._graph desc = Desc(("N",), "display") scalar = Desc((), "display") # ... this needs thinking... @@ -55,18 +53,14 @@ def draw(self, renderer, graph: Graph) -> None: "alpha": scalar, } - # copy from line - conv = g.evaluator(self._container.describe(), require) - query, _ = self._container.query(g) - evald = conv.evaluate(query) - - clip_conv = g.evaluator( - self._clip_box.describe(), - {"x": Desc(("N",), "display"), "y": Desc(("N",), "display")}, + evald = self._query_and_eval( + self._container, require, graph, cacheset="default" ) - clip_query, _ = self._clip_box.query(g) - clipx, clipy = clip_conv.evaluate(clip_query).values() - # copy from line + + clip_req = {"x": Desc(("N",), "display"), "y": Desc(("N",), "display")} + clipx, clipy = self._query_and_eval( + self._clip_box, clip_req, graph, cacheset="clip" + ).values() path = mpath.Path._fast_from_codes_and_verts( verts=np.vstack([evald["x"], evald["y"]]).T, codes=evald["codes"] @@ -111,6 +105,14 @@ def draw(self, renderer, graph: Graph) -> None: gc.restore() +class RectangleContainer(DataContainer): ... + + +class Rectangle(Patch): + def __init__(self, container, edges=None, **kwargs): + super().__init__(container, edges, **kwargs) + + class PatchWrapper(ProxyWrapper): _wrapped_class = _Patch _privtized_methods = (