Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit beeba66

Browse filesBrowse files
authored
Merge pull request #8047 from dstansby/arc-theta
Correct theta values when drawing a non-circular arc
2 parents eaf297a + 0376d83 commit beeba66
Copy full SHA for beeba66

File tree

Expand file treeCollapse file tree

4 files changed

+53
-14
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+53
-14
lines changed
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Elliptical arcs now drawn between correct angles
2+
````````````````````````````````````````````````
3+
4+
The `matplotlib.patches.Arc` patch is now correctly drawn between the given
5+
angles.
6+
7+
Previously a circular arc was drawn and then stretched into an ellipse,
8+
so the resulting arc did not lie between *theta1* and *theta2*.

‎lib/matplotlib/patches.py

Copy file name to clipboardExpand all lines: lib/matplotlib/patches.py
+13-7Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,8 +1566,6 @@ def __init__(self, xy, width, height, angle=0.0,
15661566
self.theta1 = theta1
15671567
self.theta2 = theta2
15681568

1569-
self._path = Path.arc(self.theta1, self.theta2)
1570-
15711569
@allow_rasterization
15721570
def draw(self, renderer):
15731571
"""
@@ -1619,15 +1617,25 @@ def draw(self, renderer):
16191617

16201618
self._recompute_transform()
16211619

1622-
# Get the width and height in pixels
16231620
width = self.convert_xunits(self.width)
16241621
height = self.convert_yunits(self.height)
1622+
1623+
# If the width and height of ellipse are not equal, take into account
1624+
# stretching when calculating angles to draw between
1625+
def theta_stretch(theta, scale):
1626+
theta = np.deg2rad(theta)
1627+
x = np.cos(theta)
1628+
y = np.sin(theta)
1629+
return np.rad2deg(np.arctan2(scale * y, x))
1630+
theta1 = theta_stretch(self.theta1, width / height)
1631+
theta2 = theta_stretch(self.theta2, width / height)
1632+
1633+
# Get width and height in pixels
16251634
width, height = self.get_transform().transform_point(
16261635
(width, height))
16271636
inv_error = (1.0 / 1.89818e-6) * 0.5
1628-
16291637
if width < inv_error and height < inv_error:
1630-
# self._path = Path.arc(self.theta1, self.theta2)
1638+
self._path = Path.arc(theta1, theta2)
16311639
return Patch.draw(self, renderer)
16321640

16331641
def iter_circle_intersect_on_line(x0, y0, x1, y1):
@@ -1682,8 +1690,6 @@ def iter_circle_intersect_on_line_seg(x0, y0, x1, y1):
16821690
self.get_transform().inverted()
16831691
box_path = box_path.transformed(box_path_transform)
16841692

1685-
theta1 = self.theta1
1686-
theta2 = self.theta2
16871693
thetas = set()
16881694
# For each of the point pairs, there is a line segment
16891695
for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]):
Loading

‎lib/matplotlib/tests/test_axes.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_axes.py
+32-7Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,32 @@ def test_canonical():
10021002
ax.plot([1, 2, 3])
10031003

10041004

1005+
@image_comparison(baseline_images=['arc_angles'], remove_text=True,
1006+
style='default', extensions=['png'])
1007+
def test_arc_angles():
1008+
from matplotlib import patches
1009+
# Ellipse parameters
1010+
w = 2
1011+
h = 1
1012+
centre = (0.2, 0.5)
1013+
1014+
fig, axs = plt.subplots(3, 3)
1015+
for i, ax in enumerate(axs.flat):
1016+
theta2 = i * 360 / 9
1017+
theta1 = theta2 - 45
1018+
ax.add_patch(patches.Ellipse(centre, w, h, alpha=0.3))
1019+
ax.add_patch(patches.Arc(centre, w, h, theta1=theta1, theta2=theta2))
1020+
# Straight lines intersecting start and end of arc
1021+
ax.plot([2 * np.cos(np.deg2rad(theta1)) + centre[0],
1022+
centre[0],
1023+
2 * np.cos(np.deg2rad(theta2)) + centre[0]],
1024+
[2 * np.sin(np.deg2rad(theta1)) + centre[1],
1025+
centre[1],
1026+
2 * np.sin(np.deg2rad(theta2)) + centre[1]])
1027+
ax.set_xlim(-2, 2)
1028+
ax.set_ylim(-2, 2)
1029+
1030+
10051031
@image_comparison(baseline_images=['arc_ellipse'],
10061032
remove_text=True)
10071033
def test_arc_ellipse():
@@ -1010,15 +1036,14 @@ def test_arc_ellipse():
10101036
width, height = 1e-1, 3e-1
10111037
angle = -30
10121038

1013-
theta = np.arange(0.0, 360.0, 1.0)*np.pi/180.0
1014-
x = width/2. * np.cos(theta)
1015-
y = height/2. * np.sin(theta)
1039+
theta = np.arange(0.0, 360.0, 1.0) * np.pi / 180.0
1040+
x = width / 2. * np.cos(theta)
1041+
y = height / 2. * np.sin(theta)
10161042

1017-
rtheta = angle*np.pi/180.
1043+
rtheta = angle * np.pi / 180.
10181044
R = np.array([
1019-
[np.cos(rtheta), -np.sin(rtheta)],
1020-
[np.sin(rtheta), np.cos(rtheta)],
1021-
])
1045+
[np.cos(rtheta), -np.sin(rtheta)],
1046+
[np.sin(rtheta), np.cos(rtheta)]])
10221047

10231048
x, y = np.dot(R, np.array([x, y]))
10241049
x += xcenter

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.