Skip to content

Commit d4f0ebb

Browse files
committed
MNT: Better workaround for format_cursor_data on ScalarMappables
By introducing an explicit override function, we can move the formatting code to ScalarMappable, where it logically belongs. Also, artist.py does no longer depend on colors.py and cm.py, which simplifies module dependencies.
1 parent 315da10 commit d4f0ebb

File tree

2 files changed

+37
-33
lines changed

2 files changed

+37
-33
lines changed

lib/matplotlib/artist.py

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313

1414
import matplotlib as mpl
1515
from . import _api, cbook
16-
from .colors import BoundaryNorm
17-
from .cm import ScalarMappable
1816
from .path import Path
1917
from .transforms import (BboxBase, Bbox, IdentityTransform, Transform, TransformedBbox,
2018
TransformedPatchPath, TransformedPath)
@@ -1346,37 +1344,11 @@ def format_cursor_data(self, data):
13461344
--------
13471345
get_cursor_data
13481346
"""
1349-
if np.ndim(data) == 0 and isinstance(self, ScalarMappable):
1350-
# This block logically belongs to ScalarMappable, but can't be
1351-
# implemented in it because most ScalarMappable subclasses inherit
1352-
# from Artist first and from ScalarMappable second, so
1353-
# Artist.format_cursor_data would always have precedence over
1354-
# ScalarMappable.format_cursor_data.
1355-
n = self.cmap.N
1356-
if np.ma.getmask(data):
1357-
return "[]"
1358-
normed = self.norm(data)
1359-
if np.isfinite(normed):
1360-
if isinstance(self.norm, BoundaryNorm):
1361-
# not an invertible normalization mapping
1362-
cur_idx = np.argmin(np.abs(self.norm.boundaries - data))
1363-
neigh_idx = max(0, cur_idx - 1)
1364-
# use max diff to prevent delta == 0
1365-
delta = np.diff(
1366-
self.norm.boundaries[neigh_idx:cur_idx + 2]
1367-
).max()
1368-
elif self.norm.vmin == self.norm.vmax:
1369-
# singular norms, use delta of 10% of only value
1370-
delta = np.abs(self.norm.vmin * .1)
1371-
else:
1372-
# Midpoints of neighboring color intervals.
1373-
neighbors = self.norm.inverse(
1374-
(int(normed * n) + np.array([0, 1])) / n)
1375-
delta = abs(neighbors - data).max()
1376-
g_sig_digits = cbook._g_sig_digits(data, delta)
1377-
else:
1378-
g_sig_digits = 3 # Consistent with default below.
1379-
return f"[{data:-#.{g_sig_digits}g}]"
1347+
if np.ndim(data) == 0 and hasattr(self, "_format_cursor_data_override"):
1348+
# workaround for ScalarMappable to be able to define its own
1349+
# format_cursor_data(). See ScalarMappable._format_cursor_data_override
1350+
# for details.
1351+
return self._format_cursor_data_override(data)
13801352
else:
13811353
try:
13821354
data[0]

lib/matplotlib/cm.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,38 @@ def changed(self):
611611
self.callbacks.process('changed', self)
612612
self.stale = True
613613

614+
def _format_cursor_data_override(self, data):
615+
# This function overwrites Artist.format_cursor_data(). We cannot
616+
# implement ScalarMappable.format_cursor_data() directly, because
617+
# most ScalarMappable subclasses inherit from Artist first and from
618+
# ScalarMappable second, so Artist.format_cursor_data would always
619+
# have precedence over ScalarMappable.format_cursor_data.
620+
n = self.cmap.N
621+
if np.ma.getmask(data):
622+
return "[]"
623+
normed = self.norm(data)
624+
if np.isfinite(normed):
625+
if isinstance(self.norm, colors.BoundaryNorm):
626+
# not an invertible normalization mapping
627+
cur_idx = np.argmin(np.abs(self.norm.boundaries - data))
628+
neigh_idx = max(0, cur_idx - 1)
629+
# use max diff to prevent delta == 0
630+
delta = np.diff(
631+
self.norm.boundaries[neigh_idx:cur_idx + 2]
632+
).max()
633+
elif self.norm.vmin == self.norm.vmax:
634+
# singular norms, use delta of 10% of only value
635+
delta = np.abs(self.norm.vmin * .1)
636+
else:
637+
# Midpoints of neighboring color intervals.
638+
neighbors = self.norm.inverse(
639+
(int(normed * n) + np.array([0, 1])) / n)
640+
delta = abs(neighbors - data).max()
641+
g_sig_digits = cbook._g_sig_digits(data, delta)
642+
else:
643+
g_sig_digits = 3 # Consistent with default below.
644+
return f"[{data:-#.{g_sig_digits}g}]"
645+
614646

615647
# The docstrings here must be generic enough to apply to all relevant methods.
616648
mpl._docstring.interpd.update(

0 commit comments

Comments
 (0)