Skip to content

Commit d0137e9

Browse files
authored
Merge pull request #20020 from anntzer/tcp
For polar plots, report cursor position with correct precision.
2 parents 0520d99 + 2058905 commit d0137e9

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

lib/matplotlib/projections/polar.py

+34-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections import OrderedDict
2+
import math
23
import types
34

45
import numpy as np
@@ -187,6 +188,7 @@ class ThetaFormatter(mticker.Formatter):
187188
Used to format the *theta* tick labels. Converts the native
188189
unit of radians into degrees and adds a degree symbol.
189190
"""
191+
190192
def __call__(self, x, pos=None):
191193
vmin, vmax = self.axis.get_view_interval()
192194
d = np.rad2deg(abs(vmax - vmin))
@@ -1403,11 +1405,40 @@ def set_rgrids(self, radii, labels=None, angle=None, fmt=None, **kwargs):
14031405

14041406
def format_coord(self, theta, r):
14051407
# docstring inherited
1408+
screen_xy = self.transData.transform((theta, r))
1409+
screen_xys = screen_xy + np.stack(
1410+
np.meshgrid([-1, 0, 1], [-1, 0, 1])).reshape((2, -1)).T
1411+
ts, rs = self.transData.inverted().transform(screen_xys).T
1412+
delta_t = abs((ts - theta + np.pi) % (2 * np.pi) - np.pi).max()
1413+
delta_t_halfturns = delta_t / np.pi
1414+
delta_t_degrees = delta_t_halfturns * 180
1415+
delta_r = abs(rs - r).max()
14061416
if theta < 0:
14071417
theta += 2 * np.pi
1408-
theta /= np.pi
1409-
return ('\N{GREEK SMALL LETTER THETA}=%0.3f\N{GREEK SMALL LETTER PI} '
1410-
'(%0.3f\N{DEGREE SIGN}), r=%0.3f') % (theta, theta * 180.0, r)
1418+
theta_halfturns = theta / np.pi
1419+
theta_degrees = theta_halfturns * 180
1420+
1421+
# See ScalarFormatter.format_data_short. For r, use #g-formatting
1422+
# (as for linear axes), but for theta, use f-formatting as scientific
1423+
# notation doesn't make sense and the trailing dot is ugly.
1424+
def format_sig(value, delta, opt, fmt):
1425+
digits_post_decimal = math.floor(math.log10(delta))
1426+
digits_offset = (
1427+
# For "f", only count digits after decimal point.
1428+
0 if fmt == "f"
1429+
# For "g", offset by digits before the decimal point.
1430+
else math.floor(math.log10(abs(value))) + 1 if value
1431+
# For "g", 0 contributes 1 "digit" before the decimal point.
1432+
else 1)
1433+
fmt_prec = max(0, digits_offset - digits_post_decimal)
1434+
return f"{value:-{opt}.{fmt_prec}{fmt}}"
1435+
1436+
return ('\N{GREEK SMALL LETTER THETA}={}\N{GREEK SMALL LETTER PI} '
1437+
'({}\N{DEGREE SIGN}), r={}').format(
1438+
format_sig(theta_halfturns, delta_t_halfturns, "", "f"),
1439+
format_sig(theta_degrees, delta_t_degrees, "", "f"),
1440+
format_sig(r, delta_r, "#", "g"),
1441+
)
14111442

14121443
def get_data_ratio(self):
14131444
"""

lib/matplotlib/tests/test_polar.py

+14
Original file line numberDiff line numberDiff line change
@@ -410,3 +410,17 @@ def test_axvline_axvspan_do_not_modify_rlims():
410410
ax.axvline(.5)
411411
ax.plot([.1, .2])
412412
assert ax.get_ylim() == (0, .2)
413+
414+
415+
def test_cursor_precision():
416+
ax = plt.subplot(projection="polar")
417+
# Higher radii correspond to higher theta-precisions.
418+
assert ax.format_coord(0, 0) == "θ=0π (0°), r=0.000"
419+
assert ax.format_coord(0, .1) == "θ=0.00π (0°), r=0.100"
420+
assert ax.format_coord(0, 1) == "θ=0.000π (0.0°), r=1.000"
421+
assert ax.format_coord(1, 0) == "θ=0.3π (57°), r=0.000"
422+
assert ax.format_coord(1, .1) == "θ=0.32π (57°), r=0.100"
423+
assert ax.format_coord(1, 1) == "θ=0.318π (57.3°), r=1.000"
424+
assert ax.format_coord(2, 0) == "θ=0.6π (115°), r=0.000"
425+
assert ax.format_coord(2, .1) == "θ=0.64π (115°), r=0.100"
426+
assert ax.format_coord(2, 1) == "θ=0.637π (114.6°), r=1.000"

0 commit comments

Comments
 (0)