Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit98778bb

Browse files
committed
Implement xtick and ytick rotation_mode
1 parent84fbae8 commit98778bb

File tree

9 files changed

+131
-10
lines changed

9 files changed

+131
-10
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
``xtick`` and ``ytick`` rotation modes
2+
--------------------------------------
3+
4+
A new feature has been added for handling rotation of xtick and ytick
5+
labels more intuitively. The new `rotation modes <matplotlib.text.Text.set_rotation_mode>`
6+
"xtick" and "ytick" automatically adjust the alignment of rotated tick labels,
7+
so that the text points towards their anchor point, i.e. ticks. This works for
8+
all four sides of the plot (bottom, top, left, right), reducing the need for
9+
manual adjustments when rotating labels.
10+
11+
..plot::
12+
:include-source: true
13+
:alt: Example of rotated xtick and ytick labels.
14+
15+
import matplotlib.pyplot as plt
16+
17+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 3.5), layout='constrained')
18+
19+
pos = range(5)
20+
labels = ['label'] * 5
21+
ax1.set_xticks(pos, labels, rotation=-45, rotation_mode='xtick')
22+
ax1.set_yticks(pos, labels, rotation=45, rotation_mode='ytick')
23+
ax2.xaxis.tick_top()
24+
ax2.set_xticks(pos, labels, rotation=-45, rotation_mode='xtick')
25+
ax2.yaxis.tick_right()
26+
ax2.set_yticks(pos, labels, rotation=45, rotation_mode='ytick')
27+
28+
plt.show()

‎galleries/examples/images_contours_and_fields/image_annotated_heatmap.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464

6565
# Show all ticks and label them with the respective list entries
6666
ax.set_xticks(range(len(farmers)),labels=farmers,
67-
rotation=45,ha="right",rotation_mode="anchor")
67+
rotation=45,rotation_mode="xtick")
6868
ax.set_yticks(range(len(vegetables)),labels=vegetables)
6969

7070
# Loop over data dimensions and create text annotations.
@@ -135,7 +135,7 @@ def heatmap(data, row_labels, col_labels, ax=None,
135135

136136
# Show all ticks and label them with the respective list entries.
137137
ax.set_xticks(range(data.shape[1]),labels=col_labels,
138-
rotation=-30,ha="right",rotation_mode="anchor")
138+
rotation=-30,rotation_mode="xtick")
139139
ax.set_yticks(range(data.shape[0]),labels=row_labels)
140140

141141
# Let the horizontal axes labeling appear on top.

‎galleries/examples/subplots_axes_and_figures/align_labels_demo.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
ax.plot(np.arange(1.,0.,-0.1)*2000.,np.arange(1.,0.,-0.1))
2727
ax.set_title('Title0 1')
2828
ax.xaxis.tick_top()
29-
ax.tick_params(axis='x',rotation=55)
29+
ax.set_xticks(ax.get_xticks())
30+
ax.tick_params(axis='x',rotation=55,rotation_mode='xtick')
3031

3132

3233
foriinrange(2):
@@ -35,7 +36,8 @@
3536
ax.set_ylabel('YLabel1 %d'%i)
3637
ax.set_xlabel('XLabel1 %d'%i)
3738
ifi==0:
38-
ax.tick_params(axis='x',rotation=55)
39+
ax.set_xticks(ax.get_xticks())
40+
ax.tick_params(axis='x',rotation=55,rotation_mode='xtick')
3941

4042
fig.align_labels()# same as fig.align_xlabels(); fig.align_ylabels()
4143
fig.align_titles()

