Skip to content

Commit be13e92

Browse files
committed
For polar plots, report cursor position with correct precision.
... similar to what's done for cartesian plots (in ScalarFormatter.format_data_short).
1 parent cd33ed2 commit be13e92

File tree

2 files changed

+48
-3
lines changed

2 files changed

+48
-3
lines changed

lib/matplotlib/projections/polar.py

Lines changed: 34 additions & 3 deletions
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))
@@ -1396,11 +1398,40 @@ def set_rgrids(self, radii, labels=None, angle=None, fmt=None, **kwargs):
13961398

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

14051436
def get_data_ratio(self):
14061437
"""

lib/matplotlib/tests/test_polar.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,17 @@ def test_thetalim_args():
357357
assert tuple(np.radians((ax.get_thetamin(), ax.get_thetamax()))) == (0, 1)
358358
ax.set_thetalim((2, 3))
359359
assert tuple(np.radians((ax.get_thetamin(), ax.get_thetamax()))) == (2, 3)
360+
361+
362+
def test_cursor_precision():
363+
ax = plt.subplot(projection="polar")
364+
# Higher radii correspond to higher theta-precisions.
365+
assert ax.format_coord(0, 0) == "θ=0π (0°), r=0.000"
366+
assert ax.format_coord(0, .1) == "θ=0.00π (0°), r=0.100"
367+
assert ax.format_coord(0, 1) == "θ=0.000π (0.0°), r=1.000"
368+
assert ax.format_coord(1, 0) == "θ=0.3π (57°), r=0.000"
369+
assert ax.format_coord(1, .1) == "θ=0.32π (57°), r=0.100"
370+
assert ax.format_coord(1, 1) == "θ=0.318π (57.3°), r=1.000"
371+
assert ax.format_coord(2, 0) == "θ=0.6π (115°), r=0.000"
372+
assert ax.format_coord(2, .1) == "θ=0.64π (115°), r=0.100"
373+
assert ax.format_coord(2, 1) == "θ=0.637π (114.6°), r=1.000"

0 commit comments

Comments
 (0)