From 193e5a9525e2a2314260dadc63dc3c89d03966ab Mon Sep 17 00:00:00 2001 From: Ian Thomas Date: Fri, 30 Jun 2023 11:08:19 +0100 Subject: [PATCH 1/2] Use CLOSEPOLY kind code to close tricontourf polygons --- lib/matplotlib/tests/test_triangulation.py | 66 ++++++++++++++++++++++ src/tri/_tri.cpp | 22 ++++---- 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/tests/test_triangulation.py b/lib/matplotlib/tests/test_triangulation.py index 3aca6eeea73d..a5a82e43c89f 100644 --- a/lib/matplotlib/tests/test_triangulation.py +++ b/lib/matplotlib/tests/test_triangulation.py @@ -1340,3 +1340,69 @@ def test_triplot_label(): assert labels == ['label'] assert len(handles) == 1 assert handles[0] is lines + + +def test_tricontour_path(): + x = [0, 4, 4, 0, 2] + y = [0, 0, 4, 4, 2] + triang = mtri.Triangulation(x, y) + _, ax = plt.subplots() + + # Line strip from boundary to boundary + cs = ax.tricontour(triang, [1, 0, 0, 0, 0], levels=[0.5]) + assert len(cs.collections) == 1 + paths = cs.collections[0].get_paths() + assert len(paths) == 1 + expected_vertices = [[2, 0], [1, 1], [0, 2]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2]) + assert_array_almost_equal( + paths[0].to_polygons(closed_only=False), [expected_vertices]) + + # Closed line loop inside domain + cs = ax.tricontour(triang, [0, 0, 0, 0, 1], levels=[0.5]) + assert len(cs.collections) == 1 + paths = cs.collections[0].get_paths() + assert len(paths) == 1 + expected_vertices = [[3, 1], [3, 3], [1, 3], [1, 1], [3, 1]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), [expected_vertices]) + + +def test_tricontourf_path(): + x = [0, 4, 4, 0, 2] + y = [0, 0, 4, 4, 2] + triang = mtri.Triangulation(x, y) + _, ax = plt.subplots() + + # Polygon inside domain + cs = ax.tricontourf(triang, [0, 0, 0, 0, 1], levels=[0.5, 1.5]) + assert len(cs.collections) == 1 + paths = cs.collections[0].get_paths() + assert len(paths) == 1 + expected_vertices = [[3, 1], [3, 3], [1, 3], [1, 1], [3, 1]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), [expected_vertices]) + + # Polygon following boundary and inside domain + cs = ax.tricontourf(triang, [1, 0, 0, 0, 0], levels=[0.5, 1.5]) + assert len(cs.collections) == 1 + paths = cs.collections[0].get_paths() + assert len(paths) == 1 + expected_vertices = [[2, 0], [1, 1], [0, 2], [0, 0], [2, 0]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), [expected_vertices]) + + # Polygon is outer boundary with hole + cs = ax.tricontourf(triang, [0, 0, 0, 0, 1], levels=[-0.5, 0.5]) + assert len(cs.collections) == 1 + paths = cs.collections[0].get_paths() + assert len(paths) == 1 + expected_vertices = [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0], + [1, 1], [1, 3], [3, 3], [3, 1], [1, 1]] + assert_array_almost_equal(paths[0].vertices, expected_vertices) + assert_array_equal(paths[0].codes, [1, 2, 2, 2, 79, 1, 2, 2, 2, 79]) + assert_array_almost_equal(paths[0].to_polygons(), np.split(expected_vertices, [5])) diff --git a/src/tri/_tri.cpp b/src/tri/_tri.cpp index b54eb3e07fb8..2674a3140b35 100644 --- a/src/tri/_tri.cpp +++ b/src/tri/_tri.cpp @@ -733,6 +733,9 @@ py::tuple TriContourGenerator::contour_to_segs_and_kinds(const Contour& contour) *segs_ptr++ = point->y; *codes_ptr++ = (point == line->begin() ? MOVETO : LINETO); } + + if (line->size() > 1) + *(codes_ptr-1) = CLOSEPOLY; } py::list vertices_list(1); @@ -849,11 +852,8 @@ void TriContourGenerator::find_boundary_lines_filled(Contour& contour, lower_level, upper_level, on_upper); } while (tri_edge != start_tri_edge); - // Filled contour lines must not have same first and last - // points. - if (contour_line.size() > 1 && - contour_line.front() == contour_line.back()) - contour_line.pop_back(); + // Close polygon. + contour_line.push_back(contour_line.front()); } } } @@ -872,6 +872,9 @@ void TriContourGenerator::find_boundary_lines_filled(Contour& contour, for (Boundary::size_type j = 0; j < boundary.size(); ++j) contour_line.push_back(triang.get_point_coords( triang.get_triangle_point(boundary[j]))); + + // Close polygon. + contour_line.push_back(contour_line.front()); } } } @@ -904,13 +907,8 @@ void TriContourGenerator::find_interior_lines(Contour& contour, TriEdge tri_edge = triang.get_neighbor_edge(tri, edge); follow_interior(contour_line, tri_edge, false, level, on_upper); - if (!filled) - // Non-filled contour lines must be closed. - contour_line.push_back(contour_line.front()); - else if (contour_line.size() > 1 && - contour_line.front() == contour_line.back()) - // Filled contour lines must not have same first and last points. - contour_line.pop_back(); + // Close line loop + contour_line.push_back(contour_line.front()); } } From bdd6d362274e9ef5f054a23f9d6c7f1588e0db9c Mon Sep 17 00:00:00 2001 From: Ian Thomas Date: Fri, 30 Jun 2023 19:40:25 +0100 Subject: [PATCH 2/2] Avoid using deprecated API --- lib/matplotlib/tests/test_triangulation.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/matplotlib/tests/test_triangulation.py b/lib/matplotlib/tests/test_triangulation.py index a5a82e43c89f..682a0fbe4b75 100644 --- a/lib/matplotlib/tests/test_triangulation.py +++ b/lib/matplotlib/tests/test_triangulation.py @@ -1350,8 +1350,7 @@ def test_tricontour_path(): # Line strip from boundary to boundary cs = ax.tricontour(triang, [1, 0, 0, 0, 0], levels=[0.5]) - assert len(cs.collections) == 1 - paths = cs.collections[0].get_paths() + paths = cs.get_paths() assert len(paths) == 1 expected_vertices = [[2, 0], [1, 1], [0, 2]] assert_array_almost_equal(paths[0].vertices, expected_vertices) @@ -1361,8 +1360,7 @@ def test_tricontour_path(): # Closed line loop inside domain cs = ax.tricontour(triang, [0, 0, 0, 0, 1], levels=[0.5]) - assert len(cs.collections) == 1 - paths = cs.collections[0].get_paths() + paths = cs.get_paths() assert len(paths) == 1 expected_vertices = [[3, 1], [3, 3], [1, 3], [1, 1], [3, 1]] assert_array_almost_equal(paths[0].vertices, expected_vertices) @@ -1378,8 +1376,7 @@ def test_tricontourf_path(): # Polygon inside domain cs = ax.tricontourf(triang, [0, 0, 0, 0, 1], levels=[0.5, 1.5]) - assert len(cs.collections) == 1 - paths = cs.collections[0].get_paths() + paths = cs.get_paths() assert len(paths) == 1 expected_vertices = [[3, 1], [3, 3], [1, 3], [1, 1], [3, 1]] assert_array_almost_equal(paths[0].vertices, expected_vertices) @@ -1388,8 +1385,7 @@ def test_tricontourf_path(): # Polygon following boundary and inside domain cs = ax.tricontourf(triang, [1, 0, 0, 0, 0], levels=[0.5, 1.5]) - assert len(cs.collections) == 1 - paths = cs.collections[0].get_paths() + paths = cs.get_paths() assert len(paths) == 1 expected_vertices = [[2, 0], [1, 1], [0, 2], [0, 0], [2, 0]] assert_array_almost_equal(paths[0].vertices, expected_vertices) @@ -1398,8 +1394,7 @@ def test_tricontourf_path(): # Polygon is outer boundary with hole cs = ax.tricontourf(triang, [0, 0, 0, 0, 1], levels=[-0.5, 0.5]) - assert len(cs.collections) == 1 - paths = cs.collections[0].get_paths() + paths = cs.get_paths() assert len(paths) == 1 expected_vertices = [[0, 0], [4, 0], [4, 4], [0, 4], [0, 0], [1, 1], [1, 3], [3, 3], [3, 1], [1, 1]]