Skip to content

Commit 6bbc73b

Browse files
authored
Fix GeoAxes._toggle_ticks to support bool and sequence label specs (#579)
Issue #578 reported that _toggle_ticks only handled string inputs and emitted a confusing warning for valid shorthand like labels='lb'. This diverged from the documented label input contract for lonlabels/latlabels/labels, which includes booleans and sequences. The fix makes _toggle_ticks parse inputs through _to_label_array, so bool, string, and sequence forms are all accepted consistently with format() docs. Tick-side selection now uses axis-relevant sides only (bottom/top for x, left/right for y), which prevents false warnings for mixed shorthand specs and keeps behavior deterministic. Added regression tests in test_geographic.py for labels='lb' (no warning, bottom+left tick placement) and direct _toggle_ticks calls with bool/sequence inputs. These tests fail on previous behavior and pass with this patch.
1 parent ed9d737 commit 6bbc73b

2 files changed

Lines changed: 64 additions & 33 deletions

File tree

ultraplot/axes/geo.py

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,43 +1100,42 @@ def _sharex_setup(
11001100
super()._sharex_setup(sharex, labels=labels, limits=limits)
11011101
return self.__share_axis_setup(sharex, which="x", labels=labels, limits=limits)
11021102

1103-
def _toggle_ticks(self, label: str | None, which: str) -> None:
1103+
def _toggle_ticks(self, label: Any, which: str) -> None:
11041104
"""
1105-
Ticks are controlled by matplotlib independent of the backend. We can toggle ticks on and of depending on the desired position.
1105+
Toggle x/y tick positions from geo label specifications.
1106+
1107+
Accepts the same `labels` forms as format(), including booleans, strings,
1108+
and boolean/string sequences. Only sides relevant to the requested axis
1109+
are considered: bottom/top for ``which='x'`` and left/right for
1110+
``which='y'``.
11061111
"""
1107-
if not isinstance(label, str):
1112+
if label is None:
11081113
return
11091114

1110-
# Only allow "lrbt" and "all" or "both"
1111-
label = label.replace("top", "t")
1112-
label = label.replace("bottom", "b")
1113-
label = label.replace("left", "l")
1114-
label = label.replace("right", "r")
1115-
match label:
1116-
case _ if len(label) == 2 and "t" in label and "b" in label:
1117-
self.xaxis.set_ticks_position("both")
1118-
case _ if len(label) == 2 and "l" in label and "r" in label:
1119-
self.yaxis.set_ticks_position("both")
1120-
case "t":
1121-
self.xaxis.set_ticks_position("top")
1122-
case "b":
1123-
self.xaxis.set_ticks_position("bottom")
1124-
case "l":
1125-
self.yaxis.set_ticks_position("left")
1126-
case "r":
1127-
self.yaxis.set_ticks_position("right")
1128-
case "all":
1129-
self.xaxis.set_ticks_position("both")
1130-
self.yaxis.set_ticks_position("both")
1131-
case "both":
1132-
if which == "x":
1133-
self.xaxis.set_ticks_position("both")
1134-
else:
1135-
self.yaxis.set_ticks_position("both")
1136-
case _:
1137-
warnings._warn_ultraplot(
1138-
f"Not toggling {label=}. Input was not understood. Valid values are ['left', 'right', 'top', 'bottom', 'all', 'both']"
1139-
)
1115+
is_lon = which == "x"
1116+
try:
1117+
array = self._to_label_array(label, lon=is_lon)
1118+
except ValueError:
1119+
warnings._warn_ultraplot(
1120+
f"Not toggling label={label!r}. Input was not understood."
1121+
)
1122+
return
1123+
1124+
if is_lon:
1125+
side0, side1 = bool(array[2]), bool(array[3]) # bottom, top
1126+
axis = self.xaxis
1127+
name0, name1 = "bottom", "top"
1128+
else:
1129+
side0, side1 = bool(array[0]), bool(array[1]) # left, right
1130+
axis = self.yaxis
1131+
name0, name1 = "left", "right"
1132+
1133+
if side0 and side1:
1134+
axis.set_ticks_position("both")
1135+
elif side0:
1136+
axis.set_ticks_position(name0)
1137+
elif side1:
1138+
axis.set_ticks_position(name1)
11401139

11411140
def _set_gridliner_adapter(
11421141
self, which: str, adapter: Optional[_GridlinerAdapter]

ultraplot/tests/test_geographic.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,38 @@ def test_geoticks_input_handling(recwarn):
179179
ax.format(lonticklen="1em")
180180

181181

182+
def test_geoticks_label_shorthand_lb_no_warning(recwarn):
183+
fig, ax = uplt.subplots(proj="cyl")
184+
ax.format(land=True, lonlines=30, latlines=30, labels="lb")
185+
assert len(recwarn) == 0
186+
assert ax[0].xaxis.get_ticks_position() == "bottom"
187+
assert ax[0].yaxis.get_ticks_position() == "left"
188+
uplt.close(fig)
189+
190+
191+
def test_toggle_ticks_supports_bool_and_sequence_specs():
192+
fig, ax = uplt.subplots(proj="cyl")
193+
geo = ax[0]
194+
with warnings.catch_warnings(record=True) as caught:
195+
warnings.simplefilter("always", uplt.warnings.UltraPlotWarning)
196+
geo._toggle_ticks(True, "x")
197+
assert geo.xaxis.get_ticks_position() == "bottom"
198+
geo._toggle_ticks((True, True), "x")
199+
assert geo.xaxis.get_ticks_position() in ("both", "default")
200+
geo._toggle_ticks(("left", "bottom"), "x")
201+
assert geo.xaxis.get_ticks_position() == "bottom"
202+
203+
geo._toggle_ticks(True, "y")
204+
assert geo.yaxis.get_ticks_position() == "left"
205+
geo._toggle_ticks((True, True), "y")
206+
assert geo.yaxis.get_ticks_position() in ("both", "default")
207+
geo._toggle_ticks(("left", "bottom"), "y")
208+
assert geo.yaxis.get_ticks_position() == "left"
209+
210+
assert not caught
211+
uplt.close(fig)
212+
213+
182214
@pytest.mark.parametrize(
183215
("layout", "lonlabels", "latlabels"),
184216
[

0 commit comments

Comments
 (0)