diff --git a/doc/changelog.qmd b/doc/changelog.qmd index 121b2fa56..46f687e24 100644 --- a/doc/changelog.qmd +++ b/doc/changelog.qmd @@ -112,6 +112,10 @@ title: Changelog ### Bug Fixes +- In a non-linear coordinate system (e.g. [](:class:`~plotnine.coord_trans`)), + the closing edge of a polygon is now curved along with the rest of its + boundary instead of being drawn as a straight chord. + - The space between facet panels now accounts for the margins of the axis text, so with free scales large margins no longer push the tick labels into the neighbouring panel. diff --git a/plotnine/geoms/geom_polygon.py b/plotnine/geoms/geom_polygon.py index add11541e..aaacbdae8 100644 --- a/plotnine/geoms/geom_polygon.py +++ b/plotnine/geoms/geom_polygon.py @@ -73,6 +73,19 @@ def draw_group( ): from matplotlib.collections import PolyCollection + # A polygon is a closed ring, but the vertices only trace it open. + # In a non-linear coord the closing edge must be munched like any + # other, or it stays a straight chord across a curved boundary (e.g. + # the inner arc of a polar bar). Repeat each group's first vertex so + # munch subdivides that edge too; a linear coord closes it straight, + # which is already correct, so leave it untouched there. + if not coord.is_linear: + indices = data.groupby("group", sort=False).indices + order = np.concatenate( + [np.append(idx, idx[0]) for idx in indices.values()] + ) + data = data.iloc[order].reset_index(drop=True) + data = coord.transform(data, panel_params, munch=True) data["linewidth"] = data["size"] * SIZE_FACTOR diff --git a/tests/baseline_images/test_coords/coord_trans_munches_polygon_closing_edge.png b/tests/baseline_images/test_coords/coord_trans_munches_polygon_closing_edge.png new file mode 100644 index 000000000..454cd1dd0 Binary files /dev/null and b/tests/baseline_images/test_coords/coord_trans_munches_polygon_closing_edge.png differ diff --git a/tests/test_coords.py b/tests/test_coords.py index a77d82b10..0525e9d88 100644 --- a/tests/test_coords.py +++ b/tests/test_coords.py @@ -14,6 +14,7 @@ geom_bar, geom_line, geom_point, + geom_polygon, ggplot, xlim, ) @@ -74,6 +75,21 @@ def test_coord_trans_backtransforms(): assert p == "coord_trans_backtransform" +def test_coord_trans_munches_polygon_closing_edge(): + # A polygon is a closed ring, but its vertices only trace it open; the + # edge from the last vertex back to the first must be munched like any + # other. The triangle's two explicit edges are axis-aligned (straight + # under log), so only the closing edge curves — if it is left as a + # straight chord this baseline shows a triangle instead of the arc. + tri = pd.DataFrame({"x": [1.0, 1.0, 100.0], "y": [100.0, 1.0, 1.0]}) + p = ( + ggplot(tri, aes("x", "y")) + + geom_polygon(fill="none", color="black", size=1) + + coord_trans(x="log10", y="log10") + ) + assert p == "coord_trans_munches_polygon_closing_edge" + + def test_datetime_coord_limits(): n = 6