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

Skip to content

Commit 9c4d240

Browse files
committed
Make cursor text precision actually correspond to pointing precision.
Currently, the cursor text (x=..., y=...) is typically displayed with much, much more precision than the mouse cursor has (typically, one pixel); IOW the last digits displayed are typically meaningless. Make ScalarFormatter.format_data_short convert the inter-pixel distance to data space and compute the corresponding number of significant digits to use (and don't drop the final zeroes if any, as they are now, well, significant). (A similar change could be applied to other formatters, e.g. LogFormatter.)
1 parent 053703f commit 9c4d240

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

lib/matplotlib/tests/test_ticker.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,9 @@ class TestScalarFormatter:
512512
(True, (6, 6), (-1e5, 1e5), 6, False),
513513
]
514514

515-
@pytest.mark.parametrize('unicode_minus, result',
516-
[(True, "\N{MINUS SIGN}1"), (False, "-1")])
515+
@pytest.mark.parametrize(
516+
'unicode_minus, result',
517+
[(True, "\N{MINUS SIGN}1.000"), (False, "-1.000")])
517518
def test_unicode_minus(self, unicode_minus, result):
518519
mpl.rcParams['axes.unicode_minus'] = unicode_minus
519520
assert (
@@ -558,6 +559,16 @@ def test_scilimits(self, sci_type, scilimits, lim, orderOfMag, fewticks):
558559
tmp_form.set_locs(ax.yaxis.get_majorticklocs())
559560
assert orderOfMag == tmp_form.orderOfMagnitude
560561

562+
def test_cursor_precision(self):
563+
fig, ax = plt.subplots()
564+
ax.set_xlim(-1, 1) # Pointing precision of 0.001.
565+
fmt = ax.xaxis.get_major_formatter().format_data_short
566+
assert fmt(0) == "0.000"
567+
assert fmt(0.0123) == "0.012"
568+
assert fmt(0.123) == "0.123"
569+
assert fmt(1.23) == "1.230"
570+
assert fmt(12.3) == "12.300"
571+
561572

562573
class FakeAxis:
563574
"""Allow Formatter to be called without having a "full" plot set up."""

lib/matplotlib/ticker.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,11 +587,36 @@ def set_powerlimits(self, lims):
587587

588588
def format_data_short(self, value):
589589
# docstring inherited
590+
fmt = "%-12g"
591+
if self.axis.__name__ in ["xaxis", "yaxis"]:
592+
if self.axis.__name__ == "xaxis":
593+
axis_trf = self.axis.axes.get_xaxis_transform()
594+
axis_inv_trf = axis_trf.inverted()
595+
screen_x, screen_y = axis_trf.transform((value, 0))
596+
prev_value, _ = axis_inv_trf.transform((screen_x-1, screen_y))
597+
next_value, _ = axis_inv_trf.transform((screen_x+1, screen_y))
598+
else: # yaxis:
599+
axis_trf = self.axis.axes.get_yaxis_transform()
600+
axis_inv_trf = axis_trf.inverted()
601+
screen_x, screen_y = axis_trf.transform((0, value))
602+
_, prev_value = axis_inv_trf.transform((screen_x, screen_y-1))
603+
_, next_value = axis_inv_trf.transform((screen_x, screen_y+1))
604+
# If e.g. value = 45.67 and delta = 0.02, then we want to round to
605+
# 2 digits after the decimal point (floor(log10(0.02)) = -2); 45.67
606+
# contributes 2 digits before the decimal point (ceil(log10(45.67))
607+
# = 2) so the total is 4 significant digits. A value of zero
608+
# contributes 1 "digit" before the decimal point.
609+
sig_digits = max(
610+
0,
611+
(math.ceil(math.log10(abs(value))) if value else 1)
612+
- math.floor(math.log10(max(abs(prev_value - value),
613+
abs(next_value - value)))))
614+
fmt = f"%-#.{sig_digits}g"
590615
return (
591616
"" if isinstance(value, np.ma.MaskedArray) and value.mask else
592617
self.fix_minus(
593-
locale.format_string("%-12g", (value,)) if self._useLocale else
594-
"%-12g" % value))
618+
locale.format_string(fmt, (value,)) if self._useLocale else
619+
fmt % value))
595620

596621
def format_data(self, value):
597622
# docstring inherited

0 commit comments

Comments
 (0)