@@ -32,10 +32,11 @@ class Spine(mpatches.Patch):
32
32
Spines are subclasses of class:`~matplotlib.patches.Patch`, and
33
33
inherit much of their behavior.
34
34
35
- Spines draw a line or a circle, depending if
36
- function:`~matplotlib.spines.Spine.set_patch_line` or
37
- function:`~matplotlib.spines.Spine.set_patch_circle` has been
38
- called. Line-like is the default.
35
+ Spines draw a line, a circle, or an arc depending if
36
+ function:`~matplotlib.spines.Spine.set_patch_line`,
37
+ function:`~matplotlib.spines.Spine.set_patch_circle`, or
38
+ function:`~matplotlib.spines.Spine.set_patch_arc` has been called.
39
+ Line-like is the default.
39
40
40
41
"""
41
42
def __str__ (self ):
@@ -77,10 +78,11 @@ def __init__(self, axes, spine_type, path, **kwargs):
77
78
self ._path = path
78
79
79
80
# To support drawing both linear and circular spines, this
80
- # class implements Patch behavior two ways. If
81
+ # class implements Patch behavior three ways. If
81
82
# self._patch_type == 'line', behave like a mpatches.PathPatch
82
83
# instance. If self._patch_type == 'circle', behave like a
83
- # mpatches.Ellipse instance.
84
+ # mpatches.Ellipse instance. If self._patch_type == 'arc', behave like
85
+ # a mpatches.Arc instance.
84
86
self ._patch_type = 'line'
85
87
86
88
# Behavior copied from mpatches.Ellipse:
@@ -102,13 +104,25 @@ def get_smart_bounds(self):
102
104
"""get whether the spine has smart bounds"""
103
105
return self ._smart_bounds
104
106
107
+ def set_patch_arc (self , center , radius , theta1 , theta2 ):
108
+ """set the spine to be arc-like"""
109
+ self ._patch_type = 'arc'
110
+ self ._center = center
111
+ self ._width = radius * 2
112
+ self ._height = radius * 2
113
+ self ._theta1 = theta1
114
+ self ._theta2 = theta2
115
+ self ._path = mpath .Path .arc (theta1 , theta2 )
116
+ # arc drawn on axes transform
117
+ self .set_transform (self .axes .transAxes )
118
+ self .stale = True
119
+
105
120
def set_patch_circle (self , center , radius ):
106
121
"""set the spine to be circular"""
107
122
self ._patch_type = 'circle'
108
123
self ._center = center
109
124
self ._width = radius * 2
110
125
self ._height = radius * 2
111
- self ._angle = 0
112
126
# circle drawn on axes transform
113
127
self .set_transform (self .axes .transAxes )
114
128
self .stale = True
@@ -125,18 +139,17 @@ def _recompute_transform(self):
125
139
maxes it very important to call the accessor method and
126
140
not directly access the transformation member variable.
127
141
"""
128
- assert self ._patch_type == ' circle'
142
+ assert self ._patch_type in ( 'arc' , ' circle')
129
143
center = (self .convert_xunits (self ._center [0 ]),
130
144
self .convert_yunits (self ._center [1 ]))
131
145
width = self .convert_xunits (self ._width )
132
146
height = self .convert_yunits (self ._height )
133
147
self ._patch_transform = mtransforms .Affine2D () \
134
148
.scale (width * 0.5 , height * 0.5 ) \
135
- .rotate_deg (self ._angle ) \
136
149
.translate (* center )
137
150
138
151
def get_patch_transform (self ):
139
- if self ._patch_type == ' circle' :
152
+ if self ._patch_type in ( 'arc' , ' circle') :
140
153
self ._recompute_transform ()
141
154
return self ._patch_transform
142
155
else :
@@ -255,17 +268,48 @@ def _adjust_location(self):
<
8000
td data-grid-cell-id="diff-4e07c249abaaf29d0bb2bef9c5b12a86ccaa4895fcae37004bacf9d406043f8b-255-268-0" data-selected="false" role="gridcell" style="background-color:var(--bgColor-default);text-align:center" tabindex="-1" valign="top" class="focusable-grid-cell diff-line-number position-relative diff-line-number-neutral left-side">255
268
else :
256
269
low , high = self ._bounds
257
270
258
- v1 = self ._path .vertices
259
- assert v1 .shape == (2 , 2 ), 'unexpected vertices shape'
260
- if self .spine_type in ['left' , 'right' ]:
261
- v1 [0 , 1 ] = low
262
- v1 [1 , 1 ] = high
263
- elif self .spine_type in ['bottom' , 'top' ]:
264
- v1 [0 , 0 ] = low
265
- v1 [1 , 0 ] = high
271
+ if self ._patch_type == 'arc' :
272
+ if self .spine_type in ('bottom' , 'top' ):
273
+ try :
274
+ direction = self .axes .get_theta_direction ()
275
+ except AttributeError :
276
+ direction = 1
277
+ try :
278
+ offset = self .axes .get_theta_offset ()
279
+ except AttributeError :
280
+ offset = 0
281
+ low = low * direction + offset
282
+ high = high * direction + offset
283
+ if low > high :
284
+ low , high = high , low
285
+
286
+ self ._path = mpath .Path .arc (np .rad2deg (low ), np .rad2deg (high ))
287
+
288
+ if self .spine_type == 'bottom' :
289
+ rmin , rmax = self .axes .viewLim .intervaly
290
+ try :
291
+ rorigin = self .axes .get_rorigin ()
292
+ except AttributeError :
293
+ rorigin = rmin
294
+ scaled_diameter = (rmin - rorigin ) / (rmax - rorigin )
295
+ self ._height = scaled_diameter
296
+ self ._width = scaled_diameter
297
+
298
+ else :
299
+ raise ValueError ('unable to set bounds for spine "%s"' %
300
+ self .spine_type )
266
301
else :
267
- raise ValueError ('unable to set bounds for spine "%s"' %
268
- self .spine_type )
302
+ v1 = self ._path .vertices
303
+ assert v1 .shape == (2 , 2 ), 'unexpected vertices shape'
304
+ if self .spine_type in ['left' , 'right' ]:
305
+ v1 [0 , 1 ] = low
306
+ v1 [1 , 1 ] = high
307
+ elif self .spine_type in ['bottom' , 'top' ]:
308
+ v1 [0 , 0 ] = low
309
+ v1 [1 , 0 ] = high
310
+ else :
311
+ raise ValueError ('unable to set bounds for spine "%s"' %
312
+ self .spine_type )
269
313
270
314
@allow_rasterization
271
315
def draw (self , renderer ):
@@ -463,6 +507,17 @@ def linear_spine(cls, axes, spine_type, **kwargs):
463
507
464
508
return result
465
509
510
+ @classmethod
511
+ def arc_spine (cls , axes , spine_type , center , radius , theta1 , theta2 ,
512
+ ** kwargs ):
513
+ """
514
+ (classmethod) Returns an arc :class:`Spine`.
515
+ """
516
+ path = mpath .Path .arc (theta1 , theta2 )
517
+ result = cls (axes , spine_type , path , ** kwargs )
518
+ result .set_patch_arc (center , radius , theta1 , theta2 )
519
+ return result
520
+
466
521
@classmethod
467
522
def circular_spine (cls , axes , center , radius , ** kwargs ):
468
523
"""
0 commit comments