Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e63f6cf

Browse files
authored
Merge pull request #21037 from meeseeksmachine/auto-backport-of-pr-20949-on-v3.5.x
Backport PR #20949 on branch v3.5.x (Improve formatting of imshow() cursor data independently of colorbar.)
2 parents b710367 + 5c60728 commit e63f6cf

File tree

5 files changed

+36
-39
lines changed

5 files changed

+36
-39
lines changed

lib/matplotlib/artist.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import matplotlib as mpl
1414
from . import _api, cbook
15+
from .cm import ScalarMappable
1516
from .path import Path
1617
from .transforms import (Bbox, IdentityTransform, Transform, TransformedBbox,
1718
TransformedPatchPath, TransformedPath)
@@ -1261,17 +1262,18 @@ def format_cursor_data(self, data):
12611262
--------
12621263
get_cursor_data
12631264
"""
1264-
if np.ndim(data) == 0 and getattr(self, "colorbar", None):
1265+
if np.ndim(data) == 0 and isinstance(self, ScalarMappable):
12651266
# This block logically belongs to ScalarMappable, but can't be
12661267
# implemented in it because most ScalarMappable subclasses inherit
12671268
# from Artist first and from ScalarMappable second, so
12681269
# Artist.format_cursor_data would always have precedence over
12691270
# ScalarMappable.format_cursor_data.
1270-
return (
1271-
"["
1272-
+ cbook.strip_math(
1273-
self.colorbar.formatter.format_data_short(data)).strip()
1274-
+ "]")
1271+
n = self.cmap.N
1272+
# Midpoints of neighboring color intervals.
1273+
neighbors = self.norm.inverse(
1274+
(int(self.norm(data) * n) + np.array([0, 1])) / n)
1275+
delta = abs(neighbors - data).max()
1276+
return "[{:-#.{}g}]".format(data, cbook._g_sig_digits(data, delta))
12751277
else:
12761278
try:
12771279
data[0]

lib/matplotlib/cbook/__init__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import functools
1313
import gzip
1414
import itertools
15+
import math
1516
import operator
1617
import os
1718
from pathlib import Path
@@ -2206,6 +2207,23 @@ def _format_approx(number, precision):
22062207
return f'{number:.{precision}f}'.rstrip('0').rstrip('.') or '0'
22072208

22082209

2210+
def _g_sig_digits(value, delta):
2211+
"""
2212+
Return the number of significant digits to %g-format *value*, assuming that
2213+
it is known with an error of *delta*.
2214+
"""
2215+
# If e.g. value = 45.67 and delta = 0.02, then we want to round to 2 digits
2216+
# after the decimal point (floor(log10(0.02)) = -2); 45.67 contributes 2
2217+
# digits before the decimal point (floor(log10(45.67)) + 1 = 2): the total
2218+
# is 4 significant digits. A value of 0 contributes 1 "digit" before the
2219+
# decimal point.
2220+
# For inf or nan, the precision doesn't matter.
2221+
return max(
2222+
0,
2223+
(math.floor(math.log10(abs(value))) + 1 if value else 1)
2224+
- math.floor(math.log10(delta))) if math.isfinite(value) else 0
2225+
2226+
22092227
def _unikey_or_keysym_to_mplkey(unikey, keysym):
22102228
"""
22112229
Convert a Unicode key or X keysym to a Matplotlib key name.

lib/matplotlib/projections/polar.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,16 +1399,10 @@ def format_coord(self, theta, r):
13991399
# (as for linear axes), but for theta, use f-formatting as scientific
14001400
# notation doesn't make sense and the trailing dot is ugly.
14011401
def format_sig(value, delta, opt, fmt):
1402-
digits_post_decimal = math.floor(math.log10(delta))
1403-
digits_offset = (
1404-
# For "f", only count digits after decimal point.
1405-
0 if fmt == "f"
1406-
# For "g", offset by digits before the decimal point.
1407-
else math.floor(math.log10(abs(value))) + 1 if value
1408-
# For "g", 0 contributes 1 "digit" before the decimal point.
1409-
else 1)
1410-
fmt_prec = max(0, digits_offset - digits_post_decimal)
1411-
return f"{value:-{opt}.{fmt_prec}{fmt}}"
1402+
# For "f", only count digits after decimal point.
1403+
prec = (max(0, -math.floor(math.log10(delta))) if fmt == "f" else
1404+
cbook._g_sig_digits(value, delta))
1405+
return f"{value:-{opt}.{prec}{fmt}}"
14121406

14131407
return ('\N{GREEK SMALL LETTER THETA}={}\N{GREEK SMALL LETTER PI} '
14141408
'({}\N{DEGREE SIGN}), r={}').format(

lib/matplotlib/tests/test_image.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,11 @@ def test_cursor_data():
337337

338338

339339
@pytest.mark.parametrize(
340-
"data, text_without_colorbar, text_with_colorbar", [
341-
([[10001, 10000]], "[1e+04]", "[10001]"),
342-
([[.123, .987]], "[0.123]", "[0.123]"),
340+
"data, text", [
341+
([[10001, 10000]], "[10001.000]"),
342+
([[.123, .987]], "[0.123]"),
343343
])
344-
def test_format_cursor_data(data, text_without_colorbar, text_with_colorbar):
344+
def test_format_cursor_data(data, text):
345345
from matplotlib.backend_bases import MouseEvent
346346

347347
fig, ax = plt.subplots()
@@ -350,15 +350,7 @@ def test_format_cursor_data(data, text_without_colorbar, text_with_colorbar):
350350
xdisp, ydisp = ax.transData.transform([0, 0])
351351
event = MouseEvent('motion_notify_event', fig.canvas, xdisp, ydisp)
352352
assert im.get_cursor_data(event) == data[0][0]
353-
assert im.format_cursor_data(im.get_cursor_data(event)) \
354-
== text_without_colorbar
355-
356-
fig.colorbar(im)
357-
fig.canvas.draw() # This is necessary to set up the colorbar formatter.
358-
359-
assert im.get_cursor_data(event) == data[0][0]
360-
assert im.format_cursor_data(im.get_cursor_data(event)) \
361-
== text_with_colorbar
353+
assert im.format_cursor_data(im.get_cursor_data(event)) == text
362354

363355

364356
@image_comparison(['image_clip'], style='mpl20')

lib/matplotlib/ticker.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -655,16 +655,7 @@ def format_data_short(self, value):
655655
# Rough approximation: no more than 1e4 divisions.
656656
a, b = self.axis.get_view_interval()
657657
delta = (b - a) / 1e4
658-
# If e.g. value = 45.67 and delta = 0.02, then we want to round to
659-
# 2 digits after the decimal point (floor(log10(0.02)) = -2);
660-
# 45.67 contributes 2 digits before the decimal point
661-
# (floor(log10(45.67)) + 1 = 2): the total is 4 significant digits.
662-
# A value of 0 contributes 1 "digit" before the decimal point.
663-
sig_digits = max(
664-
0,
665-
(math.floor(math.log10(abs(value))) + 1 if value else 1)
666-
- math.floor(math.log10(delta)))
667-
fmt = f"%-#.{sig_digits}g"
658+
fmt = "%-#.{}g".format(cbook._g_sig_digits(value, delta))
668659
return self._format_maybe_minus_and_locale(fmt, value)
669660

670661
def format_data(self, value):

0 commit comments

Comments
 (0)