88from .wrappers import ProxyWrapper , _stale_wrapper
99
1010from .artist import Artist , _renderer_group
11- from .description import Desc
11+ from .description import Desc , desc_like
1212from .containers import DataContainer
13- from .conversion_edge import Graph , CoordinateEdge , DefaultEdge
13+ from .conversion_edge import Graph , CoordinateEdge , DefaultEdge , TransformEdge
1414
1515
1616class Patch (Artist ):
@@ -21,8 +21,14 @@ def __init__(self, container, edges=None, **kwargs):
2121 def_edges = [
2222 CoordinateEdge .from_coords ("xycoords" , {"x" : "auto" , "y" : "auto" }, "data" ),
2323 CoordinateEdge .from_coords ("codes" , {"codes" : "auto" }, "display" ),
24- CoordinateEdge .from_coords ("facecolor" , {"color" : Desc (())}, "display" ),
25- 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+ ),
2632 CoordinateEdge .from_coords ("linewidth" , {"linewidth" : Desc (())}, "display" ),
2733 CoordinateEdge .from_coords ("hatch" , {"hatch" : Desc (())}, "display" ),
2834 CoordinateEdge .from_coords ("alpha" , {"alpha" : Desc (())}, "display" ),
@@ -45,8 +51,8 @@ def draw(self, renderer, graph: Graph) -> None:
4551 "x" : desc ,
4652 "y" : desc ,
4753 "codes" : desc ,
48- "facecolor" : scalar ,
49- "edgecolor" : scalar ,
54+ "facecolor" : Desc ((), "display" ) ,
55+ "edgecolor" : Desc (( "M" ,), "display" ) ,
5056 "linewidth" : scalar ,
5157 "linestyle" : scalar ,
5258 "hatch" : scalar ,
@@ -69,7 +75,7 @@ def draw(self, renderer, graph: Graph) -> None:
6975 with _renderer_group (renderer , "patch" , None ):
7076 gc = renderer .new_gc ()
7177
72- gc .set_foreground (evald ["facecolor " ], isRGBA = False )
78+ gc .set_foreground (evald ["edgecolor " ], isRGBA = False )
7379 gc .set_clip_rectangle (
7480 mtransforms .Bbox .from_extents (clipx [0 ], clipy [0 ], clipx [1 ], clipy [1 ])
7581 )
@@ -112,6 +118,182 @@ class Rectangle(Patch):
112118 def __init__ (self , container , edges = None , ** kwargs ):
113119 super ().__init__ (container , edges , ** kwargs )
114120
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+
115297
116298class PatchWrapper (ProxyWrapper ):
117299 _wrapped_class = _Patch
0 commit comments