Repository: Ultraplot/UltraPlot

Issue:
Adding a legend to right of plot can remove y-axis tick labels
Got a bit of a weird edge case here for you.

If I run the following code to make a subplots instance with three axes and shared y-axis labels, then hide the last one, everything looks good.

```
fig,axs=uplt.subplots(ncols=3, sharey='labs')
axs[-1].set_visible(False)
for ax in axs[:-1]:
    ax.plot([0, 1], [0, 1], label='line')
```

<img width="8240" height="2830" alt="Image" src="https://github.com/user-attachments/assets/ee0e2c0c-5a77-4e2a-98cf-bcb8bce3d272" />

However, if I then add a legend to the second axis, the y-axis ticks for that second axis become hidden:
`axs[-2].legend(loc='r')`

<img width="8590" height="2830" alt="Image" src="https://github.com/user-attachments/assets/6a318a83-79de-4eab-a7c2-fa43053484ae" />

This doesn't happen if I place the legend inside the axis:
```
fig,axs=uplt.subplots(ncols=3, sharey='labs')
axs[-1].set_visible(False)
for ax in axs[:-1]:
    ax.plot([0, 1], [0, 1], label='line')
axs[-2].legend(loc='lr')
```
<img width="8240" height="2830" alt="Image" src="https://github.com/user-attachments/assets/82a07d48-3979-4d78-a556-4b770f1bafad" />

Kind of a niche edge case, although it becomes relevant when I have say 15 plots to show in a figure, and want to make a 4x4 grid and hide the last one.

Discussion hints:

Solution patch:
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
 


Test patch:
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