Skip to content

Navigation Menu

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

[Bug]: numerical instability of Path.arc for 0 degree or 360 degree arc #29953

Copy link
Copy link
Open
@robtovey

Description

@robtovey
Issue body actions

Bug summary

Trying to create an arc path of 0/360 degrees sometimes results in one of 360/0 degrees due to floating point weirdness.

Code for reproduction

from matplotlib import patches, path, pyplot

fig, ax = pyplot.subplots(ncols=3)
ax[0].add_patch(patches.PathPatch(path.Path.arc(theta1=-90 - 1e-14, theta2=270)))
ax[0].set_title("arc(-90-1e-14, 270), should be a circle")
ax[1].add_patch(patches.PathPatch(path.Path.arc(theta1=-90, theta2=270)))
ax[1].set_title("arc(-90, 270), is a circle")
ax[2].add_patch(patches.PathPatch(path.Path.arc(theta1=-90, theta2=-90 - 1e-14)))
ax[2].set_title("arc(-90, -90-1e-14), should not be a circle")
for a in ax:
    a.set_xlim(-1, 1)
    a.set_ylim(-1, 1)
    a.set_aspect("equal")
pyplot.show()

Actual outcome

Image

Expected outcome

I expect the first plot to be a circle, identical to the second.
I expect the third plot to be empty

Additional information

The location of the bug is not hard to find:

eta1 = theta1
eta2 = theta2 - 360 * np.floor((theta2 - theta1) / 360)
# Ensure 2pi range is not flattened to 0 due to floating-point errors,
# but don't try to expand existing 0 range.
if theta2 != theta1 and eta2 <= eta1:
eta2 += 360

At runtime the first example becomes (-90 <= -90 - 1e-14) == False, which therefore skips the +360 bump.

What is much harder is to understand is what the intention is here.
If you can help me to understand what behaviour you'd like, I'd be happy to put together a PR for it.

I think theta2 < theta1 always gives an unexpected result:

  • The docstring does not clarify what should happen, therefore my assumption is that it should return an anti-clockwise arc
  • The np.floor will mean it becomes the angle range [theta1, theta2+360], which gives the third plot which I believe should not be a circle
  • The special casing only treats eta2 += 360, not eta2 -= 360

It would be great if either the docstring could be clarified or a ValueError raised on unexpected inputs here.

Operating system

No response

Matplotlib Version

3.10.0

Matplotlib Backend

No response

Python version

No response

Jupyter version

No response

Installation

pip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

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