如何在 matplotlib 中旋转 xticklabels 以使每个 xticklabel 之间的间距相等?
How can I rotate xticklabels in matplotlib so that the spacing between each xticklabel is equal?
如何在 matplotlib 中旋转 xticklabels 以使每个 xticklabel 之间的间距相等?
例如使用此代码:
import matplotlib.pyplot as plt
import numpy as np
# Data + parameters
fontsize = 20
t = np.arange(0.0, 6.0, 1)
xticklabels = ['Full', 'token emb', 'char emb', 'char LSTM',
'token LSTM', 'feed forward','ANN']
# Plotting
fig = plt.figure(1)
ax = fig.add_subplot(111)
plt.plot(t, t)
plt.xticks(range(0, len(t) + 1))
ax.tick_params(axis='both', which='major', labelsize=fontsize)
ax.set_xticklabels(xticklabels, rotation = 45)
fig.savefig('test_rotation.png', dpi=300, format='png', bbox_inches='tight')
我获得:
每个xticklabel 之间的间距不相等。例如,'Full' 和 'token emb' 之间的间距比 'feed forward' 和 'ANN' 之间的间距大得多。
我在 Windows 7 SP1 x64 Ultimate 上使用 Matplotlib 2.0.0 和 Python 3.5 64 位。
标签以刻度线位置为中心。它们的边界框宽度不等,甚至可能重叠,这使得它们看起来间隔不等。
由于您总是希望刻度标签 link 到它们的刻度标记,因此更改间距并不是一个真正的选择。
然而,您可能希望将它们对齐,使右上角成为它们在刻度线下方定位的参考。
为此使用 horizontalalignment
或 ha
参数并将其设置为 "right"
:
ax.set_xticklabels(xticklabels, rotation = 45, ha="right")
这导致以下情节:
另一种方法是让刻度标签水平居中,但也垂直居中。这导致间距相等,但需要进一步调整它们相对于轴的垂直位置。
ax.set_xticklabels(xticklabels, rotation = 45, va="center", position=(0,-0.28))
如果像问题中一样手动指定刻度(例如通过 plt.xticks
或通过 ax.set_xticks
)或者如果使用分类图,则可以使用以上内容。
相反,如果标签是自动显示的,那么 不应使用 set_xticklabels
。这通常会让标签和刻度位置变得不同步,因为 set_xticklabels
将轴的格式化程序设置为 FixedFormatter
,而定位器保持自动 AutoLocator
,或任何其他自动定位器。
在这些情况下,可以使用 plt.setp
设置现有标签的旋转和对齐方式,
plt.setp(ax.get_xticklabels(), ha="right", rotation=45)
或遍历它们以设置各自的属性,
for label in ax.get_xticklabels():
label.set_ha("right")
label.set_rotation(45)
一个例子是
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
t = np.arange("2018-01-01", "2018-03-01", dtype="datetime64[D]")
x = np.cumsum(np.random.randn(len(t)))
fig, ax = plt.subplots()
ax.plot(t, x)
for label in ax.get_xticklabels():
label.set_ha("right")
label.set_rotation(45)
plt.tight_layout()
plt.show()
这是一个很好的资源,提供了多种选择。它们并不完美,但基本上还可以:
https://www.pythoncharts.com/2019/05/17/rotating-axis-labels/
更新:
我查看了 matplotlib.text.Text.set_rotation_mode
(link) 的文档:
set_rotation_mode(self, m)
Set text rotation mode.
Parameters:
m : {None, 'default', 'anchor'}
If None or "default", the text will be first rotated,
then aligned according to their horizontal and vertical
alignments.
If "anchor", then alignment occurs before rotation.
所以如果不指定rotation_mode
,文本会先旋转再对齐。在此模式下,即使使用 ha="right"
,边界框也不完全位于文本的右上角。
如果rotation_mode="anchor"
,文字直接围绕锚点(ha="right"
)旋转。
这是一个例子(改编自here的代码)
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
labels = ['G1_bla_bla', 'G2_bla', 'G3_bla', 'G4_bla', 'G5_bla']
men_means = [20, 34, 30, 35, 27]
women_means = [25, 32, 34, 20, 25]
x = np.arange(len(labels)) # the label locations
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
ax.bar(x - width/2, men_means, width, label='Men')
ax.bar(x + width/2, women_means, width, label='Women')
# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(x)
ax.set_xticklabels(
labels,
rotation=30,
ha="right",
rotation_mode="anchor") # <====== HERE is the key
ax.legend()
plt.show()
绘图现在具有正确的对齐方式:
如果旋转角度是 ~45 度,那么 Ernest 的 ha='right
和 gbinux 的 rotation_mode='anchor'
很棒:
ax.set_xticklabels(xticklabels, rotation=45, ha='right', rotation_mode='anchor')
但是这对其他旋转角度效果不佳,例如70 度(见左侧子图)。
如果旋转角度不是 ~45 度,请将 ha='right'
与 ScaledTranslation
结合使用(见右侧子图)。
按照:
中所述应用ScaledTranslation
...
ax.set_xticklabels(xticklabels, rotation=70, ha='right')
# create offset transform (x=5pt)
from matplotlib.transforms import ScaledTranslation
dx, dy = 5, 0
offset = ScaledTranslation(dx/fig.dpi, dy/fig.dpi, scale_trans=fig.dpi_scale_trans)
# apply offset transform to all xticklabels
for label in ax.xaxis.get_majorticklabels():
label.set_transform(label.get_transform() + offset)
如何在 matplotlib 中旋转 xticklabels 以使每个 xticklabel 之间的间距相等?
例如使用此代码:
import matplotlib.pyplot as plt
import numpy as np
# Data + parameters
fontsize = 20
t = np.arange(0.0, 6.0, 1)
xticklabels = ['Full', 'token emb', 'char emb', 'char LSTM',
'token LSTM', 'feed forward','ANN']
# Plotting
fig = plt.figure(1)
ax = fig.add_subplot(111)
plt.plot(t, t)
plt.xticks(range(0, len(t) + 1))
ax.tick_params(axis='both', which='major', labelsize=fontsize)
ax.set_xticklabels(xticklabels, rotation = 45)
fig.savefig('test_rotation.png', dpi=300, format='png', bbox_inches='tight')
我获得:
每个xticklabel 之间的间距不相等。例如,'Full' 和 'token emb' 之间的间距比 'feed forward' 和 'ANN' 之间的间距大得多。
我在 Windows 7 SP1 x64 Ultimate 上使用 Matplotlib 2.0.0 和 Python 3.5 64 位。
标签以刻度线位置为中心。它们的边界框宽度不等,甚至可能重叠,这使得它们看起来间隔不等。
由于您总是希望刻度标签 link 到它们的刻度标记,因此更改间距并不是一个真正的选择。
然而,您可能希望将它们对齐,使右上角成为它们在刻度线下方定位的参考。
为此使用 horizontalalignment
或 ha
参数并将其设置为 "right"
:
ax.set_xticklabels(xticklabels, rotation = 45, ha="right")
这导致以下情节:
另一种方法是让刻度标签水平居中,但也垂直居中。这导致间距相等,但需要进一步调整它们相对于轴的垂直位置。
ax.set_xticklabels(xticklabels, rotation = 45, va="center", position=(0,-0.28))
如果像问题中一样手动指定刻度(例如通过 plt.xticks
或通过 ax.set_xticks
)或者如果使用分类图,则可以使用以上内容。
相反,如果标签是自动显示的,那么 不应使用 set_xticklabels
。这通常会让标签和刻度位置变得不同步,因为 set_xticklabels
将轴的格式化程序设置为 FixedFormatter
,而定位器保持自动 AutoLocator
,或任何其他自动定位器。
在这些情况下,可以使用 plt.setp
设置现有标签的旋转和对齐方式,
plt.setp(ax.get_xticklabels(), ha="right", rotation=45)
或遍历它们以设置各自的属性,
for label in ax.get_xticklabels():
label.set_ha("right")
label.set_rotation(45)
一个例子是
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
t = np.arange("2018-01-01", "2018-03-01", dtype="datetime64[D]")
x = np.cumsum(np.random.randn(len(t)))
fig, ax = plt.subplots()
ax.plot(t, x)
for label in ax.get_xticklabels():
label.set_ha("right")
label.set_rotation(45)
plt.tight_layout()
plt.show()
这是一个很好的资源,提供了多种选择。它们并不完美,但基本上还可以:
https://www.pythoncharts.com/2019/05/17/rotating-axis-labels/
更新:
我查看了 matplotlib.text.Text.set_rotation_mode
(link) 的文档:
set_rotation_mode(self, m)
Set text rotation mode.
Parameters:
m : {None, 'default', 'anchor'}
If None or "default", the text will be first rotated,
then aligned according to their horizontal and vertical
alignments.
If "anchor", then alignment occurs before rotation.
所以如果不指定rotation_mode
,文本会先旋转再对齐。在此模式下,即使使用 ha="right"
,边界框也不完全位于文本的右上角。
如果rotation_mode="anchor"
,文字直接围绕锚点(ha="right"
)旋转。
这是一个例子(改编自here的代码)
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
labels = ['G1_bla_bla', 'G2_bla', 'G3_bla', 'G4_bla', 'G5_bla']
men_means = [20, 34, 30, 35, 27]
women_means = [25, 32, 34, 20, 25]
x = np.arange(len(labels)) # the label locations
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
ax.bar(x - width/2, men_means, width, label='Men')
ax.bar(x + width/2, women_means, width, label='Women')
# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(x)
ax.set_xticklabels(
labels,
rotation=30,
ha="right",
rotation_mode="anchor") # <====== HERE is the key
ax.legend()
plt.show()
绘图现在具有正确的对齐方式:
如果旋转角度是 ~45 度,那么 Ernest 的 ha='right
和 gbinux 的 rotation_mode='anchor'
很棒:
ax.set_xticklabels(xticklabels, rotation=45, ha='right', rotation_mode='anchor')
但是这对其他旋转角度效果不佳,例如70 度(见左侧子图)。
如果旋转角度不是 ~45 度,请将 ha='right'
与 ScaledTranslation
结合使用(见右侧子图)。
按照
ScaledTranslation
...
ax.set_xticklabels(xticklabels, rotation=70, ha='right')
# create offset transform (x=5pt)
from matplotlib.transforms import ScaledTranslation
dx, dy = 5, 0
offset = ScaledTranslation(dx/fig.dpi, dy/fig.dpi, scale_trans=fig.dpi_scale_trans)
# apply offset transform to all xticklabels
for label in ax.xaxis.get_majorticklabels():
label.set_transform(label.get_transform() + offset)