77
88from .wrappers import ProxyWrapper , _stale_wrapper
99
10- from .containers import DataContainer
11-
1210from .artist import Artist , _renderer_group
13- from .description import Desc
14- from .conversion_edge import Graph , CoordinateEdge , DefaultEdge
11+ from .description import Desc , desc_like
12+ from .containers import DataContainer
13+ from .conversion_edge import Graph , CoordinateEdge , DefaultEdge , TransformEdge
1514
1615
1716class Patch (Artist ):
1817 def __init__ (self , container , edges = None , ** kwargs ):
1918 super ().__init__ (container , edges , ** kwargs )
2019
2120 scalar = Desc ((), "display" ) # ... this needs thinking...
22- edges = [
21+ def_edges = [
2322 CoordinateEdge .from_coords ("xycoords" , {"x" : "auto" , "y" : "auto" }, "data" ),
2423 CoordinateEdge .from_coords ("codes" , {"codes" : "auto" }, "display" ),
25- CoordinateEdge .from_coords ("facecolor" , {"color" : Desc (())}, "display" ),
26- CoordinateEdge .from_coords ("edgecolor" , {"color" : Desc (())}, "display" ),
24+ CoordinateEdge .from_coords ("facecolor" , {"facecolor" : Desc (())}, "display" ),
25+ CoordinateEdge .from_coords ("edgecolor" , {"edgecolor" : Desc (())}, "display" ),
26+ CoordinateEdge .from_coords (
27+ "facecolor_rgba" , {"facecolor" : Desc (("M" ,))}, "display"
28+ ),
29+ CoordinateEdge .from_coords (
30+ "edgecolor_rgba" , {"edgecolor" : Desc (("M" ,))}, "display"
31+ ),
2732 CoordinateEdge .from_coords ("linewidth" , {"linewidth" : Desc (())}, "display" ),
2833 CoordinateEdge .from_coords ("hatch" , {"hatch" : Desc (())}, "display" ),
2934 CoordinateEdge .from_coords ("alpha" , {"alpha" : Desc (())}, "display" ),
@@ -34,39 +39,34 @@ def __init__(self, container, edges=None, **kwargs):
3439 DefaultEdge .from_default_value ("alpha_def" , "alpha" , scalar , 1 ),
3540 DefaultEdge .from_default_value ("hatch_def" , "hatch" , scalar , None ),
3641 ]
37- self ._graph = self ._graph + Graph (edges )
42+ self ._graph = self ._graph + Graph (def_edges )
3843
3944 def draw (self , renderer , graph : Graph ) -> None :
4045 if not self .get_visible ():
4146 return
42- g = graph + self ._graph
4347 desc = Desc (("N" ,), "display" )
4448 scalar = Desc ((), "display" ) # ... this needs thinking...
4549
4650 require = {
4751 "x" : desc ,
4852 "y" : desc ,
4953 "codes" : desc ,
50- "facecolor" : scalar ,
51- "edgecolor" : scalar ,
54+ "facecolor" : Desc ((), "display" ) ,
55+ "edgecolor" : Desc (( "M" ,), "display" ) ,
5256 "linewidth" : scalar ,
5357 "linestyle" : scalar ,
5458 "hatch" : scalar ,
5559 "alpha" : scalar ,
5660 }
5761
58- # copy from line
59- conv = g .evaluator (self ._container .describe (), require )
60- query , _ = self ._container .query (g )
61- evald = conv .evaluate (query )
62-
63- clip_conv = g .evaluator (
64- self ._clip_box .describe (),
65- {"x" : Desc (("N" ,), "display" ), "y" : Desc (("N" ,), "display" )},
62+ evald = self ._query_and_eval (
63+ self ._container , require , graph , cacheset = "default"
6664 )
67- clip_query , _ = self ._clip_box .query (g )
68- clipx , clipy = clip_conv .evaluate (clip_query ).values ()
69- # copy from line
65+
66+ clip_req = {"x" : Desc (("N" ,), "display" ), "y" : Desc (("N" ,), "display" )}
67+ clipx , clipy = self ._query_and_eval (
68+ self ._clip_box , clip_req , graph , cacheset = "clip"
69+ ).values ()
7070
7171 path = mpath .Path ._fast_from_codes_and_verts (
7272 verts = np .vstack ([evald ["x" ], evald ["y" ]]).T , codes = evald ["codes" ]
@@ -75,7 +75,7 @@ def draw(self, renderer, graph: Graph) -> None:
7575 with _renderer_group (renderer , "patch" , None ):
7676 gc = renderer .new_gc ()
7777
78- gc .set_foreground (evald ["facecolor " ], isRGBA = False )
78+ gc .set_foreground (evald ["edgecolor " ], isRGBA = False )
7979 gc .set_clip_rectangle (
8080 mtransforms .Bbox .from_extents (clipx [0 ], clipy [0 ], clipx [1 ], clipy [1 ])
8181 )
@@ -111,6 +111,190 @@ def draw(self, renderer, graph: Graph) -> None:
111111 gc .restore ()
112112
113113
114+ class RectangleContainer (DataContainer ): ...
115+
116+
117+ class Rectangle (Patch ):
118+ def __init__ (self , container , edges = None , ** kwargs ):
119+ super ().__init__ (container , edges , ** kwargs )
120+
121+ rect = mpath .Path .unit_rectangle ()
122+
123+ desc = Desc ((4 ,), "abstract_path" )
124+ scalar = Desc ((), "data" )
125+ scalar_auto = Desc (())
126+ def_edges = [
127+ CoordinateEdge .from_coords (
128+ "llxycoords" ,
129+ {"lower_left_x" : scalar_auto , "lower_left_y" : scalar_auto },
130+ "data" ,
131+ ),
132+ CoordinateEdge .from_coords (
133+ "urxycoords" ,
134+ {"upper_right_x" : scalar_auto , "upper_right_y" : scalar_auto },
135+ "data" ,
136+ ),
137+ CoordinateEdge .from_coords (
138+ "rpxycoords" ,
139+ {"rotation_point_x" : scalar_auto , "rotation_point_y" : scalar_auto },
140+ "data" ,
141+ ),
142+ CoordinateEdge .from_coords ("anglecoords" , {"angle" : scalar_auto }, "data" ),
143+ DefaultEdge .from_default_value (
144+ "x_def" , "x" , desc , rect .vertices .T [0 ], weight = 0.1
145+ ),
146+ DefaultEdge .from_default_value (
147+ "y_def" , "y" , desc , rect .vertices .T [1 ], weight = 0.1
148+ ),
149+ DefaultEdge .from_default_value (
150+ "codes_def" ,
151+ "codes" ,
152+ desc_like (desc , coordinates = "display" ),
153+ rect .codes ,
154+ weight = 0.1 ,
155+ ),
156+ DefaultEdge .from_default_value ("angle_def" , "angle" , scalar , 0 ),
157+ DefaultEdge .from_default_value (
158+ "rotation_point_x_def" , "rotation_point_x" , scalar , 0
159+ ),
160+ DefaultEdge .from_default_value (
161+ "rotation_point_y_def" , "rotation_point_y" , scalar , 0
162+ ),
163+ ]
164+
165+ self ._graph = self ._graph + Graph (def_edges )
166+
167+ def _get_dynamic_graph (self , query , description , graph , cacheset ):
168+ if cacheset == "clip" :
169+ return Graph ([])
170+
171+ desc = Desc ((), "data" )
172+
173+ requires = {
174+ "upper_right_x" : desc ,
175+ "upper_right_y" : desc ,
176+ "lower_left_x" : desc ,
177+ "lower_left_y" : desc ,
178+ "angle" : desc ,
179+ "rotation_point_x" : desc ,
180+ "rotation_point_y" : desc ,
181+ }
182+
183+ g = graph + self ._graph
184+
185+ conv = g .evaluator (description , requires )
186+ evald = conv .evaluate (query )
187+
188+ bbox = mtransforms .Bbox .from_extents (
189+ evald ["lower_left_x" ],
190+ evald ["lower_left_y" ],
191+ evald ["upper_right_x" ],
192+ evald ["upper_right_y" ],
193+ )
194+ rotation_point = (evald ["rotation_point_x" ], evald ["rotation_point_y" ])
195+
196+ scale = mtransforms .BboxTransformTo (bbox )
197+ rotate = (
198+ mtransforms .Affine2D ()
199+ .translate (- rotation_point [0 ], - rotation_point [1 ])
200+ .rotate_deg (evald ["angle" ])
201+ .translate (* rotation_point )
202+ )
203+
204+ descn : Desc = Desc (("N" ,), coordinates = "data" )
205+ xy : dict [str , Desc ] = {"x" : descn , "y" : descn }
206+ edges = [
207+ TransformEdge (
208+ "scale_and_rotate" ,
209+ desc_like (xy , coordinates = "abstract_path" ),
210+ xy ,
211+ transform = scale + rotate ,
212+ )
213+ ]
214+
215+ return Graph (edges )
216+
217+
218+ class RegularPolygon (Patch ):
219+ def __init__ (self , container , edges = None , ** kwargs ):
220+ super ().__init__ (container , edges , ** kwargs )
221+
222+ scalar = Desc ((), "data" )
223+ scalar_auto = Desc (())
224+ def_edges = [
225+ CoordinateEdge .from_coords (
226+ "centercoords" ,
227+ {"center_x" : scalar_auto , "center_y" : scalar_auto },
228+ "data" ,
229+ ),
230+ CoordinateEdge .from_coords (
231+ "orientationcoords" , {"orientation" : scalar_auto }, "data"
232+ ),
233+ CoordinateEdge .from_coords ("radiuscoords" , {"radius" : scalar_auto }, "data" ),
234+ CoordinateEdge .from_coords (
235+ "num_vertices_coords" , {"num_vertices" : scalar_auto }, "data"
236+ ),
237+ DefaultEdge .from_default_value ("orientation_def" , "orientation" , scalar , 0 ),
238+ DefaultEdge .from_default_value ("radius_def" , "radius" , scalar , 5 ),
239+ ]
240+
241+ self ._graph = self ._graph + Graph (def_edges )
242+
243+ def _get_dynamic_graph (self , query , description , graph , cacheset ):
244+ if cacheset == "clip" :
245+ return Graph ([])
246+
247+ desc = Desc ((), "data" )
248+ desc_abs = Desc (("N" ,), "abstract_path" )
249+
250+ requires = {
251+ "center_x" : desc ,
252+ "center_y" : desc ,
253+ "radius" : desc ,
254+ "orientation" : desc ,
255+ "num_vertices" : desc ,
256+ }
257+
258+ g = graph + self ._graph
259+
260+ conv = g .evaluator (description , requires )
261+ evald = conv .evaluate (query )
262+
263+ circ = mpath .Path .unit_regular_polygon (evald ["num_vertices" ])
264+
265+ scale = mtransforms .Affine2D ().scale (evald ["radius" ])
266+ rotate = mtransforms .Affine2D ().rotate (evald ["orientation" ])
267+ translate = mtransforms .Affine2D ().translate (
268+ evald ["center_x" ], evald ["center_y" ]
269+ )
270+
271+ descn : Desc = Desc (("N" ,), coordinates = "data" )
272+ xy : dict [str , Desc ] = {"x" : descn , "y" : descn }
273+ edges = [
274+ TransformEdge (
275+ "scale_and_rotate" ,
276+ desc_like (xy , coordinates = "abstract_path" ),
277+ xy ,
278+ transform = scale + rotate + translate ,
279+ ),
280+ DefaultEdge .from_default_value (
281+ "x_def" , "x" , desc_abs , circ .vertices .T [0 ], weight = 0.1
282+ ),
283+ DefaultEdge .from_default_value (
284+ "y_def" , "y" , desc_abs , circ .vertices .T [1 ], weight = 0.1
285+ ),
286+ DefaultEdge .from_default_value (
287+ "codes_def" ,
288+ "codes" ,
289+ desc_like (desc_abs , coordinates = "display" ),
290+ circ .codes ,
291+ weight = 0.1 ,
292+ ),
293+ ]
294+
295+ return Graph (edges )
296+
297+
114298class PatchWrapper (ProxyWrapper ):
115299 _wrapped_class = _Patch
116300 _privtized_methods = (
0 commit comments