Skip to content

Commit c8bcb9e

Browse files
GeoTicks not responsive (#253)
* fix * more tick fixing * spelling * restore toggling * update test * update tests * add tick checker to base * more fixes * reset rc * minor tweaks * attempt doctest fix * revert array setting * add comment * Update ultraplot/tests/test_geographic.py Co-authored-by: Matthew R. Becker <beckermr@users.noreply.github.com> * rm debug * add reasoning for skip * restore location format * mv sharing internal --------- Co-authored-by: Matthew R. Becker <beckermr@users.noreply.github.com>
1 parent 91c4bb6 commit c8bcb9e

File tree

4 files changed

+279
-135
lines changed

4 files changed

+279
-135
lines changed

ultraplot/axes/base.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,6 +3199,24 @@ def _is_panel_group_member(self, other: "Axes") -> bool:
31993199
# Not in the same panel group
32003200
return False
32013201

3202+
def _is_ticklabel_on(self, side: str) -> bool:
3203+
"""
3204+
Check if tick labels are on for the specified sides.
3205+
"""
3206+
# NOTE: This is a helper function to check if tick labels are on
3207+
# for the specified sides. It returns True if any of the specified
3208+
# sides have tick labels turned on.
3209+
axis = self.xaxis
3210+
if side in ["labelleft", "labelright"]:
3211+
axis = self.yaxis
3212+
label = "label1"
3213+
if side in ["labelright", "labeltop"]:
3214+
label = "label2"
3215+
for tick in axis.get_major_ticks():
3216+
if getattr(tick, label).get_visible():
3217+
return True
3218+
return False
3219+
32023220
@docstring._snippet_manager
32033221
def inset(self, *args, **kwargs):
32043222
"""

ultraplot/axes/geo.py

Lines changed: 111 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -585,9 +585,6 @@ def __share_axis_setup(
585585
if level > 1 and limits:
586586
self._share_limits_with(other, which=which)
587587

588-
if level >= 1 and labels:
589-
self._share_labels_with_others()
590-
591588
@override
592589
def _sharey_setup(self, sharey, *, labels=True, limits=True):
593590
"""
@@ -676,9 +673,6 @@ def _apply_axis_sharing(self):
676673
return
677674
if self.figure._get_sharing_level() == 0:
678675
return
679-
# Share labels with all levels higher or equal
680-
# to 1.
681-
self._share_labels_with_others()
682676

683677
def _get_gridliner_labels(
684678
self,
@@ -687,33 +681,30 @@ def _get_gridliner_labels(
687681
left=None,
688682
right=None,
689683
):
690-
assert NotImplementedError("Should be implemented by Cartopy or Basemap Axes")
684+
raise NotImplementedError("Should be implemented by Cartopy or Basemap Axes")
691685

692686
def _toggle_gridliner_labels(
693687
self,
694-
top=None,
695-
bottom=None,
696-
left=None,
697-
right=None,
688+
labeltop=None,
689+
labelbottom=None,
690+
labelleft=None,
691+
labelright=None,
698692
geo=None,
699693
):
700694
# For BasemapAxes the gridlines are dicts with key as the coordinate and keys the line and label
701695
# We override the dict here assuming the labels are mut excl due to the N S E W extra chars
702-
if self.gridlines_major is None:
703-
return
704696
if any(i is None for i in self.gridlines_major):
705697
return
706698
gridlabels = self._get_gridliner_labels(
707-
bottom=bottom, top=top, left=left, right=right
699+
bottom=labelbottom, top=labeltop, left=labelleft, right=labelright
708700
)
709-
for direction, toggle in zip(
710-
"bottom top left right".split(),
711-
[bottom, top, left, right],
712-
):
713-
if toggle is not None:
714-
for label in gridlabels.get(direction, []):
715-
label.set_visible(toggle)
716-
self.stale = True
701+
bools = [labelbottom, labeltop, labelleft, labelright]
702+
directions = "bottom top left right".split()
703+
for direction, toggle in zip(directions, bools):
704+
if toggle is None:
705+
continue
706+
for label in gridlabels.get(direction, []):
707+
label.set_visible(toggle)
717708

718709
def _handle_axis_sharing(
719710
self,
@@ -733,48 +724,6 @@ def _handle_axis_sharing(
733724
target_axis.set_view_interval(*source_axis.get_view_interval())
734725
target_axis.set_minor_locator(source_axis.get_minor_locator())
735726

736-
def _share_labels_with_others(self):
737-
"""
738-
Helpers function to ensure the labels
739-
are shared for rectilinear GeoAxes.
740-
"""
741-
# Turn all labels off
742-
# Note: this action performs it for all the axes in
743-
# the figure. We use the stale here to only perform
744-
# it once as it is an expensive action.
745-
border_axes = self.figure._get_border_axes()
746-
# Recode:
747-
recoded = {}
748-
for direction, axes in border_axes.items():
749-
for axi in axes:
750-
recoded[axi] = recoded.get(axi, []) + [direction]
751-
752-
# We turn off the tick labels when the scale and
753-
# ticks are shared (level >= 3)
754-
are_ticks_on = False
755-
default = dict(
756-
left=are_ticks_on,
757-
right=are_ticks_on,
758-
top=are_ticks_on,
759-
bottom=are_ticks_on,
760-
)
761-
for axi in self.figure.axes:
762-
# If users call colorbar on the figure
763-
# an axis is added which needs to skip the
764-
# sharing that is specific for the GeoAxes.
765-
if not isinstance(axi, GeoAxes):
766-
continue
767-
gridlabels = self._get_gridliner_labels(
768-
bottom=True, top=True, left=True, right=True
769-
)
770-
sides = recoded.get(axi, [])
771-
tmp = default.copy()
772-
for side in sides:
773-
if side in gridlabels and gridlabels[side]:
774-
tmp[side] = True
775-
axi._toggle_gridliner_labels(**tmp)
776-
self.stale = False
777-
778727
@override
779728
def draw(self, renderer=None, *args, **kwargs):
780729
# Perform extra post-processing steps
@@ -1465,29 +1414,46 @@ def _get_side_labels() -> tuple:
14651414
top_labels = "xlabels_top"
14661415
return (left_labels, right_labels, bottom_labels, top_labels)
14671416

1417+
@override
1418+
def _is_ticklabel_on(self, side: str) -> bool:
1419+
"""
1420+
Helper function to check if tick labels are on for a given side.
1421+
"""
1422+
# Deal with different cartopy versions
1423+
left_labels, right_labels, bottom_labels, top_labels = self._get_side_labels()
1424+
if self.gridlines_major is None:
1425+
return False
1426+
elif side == "labelleft":
1427+
return getattr(self.gridlines_major, left_labels)
1428+
elif side == "labelright":
1429+
return getattr(self.gridlines_major, right_labels)
1430+
elif side == "labelbottom":
1431+
return getattr(self.gridlines_major, bottom_labels)
1432+
elif side == "labeltop":
1433+
return getattr(self.gridlines_major, top_labels)
1434+
else:
1435+
raise ValueError(f"Invalid side: {side}")
1436+
1437+
@override
14681438
def _toggle_gridliner_labels(
14691439
self,
1470-
left=None,
1471-
right=None,
1472-
bottom=None,
1473-
top=None,
1440+
labelleft=None,
1441+
labelright=None,
1442+
labelbottom=None,
1443+
labeltop=None,
14741444
geo=None,
14751445
):
14761446
"""
14771447
Toggle gridliner labels across different cartopy versions.
14781448
"""
1479-
left_labels, right_labels, bottom_labels, top_labels = (
1480-
_CartopyAxes._get_side_labels()
1481-
)
1449+
# Retrieve the property name depending
1450+
# on cartopy version.
1451+
side_labels = _CartopyAxes._get_side_labels()
1452+
togglers = (labelleft, labelright, labelbottom, labeltop)
14821453
gl = self.gridlines_major
1483-
if left is not None:
1484-
setattr(gl, left_labels, left)
1485-
if right is not None:
1486-
setattr(gl, right_labels, right)
1487-
if bottom is not None:
1488-
setattr(gl, bottom_labels, bottom)
1489-
if top is not None:
1490-
setattr(gl, top_labels, top)
1454+
for toggle, side in zip(togglers, side_labels):
1455+
if getattr(gl, side) != toggle:
1456+
setattr(gl, side, toggle)
14911457
if geo is not None: # only cartopy 0.20 supported but harmless
14921458
setattr(gl, "geo_labels", geo)
14931459

@@ -1779,7 +1745,7 @@ def _update_major_gridlines(
17791745
sides = dict()
17801746
# The ordering of these sides are important. The arrays are ordered lrbtg
17811747
for side, lon, lat in zip(
1782-
"left right bottom top geo".split(), lonarray, latarray
1748+
"labelleft labelright labelbottom labeltop geo".split(), lonarray, latarray
17831749
):
17841750
if lon and lat:
17851751
sides[side] = True
@@ -1789,7 +1755,8 @@ def _update_major_gridlines(
17891755
sides[side] = "y"
17901756
elif lon is not None or lat is not None:
17911757
sides[side] = False
1792-
self._toggle_gridliner_labels(**sides)
1758+
if sides:
1759+
self._toggle_gridliner_labels(**sides)
17931760

17941761
def _update_minor_gridlines(self, longrid=None, latgrid=None, nsteps=None):
17951762
"""
@@ -1976,6 +1943,40 @@ def _turnoff_tick_labels(self, locator: mticker.Formatter):
19761943
if isinstance(object, mtext.Text):
19771944
object.set_visible(False)
19781945

1946+
def _get_gridliner_labels(
1947+
self,
1948+
bottom=None,
1949+
top=None,
1950+
left=None,
1951+
right=None,
1952+
):
1953+
directions = "left right top bottom".split()
1954+
bools = [left, right, top, bottom]
1955+
sides = {}
1956+
for direction, is_on in zip(directions, bools):
1957+
if is_on is None:
1958+
continue
1959+
gl = self.gridlines_major[0]
1960+
if direction in ["left", "right"]:
1961+
gl = self.gridlines_major[1]
1962+
for loc, (lines, labels) in gl.items():
1963+
for label in labels:
1964+
position = label.get_position()
1965+
match direction:
1966+
case "top" if position[1] > 0:
1967+
add = True
1968+
case "bottom" if position[1] < 0:
1969+
add = True
1970+
case "left" if position[0] < 0:
1971+
add = True
1972+
case "right" if position[0] > 0:
1973+
add = True
1974+
case _:
1975+
add = False
1976+
if add:
1977+
sides.setdefault(direction, []).append(label)
1978+
return sides
1979+
19791980
def _get_lon0(self):
19801981
"""
19811982
Get the central longitude.
@@ -2196,7 +2197,7 @@ def _update_major_gridlines(
21962197
)
21972198
sides = {}
21982199
for side, lonon, laton in zip(
2199-
"left right top bottom geo".split(), lonarray, latarray
2200+
"labelleft labelright labeltop labelbottom geo".split(), lonarray, latarray
22002201
):
22012202
if lonon or laton:
22022203
sides[side] = True
@@ -2225,13 +2226,7 @@ def _update_minor_gridlines(self, longrid=None, latgrid=None, nsteps=None):
22252226
axis.isDefault_minloc = True
22262227

22272228
@override
2228-
def _get_gridliner_labels(
2229-
self,
2230-
bottom=None,
2231-
top=None,
2232-
left=None,
2233-
right=None,
2234-
):
2229+
def _is_ticklabel_on(self, side: str) -> bool:
22352230
# For basemap object, the text is organized
22362231
# as a dictionary. The keys are the numerical
22372232
# location values, and the values are a list
@@ -2245,45 +2240,47 @@ def _get_gridliner_labels(
22452240
def group_labels(
22462241
labels: list[mtext.Text],
22472242
which: str,
2248-
bottom=None,
2249-
top=None,
2250-
left=None,
2251-
right=None,
2243+
labelbottom=None,
2244+
labeltop=None,
2245+
labelleft=None,
2246+
labelright=None,
22522247
) -> dict[str, list[mtext.Text]]:
22532248
group = {}
22542249
# We take zero here as a baseline
22552250
for label in labels:
22562251
position = label.get_position()
22572252
target = None
22582253
if which == "x":
2259-
if bottom is not None and position[1] < 0:
2260-
target = "bottom"
2261-
elif top is not None and position[1] >= 0:
2262-
target = "top"
2254+
if labelbottom is not None and position[1] < 0:
2255+
target = "labelbottom"
2256+
elif labeltop is not None and position[1] >= 0:
2257+
target = "labeltop"
22632258
else:
2264-
if left is not None and position[0] < 0:
2265-
target = "left"
2266-
elif right is not None and position[0] >= 0:
2267-
target = "right"
2259+
if labelleft is not None and position[0] < 0:
2260+
target = "labelleft"
2261+
elif labelright is not None and position[0] >= 0:
2262+
target = "labelright"
22682263
if target is not None:
22692264
group[target] = group.get(target, []) + [label]
22702265
return group
22712266

2267+
gl = self.gridlines_major[0]
2268+
which = "x"
2269+
if side in ["labelleft", "labelright"]:
2270+
gl = self.gridlines_major[1]
2271+
which = "y"
22722272
# Group the text object based on their location
22732273
grouped = {}
2274-
for which, gl in zip("xy", self.gridlines_major):
2275-
for loc, (line, labels) in gl.items():
2276-
tmp = group_labels(
2277-
labels=labels,
2278-
which=which,
2279-
bottom=bottom,
2280-
top=top,
2281-
left=left,
2282-
right=right,
2283-
)
2284-
for key, values in tmp.items():
2285-
grouped[key] = grouped.get(key, []) + values
2286-
return grouped
2274+
for loc, (line, labels) in gl.items():
2275+
labels = group_labels(
2276+
labels=labels,
2277+
which=which,
2278+
**{side: True},
2279+
)
2280+
for label in labels.get(side, []):
2281+
if label.get_visible():
2282+
return True
2283+
return False
22872284

22882285

22892286
# Apply signature obfuscation after storing previous signature

0 commit comments

Comments
 (0)