@@ -1607,6 +1607,8 @@ def draw(self, renderer):
1607
1607
"""
1608
1608
if not hasattr (self ,'axes' ):
1609
1609
raise RuntimeError ('Arcs can only be used in Axes instances' )
1610
+ if not self .get_visible ():
1611
+ return
1610
1612
1611
1613
self ._recompute_transform ()
1612
1614
@@ -1619,14 +1621,40 @@ def theta_stretch(theta, scale):
1619
1621
theta = np .deg2rad (theta )
1620
1622
x = np .cos (theta )
1621
1623
y = np .sin (theta )
1622
- return np .rad2deg (np .arctan2 (scale * y ,x ))
1623
- theta1 = theta_stretch (self .theta1 ,width / height )
1624
- theta2 = theta_stretch (self .theta2 ,width / height )
1625
-
1626
- # Get width and height in pixels
1627
- width ,height = self .get_transform ().transform ((width ,height ))
1624
+ stheta = np .rad2deg (np .arctan2 (scale * y ,x ))
1625
+ # arctan2 has the range [-pi, pi], we expect [0, 2*pi]
1626
+ return (stheta + 360 )% 360
1627
+
1628
+ theta1 = self .theta1
1629
+ theta2 = self .theta2
1630
+
1631
+ if (
1632
+ # if we need to stretch the angles because we are distorted
1633
+ width != height
1634
+ # and we are not doing a full circle.
1635
+ #
1636
+ # 0 and 360 do not exactly round-trip through the angle
1637
+ # stretching (due to both float precision limitations and
1638
+ # the difference between the range of arctan2 [-pi, pi] and
1639
+ # this method [0, 360]) so avoid doing it if we don't have to.
1640
+ and not (theta1 != theta2 and theta1 % 360 == theta2 % 360 )
1641
+ ):
1642
+ theta1 = theta_stretch (self .theta1 ,width / height )
1643
+ theta2 = theta_stretch (self .theta2 ,width / height )
1644
+
1645
+ # Get width and height in pixels we need to use
1646
+ # `self.get_data_transform` rather than `self.get_transform`
1647
+ # because we want the transform from dataspace to the
1648
+ # screen space to estimate how big the arc will be in physical
1649
+ # units when rendered (the transform that we get via
1650
+ # `self.get_transform()` goes from an idealized unit-radius
1651
+ # space to screen space).
1652
+ data_to_screen_trans = self .get_data_transform ()
1653
+ pwidth ,pheight = (data_to_screen_trans .transform ((width ,height ))-
1654
+ data_to_screen_trans .transform ((0 ,0 )))
1628
1655
inv_error = (1.0 / 1.89818e-6 )* 0.5
1629
- if width < inv_error and height < inv_error :
1656
+
1657
+ if pwidth < inv_error and pheight < inv_error :
1630
1658
self ._path = Path .arc (theta1 ,theta2 )
1631
1659
return Patch .draw (self ,renderer )
1632
1660
@@ -1660,29 +1688,32 @@ def segment_circle_intersect(x0, y0, x1, y1):
1660
1688
y0e ,y1e = y0 ,y1
1661
1689
xys = line_circle_intersect (x0 ,y0 ,x1 ,y1 )
1662
1690
xs ,ys = xys .T
1663
- return xys [(x0e - epsilon < xs )& (xs < x1e + epsilon )
1664
- & (y0e - epsilon < ys )& (ys < y1e + epsilon )]
1691
+ return xys [
1692
+ (x0e - epsilon < xs )& (xs < x1e + epsilon )
1693
+ & (y0e - epsilon < ys )& (ys < y1e + epsilon )
1694
+ ]
1665
1695
1666
1696
# Transforms the axes box_path so that it is relative to the unit
1667
1697
# circle in the same way that it is relative to the desired ellipse.
1668
- box_path = Path .unit_rectangle ()
1669
1698
box_path_transform = (transforms .BboxTransformTo (self .axes .bbox )
1670
- - self .get_transform ())
1671
- box_path = box_path .transformed (box_path_transform )
1699
+ + self .get_transform (). inverted ())
1700
+ box_path = Path . unit_rectangle () .transformed (box_path_transform )
1672
1701
1673
1702
thetas = set ()
1674
1703
# For each of the point pairs, there is a line segment
1675
1704
for p0 ,p1 in zip (box_path .vertices [:- 1 ],box_path .vertices [1 :]):
1676
1705
xy = segment_circle_intersect (* p0 ,* p1 )
1677
1706
x ,y = xy .T
1678
- theta = np .rad2deg (np .arctan2 (y ,x ))
1707
+ # arctan2 return [-pi, pi), the rest of our angles are in
1708
+ # [0, 360], adjust as needed.
1709
+ theta = (np .rad2deg (np .arctan2 (y ,x ))+ 360 )% 360
1679
1710
thetas .update (theta [(theta1 < theta )& (theta < theta2 )])
1680
1711
thetas = sorted (thetas )+ [theta2 ]
1681
-
1682
1712
last_theta = theta1
1683
1713
theta1_rad = np .deg2rad (theta1 )
1684
- inside = box_path .contains_point ((np .cos (theta1_rad ),
1685
- np .sin (theta1_rad )))
1714
+ inside = box_path .contains_point (
1715
+ (np .cos (theta1_rad ),np .sin (theta1_rad ))
1716
+ )
1686
1717
1687
1718
# save original path
1688
1719
path_original = self ._path