‎lib/matplotlib/axis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def __init__(
149149
# grid(color=(1, 1, 1, 0.5), alpha=rcParams['grid.alpha'])
150150
# so the that the rcParams default would override color alpha.
151151
grid_alpha=mpl.rcParams["grid.alpha"]
152-
grid_kw= {k[5:]:vfork,vinkwargs.items()}
152+
grid_kw= {k[5:]:vfork,vinkwargs.items()ifk!="rotation_mode"}
153153

154154
self.tick1line=mlines.Line2D(
155155
[], [],
@@ -1078,7 +1078,7 @@ def _translate_tick_params(kw, reverse=False):
10781078
'tick1On','tick2On','label1On','label2On',
10791079
'length','direction','left','bottom','right','top',
10801080
'labelleft','labelbottom','labelright','labeltop',
1081-
'labelrotation',
1081+
'labelrotation','rotation_mode',
10821082
*_gridline_param_names]
10831083

10841084
keymap= {

‎lib/matplotlib/tests/test_text.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,3 +1135,58 @@ def test_font_wrap():
11351135
plt.text(3,4,t,family='monospace',ha='right',wrap=True)
11361136
plt.text(-1,0,t,fontsize=14,style='italic',ha='left',rotation=-15,
11371137
wrap=True)
1138+
1139+
1140+
deftest_ha_for_angle():
1141+
text_instance=Text()
1142+
angles=np.arange(0,360.1,0.1)
1143+
forangleinangles:
1144+
alignment=text_instance._ha_for_angle(angle)
1145+
assertalignmentin ['center','left','right']
1146+
1147+
1148+
deftest_va_for_angle():
1149+
text_instance=Text()
1150+
angles=np.arange(0,360.1,0.1)
1151+
forangleinangles:
1152+
alignment=text_instance._va_for_angle(angle)
1153+
assertalignmentin ['center','top','baseline']
1154+
1155+
1156+
@image_comparison(baseline_images=['xtick_rotation_mode'],
1157+
remove_text=False,extensions=['png'],style='mpl20')
1158+
deftest_xtick_rotation_mode():
1159+
fig,ax=plt.subplots(figsize=(12,1))
1160+
ax.set_yticks([])
1161+
ax2=ax.twiny()
1162+
1163+
ax.set_xticks(range(37), ['foo']*37,rotation_mode="xtick")
1164+
ax2.set_xticks(range(37), ['foo']*37,rotation_mode="xtick")
1165+
1166+
angles=np.linspace(0,360,37)
1167+
1168+
fortick,angleinzip(ax.get_xticklabels(),angles):
1169+
tick.set_rotation(angle)
1170+
fortick,angleinzip(ax2.get_xticklabels(),angles):
1171+
tick.set_rotation(angle)
1172+
1173+
plt.subplots_adjust(left=0.01,right=0.99,top=.6,bottom=.4)
1174+
1175+
1176+
@image_comparison(baseline_images=['ytick_rotation_mode'],
1177+
remove_text=False,extensions=['png'],style='mpl20')
1178+
deftest_ytick_rotation_mode():
1179+
fig,ax=plt.subplots(figsize=(1,12))
1180+
ax.set_xticks([])
1181+
ax2=ax.twinx()
1182+
1183+
ax.set_yticks(range(37), ['foo']*37,rotation_mode="ytick")
1184+
ax2.set_yticks(range(37), ['foo']*37,rotation_mode='ytick')
1185+
1186+
angles=np.linspace(0,360,37)
1187+
fortick,angleinzip(ax.get_yticklabels(),angles):
1188+
tick.set_rotation(angle)
1189+
fortick,angleinzip(ax2.get_yticklabels(),angles):
1190+
tick.set_rotation(angle)
1191+
1192+
plt.subplots_adjust(left=0.4,right=0.6,top=.99,bottom=.01)

‎lib/matplotlib/text.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,16 +301,19 @@ def set_rotation_mode(self, m):
301301
302302
Parameters
303303
----------
304-
m : {None, 'default', 'anchor'}
304+
m : {None, 'default', 'anchor', 'xtick', 'ytick'}
305305
If ``"default"``, the text will be first rotated, then aligned according
306306
to their horizontal and vertical alignments. If ``"anchor"``, then
307-
alignment occurs before rotation. Passing ``None`` will set the rotation
308-
mode to ``"default"``.
307+
alignment occurs before rotation. "xtick" and "ytick" adjust the
308+
horizontal/vertical alignment so that the text is visually pointing
309+
towards its anchor point. This is primarily used for rotated tick
310+
labels and positions them nicely towards their ticks. Passing
311+
``None`` will set the rotation mode to ``"default"``.
309312
"""
310313
ifmisNone:
311314
m="default"
312315
else:
313-
_api.check_in_list(("anchor","default"),rotation_mode=m)
316+
_api.check_in_list(("anchor","default","xtick","ytick"),rotation_mode=m)
314317
self._rotation_mode=m
315318
self.stale=True
316319

@@ -454,6 +457,11 @@ def _get_layout(self, renderer):
454457

455458
rotation_mode=self.get_rotation_mode()
456459
ifrotation_mode!="anchor":
460+
angle=self.get_rotation()
461+
ifrotation_mode=='xtick':
462+
halign=self._ha_for_angle(angle)
463+
elifrotation_mode=='ytick':
464+
valign=self._va_for_angle(angle)
457465
# compute the text location in display coords and the offsets
458466
# necessary to align the bbox with that location
459467
ifhalign=='center':
@@ -1380,6 +1388,32 @@ def set_fontname(self, fontname):
13801388
"""
13811389
self.set_fontfamily(fontname)
13821390

1391+
def_ha_for_angle(self,angle):
1392+
"""
1393+
Determines horizontal alignment ('ha') for rotation_mode "xtick" based on
1394+
the angle of rotation in degrees and the vertical alignment.
1395+
"""
1396+
anchor_at_bottom=self.get_verticalalignment()=='bottom'
1397+
if (angle<=10or85<=angle<=95or350<=angleor
1398+
170<=angle<=190or265<=angle<=275):
1399+
return'center'
1400+
elif10<angle<85or190<angle<265:
1401+
return'left'ifanchor_at_bottomelse'right'
1402+
return'right'ifanchor_at_bottomelse'left'
1403+
1404+
def_va_for_angle(self,angle):
1405+
"""
1406+
Determines vertical alignment ('va') for rotation_mode "ytick" based on
1407+
the angle of rotation in degrees and the horizontal alignment.
1408+
"""
1409+
anchor_at_left=self.get_horizontalalignment()=='left'
1410+
if (angle<=10or350<=angleor170<=angle<=190
1411+
or80<=angle<=100or260<=angle<=280):
1412+
return'center'
1413+
elif190<angle<260or10<angle<80:
1414+
return'baseline'ifanchor_at_leftelse'top'
1415+
return'top'ifanchor_at_leftelse'baseline'
1416+
13831417

13841418
classOffsetFrom:
13851419
"""Callable helper class for working with `Annotation`."""

‎lib/matplotlib/text.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ class Text(Artist):
106106
defset_fontname(self,fontname:str|Iterable[str])->None: ...
107107
defget_antialiased(self)->bool: ...
108108
defset_antialiased(self,antialiased:bool)->None: ...
109+
def_ha_for_angle(self,angle:Any)->Literal['center','right','left']|None: ...
110+
def_va_for_angle(self,angle:Any)->Literal['center','top','baseline']|None: ...
109111

110112
classOffsetFrom:
111113
def__init__(

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp