44
55import copy
66
7+ from dataclasses import dataclass
78from numbers import Integral , Number , Real
89import logging
910
1819from .path import Path
1920from .transforms import Bbox , BboxTransformTo , TransformedPath
2021from ._enums import JoinStyle , CapStyle
21- from ._data_containers ._helpers import containerize_draw
22+ from ._data_containers ._helpers import containerize_draw , _get_graph , check_container
23+ from ._data_containers .description import Desc
2224
2325# Imported here for backward compatibility, even though they don't
2426# really belong.
@@ -228,6 +230,26 @@ def _slice_or_none(in_v, slc):
228230 raise ValueError (f"markevery={ markevery !r} is not a recognized value" )
229231
230232
233+ @dataclass
234+ class LineContainer :
235+ x : np .ndarray
236+ y : np .ndarray
237+
238+ def describe (self ):
239+
240+ return {
241+ "x" : Desc (("N" ,), "data" ),
242+ "y" : Desc (("N" ,), "data" ),
243+ }
244+
245+ def query (self , graph , parent_coordinates = "axes" ):
246+ return {
247+ "x" : self .x ,
248+ "y" : self .y ,
249+ }, ""
250+ # TODO hash
251+
252+
231253@_docstring .interpd
232254@_api .define_aliases ({
233255 "antialiased" : ["aa" ],
@@ -336,6 +358,9 @@ def __init__(self, xdata, ydata, *,
336358 """
337359 super ().__init__ ()
338360
361+ self ._container = self ._init_container ()
362+ self .__query = None
363+
339364 # Convert sequences to NumPy arrays.
340365 if not np .iterable (xdata ):
341366 raise RuntimeError ('xdata must be a sequence' )
@@ -414,21 +439,60 @@ def __init__(self, xdata, ydata, *,
414439 not isinstance (self ._picker , bool )):
415440 self ._pickradius = self ._picker
416441
417- self ._xorig = np .asarray ([])
418- self ._yorig = np .asarray ([])
419442 self ._invalidx = True
420443 self ._invalidy = True
421- self ._x = None
422- self ._y = None
423- self ._xy = None
424444 self ._path = None
425445 self ._transformed_path = None
426446 self ._subslice = False
427447 self ._x_filled = None # used in subslicing; only x is needed
428- self ._container = None
429448
430449 self .set_data (xdata , ydata )
431450
451+ def set_container (self , container ):
452+ self ._container = container
453+ self .stale = True
454+
455+ def get_container (self ):
456+ return self ._container
457+
458+ def _init_container (self ):
459+ return LineContainer (
460+ x = np .array ([]),
461+ y = np .array ([]),
462+ )
463+
464+ @property
465+ def _xorig (self ):
466+ return self ._query ["x" ]
467+
468+ @property
469+ def _x (self ):
470+ xconv = self .convert_xunits (self ._xorig )
471+ return _to_unmasked_float_array (xconv ).ravel ()
472+
473+ @property
474+ def _yorig (self ):
475+ return self ._query ["y" ]
476+
477+ @property
478+ def _y (self ):
479+ yconv = self .convert_yunits (self ._yorig )
480+ return _to_unmasked_float_array (yconv ).ravel ()
481+
482+ @property
483+ def _xy (self ):
484+ x , y = self ._x , self ._y
485+ return np .column_stack (np .broadcast_arrays (x , y )).astype (float )
486+
487+ @property
488+ def _query (self ):
489+ if self .__query is not None :
490+ return self .__query
491+ return self ._container .query (_get_graph (self .axes ))[0 ]
492+
493+ def _cache_query (self ):
494+ self .__query = self ._container .query (_get_graph (self .axes ))[0 ]
495+
432496 def contains (self , mouseevent ):
433497 """
434498 Test whether *mouseevent* occurred on the line.
@@ -685,9 +749,6 @@ def recache(self, always=False):
685749 else :
686750 y = self ._y
687751
688- self ._xy = np .column_stack (np .broadcast_arrays (x , y )).astype (float )
689- self ._x , self ._y = self ._xy .T # views
690-
691752 self ._subslice = False
692753 if (self .axes
693754 and len (x ) > self ._subslice_optim_min_size
@@ -753,6 +814,8 @@ def draw(self, renderer, *, graph=None):
753814 if not self .get_visible ():
754815 return
755816
817+ self ._cache_query ()
818+
756819 if self ._invalidy or self ._invalidx :
757820 self .recache ()
758821 self .ind_offset = 0 # Needed for contains() method.
@@ -1300,9 +1363,11 @@ def set_xdata(self, x):
13001363 set_data
13011364 set_ydata
13021365 """
1366+ check_container (self , LineContainer , "'set_xdata'" )
13031367 if not np .iterable (x ):
13041368 raise RuntimeError ('x must be a sequence' )
1305- self ._xorig = copy .copy (x )
1369+ self ._container .x = copy .copy (x )
1370+ self .__query = None
13061371 self ._invalidx = True
13071372 self .stale = True
13081373
@@ -1319,9 +1384,11 @@ def set_ydata(self, y):
13191384 set_data
13201385 set_xdata
13211386 """
1387+ check_container (self , LineContainer , "'set_ydata'" )
13221388 if not np .iterable (y ):
13231389 raise RuntimeError ('y must be a sequence' )
1324- self ._yorig = copy .copy (y )
1390+ self ._container .y = copy .copy (y )
1391+ self .__query = None
13251392 self ._invalidy = True
13261393 self .stale = True
13271394
0 commit comments