diff --git a/ultraplot/figure.py b/ultraplot/figure.py index 1c0e47c8f..334c61a44 100644 --- a/ultraplot/figure.py +++ b/ultraplot/figure.py @@ -1487,10 +1487,18 @@ def _effective_share_level(self, axi, axis: str, sides: tuple[str, str]) -> int: if getattr(axi, "_panel_side", None) and getattr(axi, f"_share{axis}", None): return 3 - # Adjacent panels on any relevant side + # Adjacent panels on any relevant side. Ignore hidden filled panels + # (e.g. those created for outer legends/colorbars via ``loc='r'``); + # they do not participate in axis sharing and must not promote the + # parent axes' tick-label sharing level (see issue #694). panel_dict = getattr(axi, "_panel_dict", {}) for side in sides: - side_panels = panel_dict.get(side) or [] + side_panels = [ + p + for p in (panel_dict.get(side) or []) + if not getattr(p, "_panel_hidden", False) + and getattr(p, "_panel_share", False) + ] if side_panels and getattr(side_panels[0], f"_share{axis}", False): return 3 diff --git a/ultraplot/tests/test_subplots.py b/ultraplot/tests/test_subplots.py index ee61616c4..0f75cb125 100644 --- a/ultraplot/tests/test_subplots.py +++ b/ultraplot/tests/test_subplots.py @@ -948,3 +948,41 @@ def test_grid_geo_and_cartesian(): assert axs[2] in outer_axes["right"] assert axs[3] in outer_axes["right"] return fig + + +@pytest.mark.parametrize("share_level", ["labs", "lims"]) +def test_outer_legend_keeps_ticklabels_with_label_sharing(share_level: str) -> None: + """ + Regression test for issue #694. With ``sharey`` set to a "label" or + "limits" level (i.e. < 3), tick labels must remain on every visible + subplot even after an outer legend (``loc='r'``) is added next to one + of them. Previously the legend's hidden filled panel promoted the + parent's effective share level to 3 and hid its left tick labels. + """ + fig, axs = uplt.subplots(ncols=3, sharey=share_level) + axs[-1].set_visible(False) + for ax in axs[:-1]: + ax.plot([0, 1], [0, 1], label="line") + axs[-2].legend(loc="r") + fig.canvas.draw() + + for ax in axs[:-1]: + assert ax.yaxis.get_tick_params()["labelleft"] is True + + +def test_outer_legend_preserves_share_true_ticklabel_hiding() -> None: + """ + Counterpart to ``test_outer_legend_keeps_ticklabels_with_label_sharing``: + when ``sharey=True`` (level 3) the inner subplots' tick labels must + still be hidden even after an outer legend is attached. Guards against + over-correcting the issue #694 fix. + """ + fig, axs = uplt.subplots(ncols=3, sharey=True) + for ax in axs: + ax.plot([0, 1], [0, 1], label="line") + axs[1].legend(loc="r") + fig.canvas.draw() + + assert axs[0].yaxis.get_tick_params()["labelleft"] is True + assert axs[1].yaxis.get_tick_params()["labelleft"] is False + assert axs[2].yaxis.get_tick_params()["labelleft"] is False