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

Skip to content

Commit 228ee53

Browse files
committed
Add an 'auto' option to label rotation.
This option enables the automatic rotation of polar tick labels.
1 parent 77e2532 commit 228ee53

File tree

4 files changed

+62
-21
lines changed

4 files changed

+62
-21
lines changed

doc/users/whats_new.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,13 @@ negative values are simply used as labels, and the real radius is shifted by
6262
the configured minimum. This release also allows negative radii to be used for
6363
grids and ticks, which were previously silently ignored.
6464

65-
For plots of a partial circle, radial ticks and tick labels have been modified
66-
to be parallel to the circular grid line. Angular ticks have been modified to
67-
be parallel to the grid line and the labels are now perpendicular to the grid
68-
line (i.e., parallel to the outer boundary.)
65+
Radial ticks have be modified to be parallel to the circular grid line. Angular
66+
ticks will be modified to be parallel to the grid line. It may also be useful
67+
to rotate tick labels to match the boundary. Calling
68+
``ax.tick_params(rotation='auto')`` will enable this new behavior. Radial tick
69+
labels will be modified to be parallel to the circular grid line. Angular tick
70+
labels will be perpendicular to the grid line (i.e., parallel to the outer
71+
boundary.)
6972

7073

7174
Merge JSAnimation

