Open
Description
Bug report
Bug summary
When calling Path.arc in a clockwise fashion (theta1 > theta2) , the angle wrapping results in drawing the arc over the opposing angle in a counterclockwise direction.
Code for reproduction
from matplotlib.path import Path
import matplotlib as mpl
import numpy as np
### Version
print("MPL Version", mpl.__version__)
### Demo the problem
theta1 = -1
theta2 = 1
path = Path.arc(theta1, theta2)
vrt = path.vertices
print(f"Counterclockwise: {len(vrt)} steps.")
theta1 = 1
theta2 = -1
path = Path.arc(theta1, theta2)
vrt = path.vertices
print(f"Clockwise: {len(vrt)} steps.")
### The following code demonstrates what is happening inside Path.arc
theta1 = -1.0
theta2 = 1.0
## Snippet from matplotlib.path.Path.arc
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
print(f"Counterclockwise: Input({theta1}, {theta2}), Output({eta1}, {eta2})")
theta1 = 1.0
theta2 = -1.0
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
print(f"Clockwise: Input({theta1}, {theta2}), Output({eta1}, {eta2})")
Actual outcome
MPL Version 3.0.3
Counterclockwise: 7 steps.
Clockwise: 49 steps.
Counterclockwise: Input(-1.0, 1.0), Output(-1.0, 1.0)
Clockwise: Input(1.0, -1.0), Output(1.0, 359.0)
Expected outcome
The direction of the arc should not matter, either direction should draw an arc that covers 2 degrees, and the vertices generated by the function should go in the direction chosen by the user.
Proposed fix
For my purposes I fixed the problem by adding another condition into the angle wrapping logic.
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
# This is the new logic
if theta1 > theta2:
eta1 += 360
eta1, eta2 = np.deg2rad([eta1, eta2])
This assures that directionality is kept and the correct angle is covered.
Matplotlib version
Probably irrelevant but:
- Operating system: Windows
- Matplotlib version: 3.0.3 (conda)
- Python version: 3.7.0 (conda)