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

Skip to content

Commit 2b4d611

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 2b4d611

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

lib/matplotlib/tests/test_ticker.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,16 @@ def test_scilimits(self, sci_type, scilimits, lim, orderOfMag, fewticks):
558558
tmp_form.set_locs(ax.yaxis.get_majorticklocs())
559559
assert orderOfMag == tmp_form.orderOfMagnitude
560560

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

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

lib/matplotlib/ticker.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@
168168
import logging
169169
import locale
170170
import math
171+
from numbers import Integral
171172

172173
import numpy as np
173174

@@ -587,11 +588,42 @@ def set_powerlimits(self, lims):
587588

588589
def format_data_short(self, value):
589590
# docstring inherited
591+
if isinstance(value, np.ma.MaskedArray) and value.mask:
592+
return ""
593+
if isinstance(value, Integral):
594+
fmt = "%d"
595+
else:
596+
if self.axis.__name__ in ["xaxis", "yaxis"]:
597+
if self.axis.__name__ == "xaxis":
598+
axis_trf = self.axis.axes.get_xaxis_transform()
599+
axis_inv_trf = axis_trf.inverted()
600+
screen_xy = axis_trf.transform((value, 0))
601+
neighbor_values = axis_inv_trf.transform(
602+
screen_xy + [[-1, 0], [+1, 0]])[:, 0]
603+
else: # yaxis:
604+
axis_trf = self.axis.axes.get_yaxis_transform()
605+
axis_inv_trf = axis_trf.inverted()
606+
screen_xy = axis_trf.transform((0, value))
607+
neighbor_values = axis_inv_trf.transform(
608+
screen_xy + [[0, -1], [0, +1]])[:, 1]
609+
delta = abs(neighbor_values - value).max()
610+
else:
611+
# Rough approximation: no more than 1e4 pixels.
612+
delta = self.axis.get_view_interval() / 1e4
613+
# If e.g. value = 45.67 and delta = 0.02, then we want to round to
614+
# 2 digits after the decimal point (floor(log10(0.02)) = -2);
615+
# 45.67 contributes 2 digits before the decimal point
616+
# (floor(log10(45.67)) + 1 = 2): the total is 4 significant digits.
617+
# A value of 0 contributes 1 "digit" before the decimal point.
618+
sig_digits = max(
619+
0,
620+
(math.floor(math.log10(abs(value))) + 1 if value else 1)
621+
- math.floor(math.log10(delta)))
622+
fmt = f"%-#.{sig_digits}g"
590623
return (
591-
"" if isinstance(value, np.ma.MaskedArray) and value.mask else
592624
self.fix_minus(
593-
locale.format_string("%-12g", (value,)) if self._useLocale else
594-
"%-12g" % value))
625+
locale.format_string(fmt, (value,)) if self._useLocale else
626+
fmt % value))
595627

596628
def format_data(self, value):
597629
# docstring inherited

0 commit comments

Comments
 (0)