lib/matplotlib/axis.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def __init__(self, axes, loc, label,
140140
labelsize = rcParams['%s.labelsize' % name]
141141
self._labelsize = labelsize
142142

143-
self._labelrotation = labelrotation
143+
self._set_labelrotation(labelrotation)
144144

145145
if zorder is None:
146146
if major:
@@ -167,6 +167,20 @@ def __init__(self, axes, loc, label,
167167

168168
self.update_position(loc)
169169

170+
def _set_labelrotation(self, labelrotation):
171+
if isinstance(labelrotation, six.string_types):
172+
mode = labelrotation
173+
angle = 0
174+
elif isinstance(labelrotation, (tuple, list)):
175+
mode, angle = labelrotation
176+
else:
177+
mode = 'default'
178+
angle = labelrotation
179+
if mode not in ('auto', 'default'):
180+
raise ValueError("Label rotation mode must be 'default' or "
181+
"'auto', not '{}'.".format(mode))
182+
self._labelrotation = (mode, angle)
183+
170184
def apply_tickdir(self, tickdir):
171185
"""
172186
Calculate self._pad and self._tickmarkers
@@ -331,8 +345,14 @@ def _apply_params(self, **kw):
331345
self.tick2line.set(**tick_kw)
332346
for k, v in six.iteritems(tick_kw):
333347
setattr(self, '_' + k, v)
348+
349+
if 'labelrotation' in kw:
350+
self._set_labelrotation(kw.pop('labelrotation'))
351+
self.label1.set(rotation=self._labelrotation[1])
352+
self.label2.set(rotation=self._labelrotation[1])
353+
334354
label_list = [k for k in six.iteritems(kw)
335-
if k[0] in ['labelsize', 'labelcolor', 'labelrotation']]
355+
if k[0] in ['labelsize', 'labelcolor']]
336356
if label_list:
337357
label_kw = {k[5:]: v for k, v in label_list}
338358
self.label1.set(**label_kw)

lib/matplotlib/projections/polar.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from __future__ import (absolute_import, division, print_function,
22
unicode_literals)
33

4+
import six
5+
46
from collections import OrderedDict
57

68
import numpy as np
@@ -251,9 +253,9 @@ class ThetaTick(maxis.XTick):
251253
tick location. This results in ticks that are correctly perpendicular to
252254
the arc spine.
253255
254-
Labels are also rotated to be parallel to the spine. The label padding is
255-
also applied here since it's not possible to use a generic axes transform
256-
to produce tick-specific padding.
256+
When 'auto' rotation is enabled, labels are also rotated to be parallel to
257+
the spine. The label padding is also applied here since it's not possible
258+
to use a generic axes transform to produce tick-specific padding.
257259
"""
258260
def __init__(self, axes, *args, **kwargs):
259261
self._text1_translate = mtransforms.ScaledTranslation(
@@ -322,14 +324,15 @@ def update_position(self, loc):
322324
trans = self.tick2line._marker._transform
323325
self.tick2line._marker._transform = trans
324326

325-
if not _is_full_circle_deg(axes.get_thetamin(), axes.get_thetamax()):
327+
mode, user_angle = self._labelrotation
328+
if mode == 'default':
329+
angle = 0
330+
else:
326331
if angle > np.pi / 2:
327332
angle -= np.pi
328333
elif angle < -np.pi / 2:
329334
angle += np.pi
330-
else:
331-
angle = 0
332-
angle = np.rad2deg(angle) + self._labelrotation
335+
angle = np.rad2deg(angle) + user_angle
333336
if self.label1On:
334337
self.label1.set_rotation(angle)
335338
if self.label2On:
@@ -488,8 +491,8 @@ class RadialTick(maxis.YTick):
488491
This subclass of `YTick` provides radial ticks with some small modification
489492
to their re-positioning such that ticks are rotated based on axes limits.
490493
This results in ticks that are correctly perpendicular to the spine. Labels
491-
are also rotated to be perpendicular to the spine, but only for wedges, to
492-
preserve backwards compatibility.
494+
are also rotated to be perpendicular to the spine, when 'auto' rotation is
495+
enabled.
493496
"""
494497
def _get_text1(self):
495498
t = super(RadialTick, self)._get_text1()
@@ -524,9 +527,14 @@ def update_position(self, loc):
524527
full = _is_full_circle_deg(thetamin, thetamax)
525528

526529
if full:
527-
angle = axes.get_rlabel_position()
530+
angle = axes.get_rlabel_position() * direction + offset - 90
528531
tick_angle = 0
529-
text_angle = 0
532+
if angle > 90:
533+
text_angle = angle - 180
534+
elif angle < -90:
535+
text_angle = angle + 180
536+
else:
537+
text_angle = angle
530538
else:
531539
angle = thetamin * direction + offset - 90
532540
if direction > 0:
@@ -539,7 +547,11 @@ def update_position(self, loc):
539547
text_angle = angle + 180
540548
else:
541549
text_angle = angle
542-
text_angle += self._labelrotation
550+
mode, user_angle = self._labelrotation
551+
if mode == 'auto':
552+
text_angle += user_angle
553+
else:
554+
text_angle = user_angle
543555
if self.label1On:
544556
if full:
545557
ha = 'left'
@@ -583,7 +595,11 @@ def update_position(self, loc):
583595
text_angle = angle + 180
584596
else:
585597
text_angle = angle
586-
text_angle += self._labelrotation
598+
mode, user_angle = self._labelrotation
599+
if mode == 'auto':
600+
text_angle += user_angle
601+
else:
602+
text_angle = user_angle
587603
if self.label2On:
588604
ha, va = self._determine_anchor(angle, False)
589605
self.label2.set_ha(ha)

lib/matplotlib/tests/test_axes.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@ def test_polar_rlabel_position():
668668
fig = plt.figure()
669669
ax = fig.add_subplot(111, projection='polar')
670670
ax.set_rlabel_position(315)
671+
ax.tick_params(rotation='auto')
671672

672673

673674
@image_comparison(baseline_images=['polar_theta_wedge'], style='default',
@@ -692,8 +693,9 @@ def test_polar_theta_limits():
692693
ax.set_thetamin(start)
693694
ax.set_thetamax(end)
694695
ax.tick_params(tick1On=True, tick2On=True,
695-
direction=DIRECTIONS[i % len(DIRECTIONS)])
696-
ax.yaxis.set_tick_params(label2On=True)
696+
direction=DIRECTIONS[i % len(DIRECTIONS)],
697+
rotation='auto')
698+
ax.yaxis.set_tick_params(label2On=True, rotation='auto')
697699
else:
698700
ax.set_visible(False)
699701

0 commit comments

Comments
 (0)