FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Set correct path for Arc · matplotlib/matplotlib@74bf6ae · GitHub

Repository navigation

Commit 74bf6ae

Browse files
committed
Set correct path for Arc
1 parent 3245d39 commit 74bf6ae

6 files changed

Lines changed: 179 additions & 41 deletions

File tree

‎lib/matplotlib/patches.py‎

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,6 +1968,9 @@ def __init__(self, xy, width, height, angle=0.0,
19681968

19691969
self.theta1 = theta1
19701970
self.theta2 = theta2
1971+
self._theta1, self._theta2, self._width, self._height = \
1972+
self._theta_stretch()
1973+
self._path = Path.arc(self._theta1, self._theta2)
19711974

19721975
@artist.allow_rasterization
19731976
def draw(self, renderer):
@@ -2023,36 +2026,7 @@ def draw(self, renderer):
20232026

20242027
self._recompute_transform()
20252028

2026-
width = self.convert_xunits(self.width)
2027-
height = self.convert_yunits(self.height)
2028-
2029-
# If the width and height of ellipse are not equal, take into account
2030-
# stretching when calculating angles to draw between
2031-
def theta_stretch(theta, scale):
2032-
theta = np.deg2rad(theta)
2033-
x = np.cos(theta)
2034-
y = np.sin(theta)
2035-
stheta = np.rad2deg(np.arctan2(scale * y, x))
2036-
# arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2037-
return (stheta + 360) % 360
2038-
2039-
theta1 = self.theta1
2040-
theta2 = self.theta2
2041-
2042-
if (
2043-
# if we need to stretch the angles because we are distorted
2044-
width != height
2045-
# and we are not doing a full circle.
2046-
#
2047-
# 0 and 360 do not exactly round-trip through the angle
2048-
# stretching (due to both float precision limitations and
2049-
# the difference between the range of arctan2 [-pi, pi] and
2050-
# this method [0, 360]) so avoid doing it if we don't have to.
2051-
and not (theta1 != theta2 and theta1 % 360 == theta2 % 360)
2052-
):
2053-
theta1 = theta_stretch(self.theta1, width / height)
2054-
theta2 = theta_stretch(self.theta2, width / height)
2055-
2029+
self._update_path()
20562030
# Get width and height in pixels we need to use
20572031
# `self.get_data_transform` rather than `self.get_transform`
20582032
# because we want the transform from dataspace to the
@@ -2061,12 +2035,12 @@ def theta_stretch(theta, scale):
20612035
# `self.get_transform()` goes from an idealized unit-radius
20622036
# space to screen space).
20632037
data_to_screen_trans = self.get_data_transform()
2064-
pwidth, pheight = (data_to_screen_trans.transform((width, height)) -
2065-
data_to_screen_trans.transform((0, 0)))
2038+
pwidth, pheight = (
2039+
data_to_screen_trans.transform((self._width, self._height)) -
2040+
data_to_screen_trans.transform((0, 0)))
20662041
inv_error = (1.0 / 1.89818e-6) * 0.5
20672042

20682043
if pwidth < inv_error and pheight < inv_error:
2069-
self._path = Path.arc(theta1, theta2)
20702044
return Patch.draw(self, renderer)
20712045

20722046
def line_circle_intersect(x0, y0, x1, y1):
@@ -2118,10 +2092,11 @@ def segment_circle_intersect(x0, y0, x1, y1):
21182092
# arctan2 return [-pi, pi), the rest of our angles are in
21192093
# [0, 360], adjust as needed.
21202094
theta = (np.rad2deg(np.arctan2(y, x)) + 360) % 360
2121-
thetas.update(theta[(theta1 < theta) & (theta < theta2)])
2122-
thetas = sorted(thetas) + [theta2]
2123-
last_theta = theta1
2124-
theta1_rad = np.deg2rad(theta1)
2095+
thetas.update(
2096+
theta[(self._theta1 < theta) & (theta < self._theta2)])
2097+
thetas = sorted(thetas) + [self._theta2]
2098+
last_theta = self._theta1
2099+
theta1_rad = np.deg2rad(self._theta1)
21252100
inside = box_path.contains_point(
21262101
(np.cos(theta1_rad), np.sin(theta1_rad))
21272102
)
@@ -2140,6 +2115,44 @@ def segment_circle_intersect(x0, y0, x1, y1):
21402115
# restore original path
21412116
self._path = path_original
21422117

2118+
def _update_path(self):
2119+
# Compute new values and update and set new _path if changed
2120+
stretched = self._theta_stretch()
2121+
if any(a != b for a, b in zip(stretched, (self._theta1, self._theta2,
2122+
self._width, self._height))):
2123+
self._theta1, self._theta2, self._width, self._height = stretched
2124+
self._path = Path.arc(self._theta1, self._theta2)
2125+
2126+
def _theta_stretch(self):
2127+
# If the width and height of ellipse are not equal, take into account
2128+
# stretching when calculating angles to draw between
2129+
def theta_stretch(theta, scale):
2130+
theta = np.deg2rad(theta)
2131+
x = np.cos(theta)
2132+
y = np.sin(theta)
2133+
stheta = np.rad2deg(np.arctan2(scale * y, x))
2134+
# arctan2 has the range [-pi, pi], we expect [0, 2*pi]
2135+
return (stheta + 360) % 360
2136+
2137+
width = self.convert_xunits(self.width)
2138+
height = self.convert_yunits(self.height)
2139+
if (
2140+
# if we need to stretch the angles because we are distorted
2141+
width != height
2142+
# and we are not doing a full circle.
2143+
#
2144+
# 0 and 360 do not exactly round-trip through the angle
2145+
# stretching (due to both float precision limitations and
2146+
# the difference between the range of arctan2 [-pi, pi] and
2147+
# this method [0, 360]) so avoid doing it if we don't have to.
2148+
and not (self.theta1 != self.theta2 and
2149+
self.theta1 % 360 == self.theta2 % 360)
2150+
):
2151+
theta1 = theta_stretch(self.theta1, width / height)
2152+
theta2 = theta_stretch(self.theta2, width / height)
2153+
return theta1, theta2, width, height
2154+
return self.theta1, self.theta2, width, height
2155+
21432156

21442157
def bbox_artist(artist, renderer, props=None, fill=True):
21452158
"""
4.16 KB
LoadingViewer requires iframe.
Lines changed: 85 additions & 0 deletions
LoadingViewer requires iframe.

‎lib/matplotlib/tests/test_patches.py‎

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import matplotlib as mpl
99
from matplotlib.patches import (Annulus, Ellipse, Patch, Polygon, Rectangle,
10-
FancyArrowPatch, FancyArrow, BoxStyle)
10+
FancyArrowPatch, FancyArrow, BoxStyle, Arc)
1111
from matplotlib.testing.decorators import image_comparison, check_figures_equal
1212
from matplotlib.transforms import Bbox
1313
import matplotlib.pyplot as plt
@@ -642,7 +642,7 @@ def test_large_arc():
642642
y = -2115
643643
diameter = 4261
644644
for ax in [ax1, ax2]:
645-
a = mpatches.Arc((x, y), diameter, diameter, lw=2, color='k')
645+
a = Arc((x, y), diameter, diameter, lw=2, color='k')
646646
ax.add_patch(a)
647647
ax.set_axis_off()
648648
ax.set_aspect('equal')
@@ -669,7 +669,7 @@ def test_rotated_arcs():
669669
for prescale, centers in zip((1 - .0001, (1 - .0001) / np.sqrt(2)),
670670
(on_axis_centers, diag_centers)):
671671
for j, (x_sign, y_sign) in enumerate(centers, start=k):
672-
a = mpatches.Arc(
672+
a = Arc(
673673
(x_sign * scale * prescale,
674674
y_sign * scale * prescale),
675675
scale * sx,
@@ -808,3 +808,32 @@ def test_default_capstyle():
808808
def test_default_joinstyle():
809809
patch = Patch()
810810
assert patch.get_joinstyle() == 'miter'
811+
812+
813+
@image_comparison(["autoscale_arc"], extensions=['png', 'svg'],
814+
style="mpl20")
815+
def test_autoscale_arc():
816+
fig, axs = plt.subplots(1, 3, squeeze=False, figsize=(4, 1))
817+
arc_lists = (
818+
[Arc((0, 0), 1, 1, theta1=0, theta2=90)],
819+
[Arc((0.5, 0.5), 1.5, 0.5, theta1=10, theta2=20)],
820+
[Arc((0.5, 0.5), 1.5, 0.5, theta1=10, theta2=20),
821+
Arc((0.5, 0.5), 2.5, 0.5, theta1=110, theta2=120),
822+
Arc((0.5, 0.5), 3.5, 0.5, theta1=210, theta2=220),
823+
Arc((0.5, 0.5), 4.5, 0.5, theta1=310, theta2=320)])
824+
825+
for ax, arcs in zip(axs[0], arc_lists):
826+
for arc in arcs:
827+
ax.add_patch(arc)
828+
ax.autoscale()
829+
ax.set_axis_off()
830+
831+
832+
@check_figures_equal(extensions=["png", 'svg', 'pdf', 'eps'])
833+
def test_arc_in_collection(fig_test, fig_ref):
834+
arc1 = Arc([.5, .5], .5, 1, theta1=0, theta2=60, angle=20)
835+
arc2 = Arc([.5, .5], .5, 1, theta1=0, theta2=60, angle=20)
836+
col = mcollections.PatchCollection(patches=[arc2], facecolors='none',
837+
edgecolors='k')
838+
fig_ref.subplots().add_patch(arc1)
839+
fig_test.subplots().add_collection(col)
48.1 KB
LoadingViewer requires iframe.

‎lib/mpl_toolkits/tests/test_mplot3d.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import matplotlib as mpl
88
from matplotlib.backend_bases import MouseButton
99
from matplotlib import cm
10-
from matplotlib import colors as mcolors
10+
from matplotlib import colors as mcolors, patches as mpatch
1111
from matplotlib.testing.decorators import image_comparison, check_figures_equal
1212
from matplotlib.testing.widgets import mock_event
1313
from matplotlib.collections import LineCollection, PolyCollection
@@ -1742,3 +1742,14 @@ def test_view_init_vertical_axis(
17421742
tickdir_expected = tickdirs_expected[i]
17431743
tickdir_actual = axis._get_tickdir()
17441744
np.testing.assert_array_equal(tickdir_expected, tickdir_actual)
1745+
1746+
1747+
@image_comparison(baseline_images=['arc_pathpatch.png'],
1748+
remove_text=True,
1749+
style='default')
1750+
def test_arc_pathpatch():
1751+
ax = plt.subplot(1, 1, 1, projection="3d")
1752+
a = mpatch.Arc((0.5, 0.5), width=0.5, height=0.9,
1753+
angle=20, theta1=10, theta2=130)
1754+
ax.add_patch(a)
1755+
art3d.pathpatch_2d_to_3d(a, z=0, zdir='z')

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL