diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index a61f01c0d48a..bef1c5f8184f 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -19,8 +19,7 @@ def test_empty_closed_path(): path = Path(np.zeros((0, 2)), closed=True) assert path.vertices.shape == (0, 2) assert path.codes is None - assert_array_equal(path.get_extents().extents, - transforms.Bbox.null().extents) + assert_array_equal(path.get_extents().extents, transforms.Bbox.null().extents) def test_readonly_path(): @@ -35,19 +34,19 @@ def modify_vertices(): def test_path_exceptions(): bad_verts1 = np.arange(12).reshape(4, 3) - with pytest.raises(ValueError, - match=re.escape(f'has shape {bad_verts1.shape}')): + with pytest.raises(ValueError, match=re.escape(f"has shape {bad_verts1.shape}")): Path(bad_verts1) bad_verts2 = np.arange(12).reshape(2, 3, 2) - with pytest.raises(ValueError, - match=re.escape(f'has shape {bad_verts2.shape}')): + with pytest.raises(ValueError, match=re.escape(f"has shape {bad_verts2.shape}")): Path(bad_verts2) good_verts = np.arange(12).reshape(6, 2) bad_codes = np.arange(2) - msg = re.escape(f"Your vertices have shape {good_verts.shape} " - f"but your codes have shape {bad_codes.shape}") + msg = re.escape( + f"Your vertices have shape {good_verts.shape} " + f"but your codes have shape {bad_codes.shape}" + ) with pytest.raises(ValueError, match=msg): Path(good_verts, bad_codes) @@ -57,23 +56,62 @@ def test_point_in_path(): path = Path._create_closed([(0, 0), (0, 1), (1, 1), (1, 0)]) points = [(0.5, 0.5), (1.5, 0.5)] ret = path.contains_points(points) - assert ret.dtype == 'bool' + assert ret.dtype == "bool" np.testing.assert_equal(ret, [True, False]) @pytest.mark.parametrize( "other_path, inside, inverted_inside", - [(Path([(0.25, 0.25), (0.25, 0.75), (0.75, 0.75), (0.75, 0.25), (0.25, 0.25)], - closed=True), True, False), - (Path([(-0.25, -0.25), (-0.25, 1.75), (1.75, 1.75), (1.75, -0.25), (-0.25, -0.25)], - closed=True), False, True), - (Path([(-0.25, -0.25), (-0.25, 1.75), (0.5, 0.5), - (1.75, 1.75), (1.75, -0.25), (-0.25, -0.25)], - closed=True), False, False), - (Path([(0.25, 0.25), (0.25, 1.25), (1.25, 1.25), (1.25, 0.25), (0.25, 0.25)], - closed=True), False, False), - (Path([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)], closed=True), False, False), - (Path([(2, 2), (2, 3), (3, 3), (3, 2), (2, 2)], closed=True), False, False)]) + [ + ( + Path( + [(0.25, 0.25), (0.25, 0.75), (0.75, 0.75), (0.75, 0.25), (0.25, 0.25)], + closed=True, + ), + True, + False, + ), + ( + Path( + [ + (-0.25, -0.25), + (-0.25, 1.75), + (1.75, 1.75), + (1.75, -0.25), + (-0.25, -0.25), + ], + closed=True, + ), + False, + True, + ), + ( + Path( + [ + (-0.25, -0.25), + (-0.25, 1.75), + (0.5, 0.5), + (1.75, 1.75), + (1.75, -0.25), + (-0.25, -0.25), + ], + closed=True, + ), + False, + False, + ), + ( + Path( + [(0.25, 0.25), (0.25, 1.25), (1.25, 1.25), (1.25, 0.25), (0.25, 0.25)], + closed=True, + ), + False, + False, + ), + (Path([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)], closed=True), False, False), + (Path([(2, 2), (2, 3), (3, 3), (3, 2), (2, 2)], closed=True), False, False), + ], +) def test_contains_path(other_path, inside, inverted_inside): path = Path([(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)], closed=True) assert path.contains_path(other_path) is inside @@ -90,8 +128,10 @@ def test_contains_points_negative_radius(): _test_paths = [ # interior extrema determine extents and degenerate derivative - Path([[0, 0], [1, 0], [1, 1], [0, 1]], - [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4]), + Path( + [[0, 0], [1, 0], [1, 1], [0, 1]], + [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4], + ), # a quadratic curve Path([[0, 0], [0, 1], [1, 0]], [Path.MOVETO, Path.CURVE3, Path.CURVE3]), # a linear curve, degenerate vertically @@ -101,11 +141,15 @@ def test_contains_points_negative_radius(): ] -_test_path_extents = [(0., 0., 0.75, 1.), (0., 0., 1., 0.5), (0., 1., 1., 1.), - (1., 2., 1., 2.)] +_test_path_extents = [ + (0.0, 0.0, 0.75, 1.0), + (0.0, 0.0, 1.0, 0.5), + (0.0, 1.0, 1.0, 1.0), + (1.0, 2.0, 1.0, 2.0), +] -@pytest.mark.parametrize('path, extents', zip(_test_paths, _test_path_extents)) +@pytest.mark.parametrize("path, extents", list(zip(_test_paths, _test_path_extents))) def test_exact_extents(path, extents): # notice that if we just looked at the control points to get the bounding # box of each curve, we would get the wrong answers. For example, for @@ -119,14 +163,12 @@ def test_exact_extents(path, extents): assert np.all(path.get_extents().extents == extents) -@pytest.mark.parametrize('ignored_code', [Path.CLOSEPOLY, Path.STOP]) +@pytest.mark.parametrize("ignored_code", [Path.CLOSEPOLY, Path.STOP]) def test_extents_with_ignored_codes(ignored_code): # Check that STOP and CLOSEPOLY points are ignored when calculating extents # of a path with only straight lines - path = Path([[0, 0], - [1, 1], - [2, 2]], [Path.MOVETO, Path.MOVETO, ignored_code]) - assert np.all(path.get_extents().extents == (0., 0., 1., 1.)) + path = Path([[0, 0], [1, 1], [2, 2]], [Path.MOVETO, Path.MOVETO, ignored_code]) + assert np.all(path.get_extents().extents == (0.0, 0.0, 1.0, 1.0)) def test_point_in_path_nan(): @@ -143,15 +185,22 @@ def test_nonlinear_containment(): ax.set(xscale="log", ylim=(0, 1)) polygon = ax.axvspan(1, 10) assert polygon.get_path().contains_point( - ax.transData.transform((5, .5)), polygon.get_transform()) + ax.transData.transform((5, 0.5)), polygon.get_transform() + ) assert not polygon.get_path().contains_point( - ax.transData.transform((.5, .5)), polygon.get_transform()) + ax.transData.transform((0.5, 0.5)), polygon.get_transform() + ) assert not polygon.get_path().contains_point( - ax.transData.transform((50, .5)), polygon.get_transform()) + ax.transData.transform((50, 0.5)), polygon.get_transform() + ) -@image_comparison(['arrow_contains_point.png'], remove_text=True, style='mpl20', - tol=0 if platform.machine() == 'x86_64' else 0.027) +@image_comparison( + ["arrow_contains_point.png"], + remove_text=True, + style="mpl20", + tol=0 if platform.machine() == "x86_64" else 0.027, +) def test_arrow_contains_point(): # fix bug (#8384) fig, ax = plt.subplots() @@ -159,29 +208,27 @@ def test_arrow_contains_point(): ax.set_ylim(0, 2) # create an arrow with Curve style - arrow = patches.FancyArrowPatch((0.5, 0.25), (1.5, 0.75), - arrowstyle='->', - mutation_scale=40) + arrow = patches.FancyArrowPatch( + (0.5, 0.25), (1.5, 0.75), arrowstyle="->", mutation_scale=40 + ) ax.add_patch(arrow) # create an arrow with Bracket style - arrow1 = patches.FancyArrowPatch((0.5, 1), (1.5, 1.25), - arrowstyle=']-[', - mutation_scale=40) + arrow1 = patches.FancyArrowPatch( + (0.5, 1), (1.5, 1.25), arrowstyle="]-[", mutation_scale=40 + ) ax.add_patch(arrow1) # create an arrow with other arrow style - arrow2 = patches.FancyArrowPatch((0.5, 1.5), (1.5, 1.75), - arrowstyle='fancy', - fill=False, - mutation_scale=40) + arrow2 = patches.FancyArrowPatch( + (0.5, 1.5), (1.5, 1.75), arrowstyle="fancy", fill=False, mutation_scale=40 + ) ax.add_patch(arrow2) patches_list = [arrow, arrow1, arrow2] # generate some points - X, Y = np.meshgrid(np.arange(0, 2, 0.1), - np.arange(0, 2, 0.1)) + X, Y = np.meshgrid(np.arange(0, 2, 0.1), np.arange(0, 2, 0.1)) for k, (x, y) in enumerate(zip(X.ravel(), Y.ravel())): xdisp, ydisp = ax.transData.transform([x, y]) - event = MouseEvent('button_press_event', fig.canvas, xdisp, ydisp) + event = MouseEvent("button_press_event", fig.canvas, xdisp, ydisp) for m, patch in enumerate(patches_list): # set the points to red only if the arrow contains the point inside, res = patch.contains(event) @@ -189,33 +236,35 @@ def test_arrow_contains_point(): ax.scatter(x, y, s=5, c="r") -@image_comparison(['path_clipping.svg'], remove_text=True) +@image_comparison(["path_clipping.svg"], remove_text=True) def test_path_clipping(): fig = plt.figure(figsize=(6.0, 6.2)) - for i, xy in enumerate([ + for i, xy in enumerate( + [ [(200, 200), (200, 350), (400, 350), (400, 200)], [(200, 200), (200, 350), (400, 350), (400, 100)], [(200, 100), (200, 350), (400, 350), (400, 100)], [(200, 100), (200, 415), (400, 350), (400, 100)], [(200, 100), (200, 415), (400, 415), (400, 100)], [(200, 415), (400, 415), (400, 100), (200, 100)], - [(400, 415), (400, 100), (200, 100), (200, 415)]]): - ax = fig.add_subplot(4, 2, i+1) + [(400, 415), (400, 100), (200, 100), (200, 415)], + ] + ): + ax = fig.add_subplot(4, 2, i + 1) bbox = [0, 140, 640, 260] ax.set_xlim(bbox[0], bbox[0] + bbox[2]) ax.set_ylim(bbox[1], bbox[1] + bbox[3]) - ax.add_patch(Polygon( - xy, facecolor='none', edgecolor='red', closed=True)) + ax.add_patch(Polygon(xy, facecolor="none", edgecolor="red", closed=True)) -@image_comparison(['semi_log_with_zero.png'], style='mpl20') +@image_comparison(["semi_log_with_zero.png"], style="mpl20") def test_log_transform_with_zero(): x = np.arange(-10, 10) - y = (1.0 - 1.0/(x**2+1))**20 + y = (1.0 - 1.0 / (x**2 + 1)) ** 20 fig, ax = plt.subplots() - ax.semilogy(x, y, "-o", lw=15, markeredgecolor='k') + ax.semilogy(x, y, "-o", lw=15, markeredgecolor="k") ax.set_ylim(1e-7, 1) ax.grid(True) @@ -235,14 +284,14 @@ def test_make_compound_path_empty(): def test_make_compound_path_stops(): zero = [0, 0] - paths = 3*[Path([zero, zero], [Path.MOVETO, Path.STOP])] + paths = 3 * [Path([zero, zero], [Path.MOVETO, Path.STOP])] compound_path = Path.make_compound_path(*paths) # the choice to not preserve the terminal STOP is arbitrary, but # documented, so we test that it is in fact respected here assert np.sum(compound_path.codes == Path.STOP) == 0 -@image_comparison(['xkcd.png'], remove_text=True) +@image_comparison(["xkcd.png"], remove_text=True) def test_xkcd(): np.random.seed(0) @@ -254,7 +303,7 @@ def test_xkcd(): ax.plot(x, y) -@image_comparison(['xkcd_marker.png'], remove_text=True) +@image_comparison(["xkcd_marker.png"], remove_text=True) def test_xkcd_marker(): np.random.seed(0) @@ -265,25 +314,27 @@ def test_xkcd_marker(): with plt.xkcd(): fig, ax = plt.subplots() - ax.plot(x, y1, '+', ms=10) - ax.plot(x, y2, 'o', ms=10) - ax.plot(x, y3, '^', ms=10) + ax.plot(x, y1, "+", ms=10) + ax.plot(x, y2, "o", ms=10) + ax.plot(x, y3, "^", ms=10) -@image_comparison(['marker_paths.pdf'], remove_text=True) +@image_comparison(["marker_paths.pdf"], remove_text=True) def test_marker_paths_pdf(): N = 7 - plt.errorbar(np.arange(N), - np.ones(N) + 4, - np.ones(N)) + plt.errorbar(np.arange(N), np.ones(N) + 4, np.ones(N)) plt.xlim(-1, N) plt.ylim(-1, 7) -@image_comparison(['nan_path'], style='default', remove_text=True, - extensions=['pdf', 'svg', 'eps', 'png'], - tol=0 if platform.machine() == 'x86_64' else 0.009) +@image_comparison( + ["nan_path"], + style="default", + remove_text=True, + extensions=["pdf", "svg", "eps", "png"], + tol=0 if platform.machine() == "x86_64" else 0.009, +) def test_nan_isolated_points(): y0 = [0, np.nan, 2, np.nan, 4, 5, 6] @@ -291,34 +342,37 @@ def test_nan_isolated_points(): fig, ax = plt.subplots() - ax.plot(y0, '-o') - ax.plot(y1, '-o') + ax.plot(y0, "-o") + ax.plot(y1, "-o") def test_path_no_doubled_point_in_to_polygon(): hand = np.array( - [[1.64516129, 1.16145833], - [1.64516129, 1.59375], - [1.35080645, 1.921875], - [1.375, 2.18229167], - [1.68548387, 1.9375], - [1.60887097, 2.55208333], - [1.68548387, 2.69791667], - [1.76209677, 2.56770833], - [1.83064516, 1.97395833], - [1.89516129, 2.75], - [1.9516129, 2.84895833], - [2.01209677, 2.76041667], - [1.99193548, 1.99479167], - [2.11290323, 2.63020833], - [2.2016129, 2.734375], - [2.25403226, 2.60416667], - [2.14919355, 1.953125], - [2.30645161, 2.36979167], - [2.39112903, 2.36979167], - [2.41532258, 2.1875], - [2.1733871, 1.703125], - [2.07782258, 1.16666667]]) + [ + [1.64516129, 1.16145833], + [1.64516129, 1.59375], + [1.35080645, 1.921875], + [1.375, 2.18229167], + [1.68548387, 1.9375], + [1.60887097, 2.55208333], + [1.68548387, 2.69791667], + [1.76209677, 2.56770833], + [1.83064516, 1.97395833], + [1.89516129, 2.75], + [1.9516129, 2.84895833], + [2.01209677, 2.76041667], + [1.99193548, 1.99479167], + [2.11290323, 2.63020833], + [2.2016129, 2.734375], + [2.25403226, 2.60416667], + [2.14919355, 1.953125], + [2.30645161, 2.36979167], + [2.39112903, 2.36979167], + [2.41532258, 2.1875], + [2.1733871, 1.703125], + [2.07782258, 1.16666667], + ] + ) (r0, c0, r1, c1) = (1.0, 1.5, 2.1, 2.5) @@ -335,8 +389,7 @@ def test_path_to_polygons(): p = Path(data) assert_array_equal(p.to_polygons(width=40, height=40), []) - assert_array_equal(p.to_polygons(width=40, height=40, closed_only=False), - [data]) + assert_array_equal(p.to_polygons(width=40, height=40, closed_only=False), [data]) assert_array_equal(p.to_polygons(), []) assert_array_equal(p.to_polygons(closed_only=False), [data]) @@ -345,8 +398,7 @@ def test_path_to_polygons(): p = Path(data) assert_array_equal(p.to_polygons(width=40, height=40), [closed_data]) - assert_array_equal(p.to_polygons(width=40, height=40, closed_only=False), - [data]) + assert_array_equal(p.to_polygons(width=40, height=40, closed_only=False), [data]) assert_array_equal(p.to_polygons(), [closed_data]) assert_array_equal(p.to_polygons(closed_only=False), [data]) @@ -415,9 +467,15 @@ def test_path_shallowcopy(): assert path2.codes is path2_copy.codes -@pytest.mark.parametrize('phi', np.concatenate([ - np.array([0, 15, 30, 45, 60, 75, 90, 105, 120, 135]) + delta - for delta in [-1, 0, 1]])) +@pytest.mark.parametrize( + "phi", + np.concatenate( + [ + np.array([0, 15, 30, 45, 60, 75, 90, 105, 120, 135]) + delta + for delta in [-1, 0, 1] + ] + ), +) def test_path_intersect_path(phi): # test for the range of intersection angles eps_array = [1e-5, 1e-8, 1e-10, 1e-12] @@ -494,12 +552,12 @@ def test_path_intersect_path(phi): assert not a.intersects_path(b) and not b.intersects_path(a) # a and b are collinear but do not intersect - a = transform.transform_path(Path([(0., -5.), (1., -5.)])) - b = transform.transform_path(Path([(1., 5.), (0., 5.)])) + a = transform.transform_path(Path([(0.0, -5.0), (1.0, -5.0)])) + b = transform.transform_path(Path([(1.0, 5.0), (0.0, 5.0)])) assert not a.intersects_path(b) and not b.intersects_path(a) -@pytest.mark.parametrize('offset', range(-720, 361, 45)) +@pytest.mark.parametrize("offset", range(-720, 361, 45)) def test_full_arc(offset): low = offset high = 360 + offset @@ -513,23 +571,30 @@ def test_full_arc(offset): def test_disjoint_zero_length_segment(): this_path = Path( - np.array([ - [824.85064295, 2056.26489203], - [861.69033931, 2041.00539016], - [868.57864109, 2057.63522175], - [831.73894473, 2072.89472361], - [824.85064295, 2056.26489203]]), - np.array([1, 2, 2, 2, 79], dtype=Path.code_type)) + np.array( + [ + [824.85064295, 2056.26489203], + [861.69033931, 2041.00539016], + [868.57864109, 2057.63522175], + [831.73894473, 2072.89472361], + [824.85064295, 2056.26489203], + ] + ), + np.array([1, 2, 2, 2, 79], dtype=Path.code_type), + ) outline_path = Path( - np.array([ - [859.91051028, 2165.38461538], - [859.06772495, 2149.30331334], - [859.06772495, 2181.46591743], - [859.91051028, 2165.38461538], - [859.91051028, 2165.38461538]]), - np.array([1, 2, 2, 2, 2], - dtype=Path.code_type)) + np.array( + [ + [859.91051028, 2165.38461538], + [859.06772495, 2149.30331334], + [859.06772495, 2181.46591743], + [859.91051028, 2165.38461538], + [859.91051028, 2165.38461538], + ] + ), + np.array([1, 2, 2, 2, 2], dtype=Path.code_type), + ) assert not outline_path.intersects_path(this_path) assert not this_path.intersects_path(outline_path) @@ -537,18 +602,24 @@ def test_disjoint_zero_length_segment(): def test_intersect_zero_length_segment(): this_path = Path( - np.array([ - [0, 0], - [1, 1], - ])) + np.array( + [ + [0, 0], + [1, 1], + ] + ) + ) outline_path = Path( - np.array([ - [1, 0], - [.5, .5], - [.5, .5], - [0, 1], - ])) + np.array( + [ + [1, 0], + [0.5, 0.5], + [0.5, 0.5], + [0, 1], + ] + ) + ) assert outline_path.intersects_path(this_path) assert this_path.intersects_path(outline_path) @@ -560,16 +631,16 @@ def test_cleanup_closepoly(): # control points but also the CLOSEPOLY, since it has nowhere valid to # point. paths = [ - Path([[np.nan, np.nan], [np.nan, np.nan]], - [Path.MOVETO, Path.CLOSEPOLY]), + Path([[np.nan, np.nan], [np.nan, np.nan]], [Path.MOVETO, Path.CLOSEPOLY]), # we trigger a different path in the C++ code if we don't pass any # codes explicitly, so we must also make sure that this works Path([[np.nan, np.nan], [np.nan, np.nan]]), # we should also make sure that this cleanup works if there's some # multi-vertex curves - Path([[np.nan, np.nan], [np.nan, np.nan], [np.nan, np.nan], - [np.nan, np.nan]], - [Path.MOVETO, Path.CURVE3, Path.CURVE3, Path.CLOSEPOLY]) + Path( + [[np.nan, np.nan], [np.nan, np.nan], [np.nan, np.nan], [np.nan, np.nan]], + [Path.MOVETO, Path.CURVE3, Path.CURVE3, Path.CLOSEPOLY], + ), ] for p in paths: cleaned = p.cleaned(remove_nans=True) @@ -579,12 +650,7 @@ def test_cleanup_closepoly(): def test_interpolated_moveto(): # Initial path has two subpaths with two LINETOs each - vertices = np.array([[0, 0], - [0, 1], - [1, 2], - [4, 4], - [4, 5], - [5, 5]]) + vertices = np.array([[0, 0], [0, 1], [1, 2], [4, 4], [4, 5], [5, 5]]) codes = [Path.MOVETO, Path.LINETO, Path.LINETO] * 2 path = Path(vertices, codes) @@ -596,20 +662,16 @@ def test_interpolated_moveto(): def test_interpolated_closepoly(): - codes = [Path.MOVETO] + [Path.LINETO]*2 + [Path.CLOSEPOLY] + codes = [Path.MOVETO] + [Path.LINETO] * 2 + [Path.CLOSEPOLY] vertices = [(4, 3), (5, 4), (5, 3), (0, 0)] path = Path(vertices, codes) result = path.interpolated(2) - expected_vertices = np.array([[4, 3], - [4.5, 3.5], - [5, 4], - [5, 3.5], - [5, 3], - [4.5, 3], - [4, 3]]) - expected_codes = [Path.MOVETO] + [Path.LINETO]*5 + [Path.CLOSEPOLY] + expected_vertices = np.array( + [[4, 3], [4.5, 3.5], [5, 4], [5, 3.5], [5, 3], [4.5, 3], [4, 3]] + ) + expected_codes = [Path.MOVETO] + [Path.LINETO] * 5 + [Path.CLOSEPOLY] np.testing.assert_allclose(result.vertices, expected_vertices) np.testing.assert_array_equal(result.codes, expected_codes) @@ -621,8 +683,7 @@ def test_interpolated_closepoly(): path = Path(vertices, codes) result = path.interpolated(2) - extra_expected_vertices = np.array([[3, 2], - [2, 1]]) + extra_expected_vertices = np.array([[3, 2], [2, 1]]) expected_vertices = np.concatenate([expected_vertices, extra_expected_vertices]) expected_codes += [Path.LINETO] * 2 @@ -633,21 +694,17 @@ def test_interpolated_closepoly(): def test_interpolated_moveto_closepoly(): # Initial path has two closed subpaths - codes = ([Path.MOVETO] + [Path.LINETO]*2 + [Path.CLOSEPOLY]) * 2 + codes = ([Path.MOVETO] + [Path.LINETO] * 2 + [Path.CLOSEPOLY]) * 2 vertices = [(4, 3), (5, 4), (5, 3), (0, 0), (8, 6), (10, 8), (10, 6), (0, 0)] path = Path(vertices, codes) result = path.interpolated(2) - expected_vertices1 = np.array([[4, 3], - [4.5, 3.5], - [5, 4], - [5, 3.5], - [5, 3], - [4.5, 3], - [4, 3]]) + expected_vertices1 = np.array( + [[4, 3], [4.5, 3.5], [5, 4], [5, 3.5], [5, 3], [4.5, 3], [4, 3]] + ) expected_vertices = np.concatenate([expected_vertices1, expected_vertices1 * 2]) - expected_codes = ([Path.MOVETO] + [Path.LINETO]*5 + [Path.CLOSEPOLY]) * 2 + expected_codes = ([Path.MOVETO] + [Path.LINETO] * 5 + [Path.CLOSEPOLY]) * 2 np.testing.assert_allclose(result.vertices, expected_vertices) np.testing.assert_array_equal(result.codes, expected_codes)