Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commitd1e2a20

Browse files
committed
FIX: correctly handle large arcs
The draw method of mpatches.Arc has two paths: - if the arc is "small" compared to its size in the rendered image then render the whole arc and let clipping do it's thing - if the arc is "big" compared to its size on the screen then sort out where the circle intersects the axes boundary and only draw that part of itThis makes several changes to the Arc draw method: - make sure that we keep angles in [0, 360) range - only go through the angle stretching code if we need to (to avoid numerical instability of angles not round-tripping with scale=1) - compute length, not offset from origin of width / height and use the correct transform. Previously we were effectively squaring the height and widthTests: - Adjusted an existing test image to use this failing case and to exercise both code paths. - Added a test function of ensuring we can draw a big arc in each quadrant
1 parentefda565 commitd1e2a20

File tree

4 files changed

+623
-29
lines changed

4 files changed

+623
-29
lines changed

‎lib/matplotlib/patches.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,14 +1659,35 @@ def theta_stretch(theta, scale):
16591659
theta=np.deg2rad(theta)
16601660
x=np.cos(theta)
16611661
y=np.sin(theta)
1662-
returnnp.rad2deg(np.arctan2(scale*y,x))
1663-
theta1=theta_stretch(self.theta1,width/height)
1664-
theta2=theta_stretch(self.theta2,width/height)
1662+
stheta=np.rad2deg(np.arctan2(scale*y,x))
1663+
# arctan2 has the range [-pi, pi], we expect [0, 2*pi]
1664+
1665+
return (stheta+360)%360
1666+
1667+
theta1=self.theta1
1668+
theta2=self.theta2
1669+
1670+
if (
1671+
# if we need to stretch the angles because we are distorted
1672+
width!=height
1673+
# and we are not doing a full circle
1674+
andnot (theta1!=theta2andtheta1%360==theta2%360)
1675+
):
1676+
theta1=theta_stretch(self.theta1,width/height)
1677+
theta2=theta_stretch(self.theta2,width/height)
16651678

16661679
# Get width and height in pixels
1667-
width,height=self.get_transform().transform((width,height))
1680+
# we need to grab the tranfrom via a parent class method because
1681+
# we want the transform from the coordiante system the arc will be
1682+
# drawn in to the screen space.
1683+
# The transform that we get via `self.get_transform()` goes from
1684+
# an idealized unit-radius space to screen space
1685+
data_to_screen_trans=self.get_data_transform()
1686+
pwidth,pheight= (data_to_screen_trans.transform((width,height))-
1687+
data_to_screen_trans.transform((0,0)))
16681688
inv_error= (1.0/1.89818e-6)*0.5
1669-
ifwidth<inv_errorandheight<inv_error:
1689+
1690+
ifpwidth<inv_errorandpheight<inv_error:
16701691
self._path=Path.arc(theta1,theta2)
16711692
returnPatch.draw(self,renderer)
16721693

@@ -1700,29 +1721,32 @@ def segment_circle_intersect(x0, y0, x1, y1):
17001721
y0e,y1e=y0,y1
17011722
xys=line_circle_intersect(x0,y0,x1,y1)
17021723
xs,ys=xys.T
1703-
returnxys[(x0e-epsilon<xs)& (xs<x1e+epsilon)
1704-
& (y0e-epsilon<ys)& (ys<y1e+epsilon)]
1724+
returnxys[
1725+
(x0e-epsilon<xs)& (xs<x1e+epsilon)
1726+
& (y0e-epsilon<ys)& (ys<y1e+epsilon)
1727+
]
17051728

17061729
# Transforms the axes box_path so that it is relative to the unit
17071730
# circle in the same way that it is relative to the desired ellipse.
1708-
box_path=Path.unit_rectangle()
17091731
box_path_transform= (transforms.BboxTransformTo(self.axes.bbox)
17101732
+self.get_transform().inverted())
1711-
box_path=box_path.transformed(box_path_transform)
1733+
box_path=Path.unit_rectangle().transformed(box_path_transform)
17121734

17131735
thetas=set()
17141736
# For each of the point pairs, there is a line segment
17151737
forp0,p1inzip(box_path.vertices[:-1],box_path.vertices[1:]):
17161738
xy=segment_circle_intersect(*p0,*p1)
17171739
x,y=xy.T
1718-
theta=np.rad2deg(np.arctan2(y,x))
1740+
# arctan2 return [-pi, pi), the rest of our angles are in
1741+
# [0, 360], adjust as needed.
1742+
theta= (np.rad2deg(np.arctan2(y,x))+360)%360
17191743
thetas.update(theta[(theta1<theta)& (theta<theta2)])
17201744
thetas=sorted(thetas)+ [theta2]
1721-
17221745
last_theta=theta1
17231746
theta1_rad=np.deg2rad(theta1)
1724-
inside=box_path.contains_point((np.cos(theta1_rad),
1725-
np.sin(theta1_rad)))
1747+
inside=box_path.contains_point(
1748+
(np.cos(theta1_rad),np.sin(theta1_rad))
1749+
)
17261750

17271751
# save original path
17281752
path_original=self._path

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp