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

FIX: correctly handle large arcs#17564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
tacaswell merged 5 commits intomatplotlib:masterfromtacaswell:fix_big_arc
Jun 17, 2020
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 46 additions & 15 deletionslib/matplotlib/patches.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1647,6 +1647,8 @@ def draw(self, renderer):
"""
if not hasattr(self, 'axes'):
raise RuntimeError('Arcs can only be used in Axes instances')
if not self.get_visible():
return

self._recompute_transform()

Expand All@@ -1659,14 +1661,40 @@ def theta_stretch(theta, scale):
theta = np.deg2rad(theta)
x = np.cos(theta)
y = np.sin(theta)
return np.rad2deg(np.arctan2(scale * y, x))
theta1 = theta_stretch(self.theta1, width / height)
theta2 = theta_stretch(self.theta2, width / height)

# Get width and height in pixels
width, height = self.get_transform().transform((width, height))
stheta = np.rad2deg(np.arctan2(scale * y, x))
# arctan2 has the range [-pi, pi], we expect [0, 2*pi]
return (stheta + 360) % 360

theta1 = self.theta1
theta2 = self.theta2

if (
# if we need to stretch the angles because we are distorted
width != height
# and we are not doing a full circle.
#
# 0 and 360 do not exactly round-trip through the angle
# stretching (due to both float precision limitations and
# the difference between the range of arctan2 [-pi, pi] and
# this method [0, 360]) so avoid doing it if we don't have to.
and not (theta1 != theta2 and theta1 % 360 == theta2 % 360)
Copy link
Contributor

@anntzeranntzerJun 16, 2020
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

probably needs a comment, IIRC you do this because theta1 and theta2 may not match anymore after stretching? (i.e. why can't you just always stretch)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

can you instead first take everything mod 360 and then always stretch?

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I tried that and it did not work, as0%360 == 360%360. I guess we could keep track of iftheta1 == theta2 up front and then add back 360 if they were? I don't think we want to special casetheta1 == theta2 as input to mean "full circle" not "no arc".

):
theta1 = theta_stretch(self.theta1, width / height)
theta2 = theta_stretch(self.theta2, width / height)

# Get width and height in pixels we need to use
# `self.get_data_transform` rather than `self.get_transform`
# because we want the transform from dataspace to the
# screen space to estimate how big the arc will be in physical
# units when rendered (the transform that we get via
# `self.get_transform()` goes from an idealized unit-radius
# space to screen space).
data_to_screen_trans = self.get_data_transform()
pwidth, pheight = (data_to_screen_trans.transform((width, height)) -
data_to_screen_trans.transform((0, 0)))
inv_error = (1.0 / 1.89818e-6) * 0.5
if width < inv_error and height < inv_error:

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

Expand DownExpand Up@@ -1700,29 +1728,32 @@ def segment_circle_intersect(x0, y0, x1, y1):
y0e, y1e = y0, y1
xys = line_circle_intersect(x0, y0, x1, y1)
xs, ys = xys.T
return xys[(x0e - epsilon < xs) & (xs < x1e + epsilon)
& (y0e - epsilon < ys) & (ys < y1e + epsilon)]
return xys[
(x0e - epsilon < xs) & (xs < x1e + epsilon)
& (y0e - epsilon < ys) & (ys < y1e + epsilon)
]

# Transforms the axes box_path so that it is relative to the unit
# circle in the same way that it is relative to the desired ellipse.
box_path = Path.unit_rectangle()
box_path_transform = (transforms.BboxTransformTo(self.axes.bbox)
+ self.get_transform().inverted())
box_path =box_path.transformed(box_path_transform)
box_path =Path.unit_rectangle().transformed(box_path_transform)

thetas = set()
# For each of the point pairs, there is a line segment
for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]):
xy = segment_circle_intersect(*p0, *p1)
x, y = xy.T
theta = np.rad2deg(np.arctan2(y, x))
# arctan2 return [-pi, pi), the rest of our angles are in
# [0, 360], adjust as needed.
theta = (np.rad2deg(np.arctan2(y, x)) + 360) % 360
thetas.update(theta[(theta1 < theta) & (theta < theta2)])
thetas = sorted(thetas) + [theta2]

last_theta = theta1
theta1_rad = np.deg2rad(theta1)
inside = box_path.contains_point((np.cos(theta1_rad),
np.sin(theta1_rad)))
inside = box_path.contains_point(
(np.cos(theta1_rad), np.sin(theta1_rad))
)

# save original path
path_original = self._path
Expand Down
Binary file modifiedlib/matplotlib/tests/baseline_images/test_axes/arc_angles.png
View file
Open in desktop
Loading
Sorry, something went wrong.Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

[8]ページ先頭

©2009-2025 Movatter.jp