diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index e72eb1a9ca73..086a1207dbd1 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -943,13 +943,20 @@ def arc(cls, theta1, theta2, n=None, is_wedge=False): polylines, quadratic or cubic Bezier curves `_. """ + # we want to get the same result when the input changes within [-tol, tol] + # this behavior is only for internal use to offset floating-point error + # so it should not be relied on by the user + tol = 1e-6 + halfpi = np.pi * 0.5 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: + # condition: theta1 != theta2 and eta2 <= eta1 + # implementation note: use np.isclose() may break when theta1 = 0 + if abs(theta1 - theta2) >= tol and (eta2 <= eta1 + tol): eta2 += 360 eta1, eta2 = np.deg2rad([eta1, eta2]) diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 8c0c32dc133b..a475b10c7755 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -475,6 +475,22 @@ def test_full_arc(offset): np.testing.assert_allclose(maxs, 1) +@pytest.mark.parametrize('offset', range(-720, 361, 45)) +def test_full_arc_rounding(offset): + # GH 26972 - edge case for floating point rounding + # we want get the same result when input of arc + # changes within [-tol, tol], where tol = 1e-6 + tol = 1e-6 + low = offset + high = 360 + offset + tol + + path = Path.arc(low, high) + mins = np.min(path.vertices, axis=0) + maxs = np.max(path.vertices, axis=0) + np.testing.assert_allclose(mins, -1) + np.testing.assert_allclose(maxs, 1) + + def test_disjoint_zero_length_segment(): this_path = Path( np.array([