1616from matplotlib .artist import Artist as _Artist
1717
1818from data_prototype .containers import DataContainer , _MatplotlibTransform
19+ from data_prototype .conversion_node import (
20+ ConversionNode ,
21+ RenameConversionNode ,
22+ evaluate_pipeline ,
23+ FunctionConversionNode ,
24+ LimitKeysConversionNode ,
25+ )
1926
2027
2128class _BBox (Protocol ):
@@ -139,45 +146,26 @@ def _query_and_transform(self, renderer, *, xunits: List[str], yunits: List[str]
139146 return self ._cache [cache_key ]
140147 except KeyError :
141148 ...
142- # TODO decide if units go pre-nu or post-nu?
143- for x_like in xunits :
144- if x_like in data :
145- data [x_like ] = ax .xaxis .convert_units (data [x_like ])
146- for y_like in yunits :
147- if y_like in data :
148- data [y_like ] = ax .xaxis .convert_units (data [y_like ])
149-
150- # doing the nu work here is nice because we can write it once, but we
151- # really want to push this computation down a layer
152- # TODO sort out how this interoperates with the transform stack
153- transformed_data = {}
154- for k , (nu , sig ) in self ._sigs .items ():
155- to_pass = set (sig .parameters )
156- transformed_data [k ] = nu (** {k : data [k ] for k in to_pass })
149+ # TODO units
150+ transformed_data = evaluate_pipeline (self ._converters , data )
157151
158152 self ._cache [cache_key ] = transformed_data
159153 return transformed_data
160154
161- def __init__ (self , data , converters , ** kwargs ):
155+ def __init__ (self , data , converters : ConversionNode | list [ ConversionNode ] | None , ** kwargs ):
162156 super ().__init__ (** kwargs )
163157 self .data = data
164158 self ._cache = LFUCache (64 )
165159 # TODO make sure mutating this will invalidate the cache!
166- self ._converters = converters or {}
167- for k in self .required_keys :
168- self ._converters .setdefault (k , _make_identity (k ))
169- desc = data .describe ()
170- for k in self .expected_keys :
171- if k in desc :
172- self ._converters .setdefault (k , _make_identity (k ))
173- self ._sigs = {k : (nu , inspect .signature (nu )) for k , nu in self ._converters .items ()}
160+ if isinstance (converters , ConversionNode ):
161+ converters = [converters ]
162+ self ._converters : list [ConversionNode ] = converters or []
163+ setters = list (self .expected_keys | self .required_keys )
164+ if hasattr (self , "_wrapped_class" ):
165+ setters += [f [4 :] for f in dir (self ._wrapped_class ) if f .startswith ("set_" )]
166+ self ._converters .append (LimitKeysConversionNode .from_keys ("setters" , setters ))
174167 self .stale = True
175168
176- # TODO add a setter
177- @property
178- def converters (self ):
179- return dict (self ._converters )
180-
181169
182170class ProxyWrapper (ProxyWrapperBase ):
183171 _privtized_methods : Tuple [str , ...] = ()
@@ -208,6 +196,9 @@ class LineWrapper(ProxyWrapper):
208196 def __init__ (self , data : DataContainer , converters = None , / , ** kwargs ):
209197 super ().__init__ (data , converters )
210198 self ._wrapped_instance = self ._wrapped_class (np .array ([]), np .array ([]), ** kwargs )
199+ self ._converters .insert (- 1 , RenameConversionNode .from_mapping ("xydata" , {"x" : "xdata" , "y" : "ydata" }))
200+ setters = [f [4 :] for f in dir (self ._wrapped_class ) if f .startswith ("set_" )]
201+ self ._converters [- 1 ] = LimitKeysConversionNode .from_keys ("setters" , setters )
211202
212203 @_stale_wrapper
213204 def draw (self , renderer ):
@@ -218,7 +209,6 @@ def draw(self, renderer):
218209
219210 def _update_wrapped (self , data ):
220211 for k , v in data .items ():
221- k = {"x" : "xdata" , "y" : "ydata" }.get (k , k )
222212 getattr (self ._wrapped_instance , f"set_{ k } " )(v )
223213
224214
@@ -263,15 +253,17 @@ class ImageWrapper(ProxyWrapper):
263253 required_keys = {"xextent" , "yextent" , "image" }
264254
265255 def __init__ (self , data : DataContainer , converters = None , / , cmap = None , norm = None , ** kwargs ):
266- converters = dict ( converters or {})
256+ converters = converters or []
267257 if cmap is not None or norm is not None :
268258 if converters is not None and "image" in converters :
269259 raise ValueError ("Conflicting input" )
270260 if cmap is None :
271261 cmap = mpl .colormaps ["viridis" ]
272262 if norm is None :
273263 raise ValueError ("not sure how to do autoscaling yet" )
274- converters ["image" ] = lambda image : cmap (norm (image ))
264+ converters .append (
265+ FunctionConversionNode .from_funcs ("map colors" , {"image" : lambda image : cmap (norm (image ))})
266+ )
275267 super ().__init__ (data , converters )
276268 kwargs .setdefault ("origin" , "lower" )
277269 self ._wrapped_instance = self ._wrapped_class (None , ** kwargs )
0 commit comments