@@ -1552,9 +1552,103 @@ def get_angle(self):
15521552 angle = property (get_angle , set_angle )
15531553
15541554
1555- class Circle (Ellipse ):
1556- """A circle patch."""
15571555
1556+ class Annulus (Patch ):
1557+ """
1558+ An elliptical annulus.
1559+ """
1560+
1561+ def __str__ (self ):
1562+ if self .a == self .b :
1563+ fmt = "Annulus(xy=(%s, %s), r=%s, width=%s, angle=%s)"
1564+ pars = (self .center [0 ], self .center [1 ],
1565+ self .a , self .width , self .angle )
1566+ else :
1567+ fmt = "Annulus(xy=(%s, %s), a=%s, b=%s, width=%s, angle=%s)"
1568+ pars = (self .center [0 ], self .center [1 ],
1569+ self .a , self .b , self .width , self .angle )
1570+ return fmt % pars
1571+
1572+ @docstring .dedent_interpd
1573+ def __init__ (self , xy , r , width , angle = 0.0 , ** kwargs ):
1574+ """
1575+ *xy*
1576+ center of annulus
1577+
1578+ *r*
1579+ if float:
1580+ radius of the outer circle
1581+ if array-like of size 2:
1582+ semi-major and -minor axes of outer ellipse
1583+
1584+ *width*
1585+ width of the annulus
1586+
1587+ *angle*
1588+ rotation in degrees (anti-clockwise)
1589+
1590+ Valid kwargs are:
1591+ %(Patch)s
1592+ """
1593+ Patch .__init__ (self , ** kwargs )
1594+
1595+ if np .size (r ) == 2 :
1596+ self .a , self .b = r
1597+ elif np .size (r ) == 1 :
1598+ self .a = self .b = float (r )
1599+ else :
1600+ raise ValueError (
1601+ 'r parameter should be either float, or sequence of size 2' )
1602+
1603+ if min (self .a , self .b ) <= width :
1604+ raise ValueError (
1605+ 'Width should be smaller than semi-minor axis' )
1606+
1607+ self .center = xy
1608+ self .width = width
1609+ self .angle = angle
1610+ self ._path = None
1611+ # Note: This cannot be calculated until this is added to an Axes
1612+ self ._patch_transform = transforms .IdentityTransform ()
1613+
1614+ def _transform_verts (self , verts , a , b ):
1615+ center = (self .convert_xunits (self .center [0 ]),
1616+ self .convert_yunits (self .center [1 ]))
1617+ a = self .convert_xunits (a )
1618+ b = self .convert_yunits (b )
1619+ tr = transforms .Affine2D () \
1620+ .scale (a , b ) \
1621+ .rotate_deg (self .angle ) \
1622+ .translate (* center )
1623+
1624+ return tr .transform (verts )
1625+
1626+ def _recompute_path (self ):
1627+
1628+ # circular arc
1629+ arc = Path .arc (0 , 360 )
1630+
1631+ # annulus needs to draw the outer ring
1632+ # followed by a reversed and scaled inner ring
1633+ a , b , w = self .a , self .b , self .width
1634+ v1 = self ._transform_verts (arc .vertices , a , b )
1635+ v2 = self ._transform_verts (arc .vertices [::- 1 ], a - w , b - w )
1636+ v = np .vstack ([v1 , v2 , v1 [0 , :], (0 , 0 )])
1637+ c = np .hstack ([arc .codes , arc .codes , Path .MOVETO , Path .CLOSEPOLY ])
1638+ c [len (arc .codes )] = Path .MOVETO
1639+
1640+ self ._path = Path (v , c )
1641+
1642+ def get_path (self ):
1643+ if self ._path is None :
1644+ self ._recompute_path ()
1645+ return self ._path
1646+
1647+
1648+ class Circle (Ellipse ):
1649+ """
1650+ A circle patch.
1651+ """
15581652 def __str__ (self ):
15591653 pars = self .center [0 ], self .center [1 ], self .radius
15601654 fmt = "Circle(xy=(%g, %g), radius=%g)"
0 commit comments