如何在 matplotlib 中旋转 xticlabel,使每个 xticlabel 之间的间距相等?

如何在 matplotlib 中旋转 xticlabel,使每个 xticlabel 之间的间距相等?

例如,使用以下代码:

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')

我得到:

enter image description here

每个 xticlabel 之间的间距是不等的。例如,“ Full”和“ Token emb”之间的间距比“ feed forward”和“ ANN”之间的间距大得多。

我在 Windows 7 SP1 x64 Ultimate 上使用 Matplotlib 2.0.0和 Python 3.564位。

103549 次浏览

标签位于标记位置的中心。它们的边框宽度不等,甚至可能重叠,这使得它们看起来间隔不等。

enter image description here

因为您总是希望标签链接到它们的标记,所以更改间距实际上不是一个选项。

然而,你可能想要对齐他们这样的右上角是他们的定位参考下面的刻度。

使用 horizontalalignmentha参数,并将其设置为 "right":

ax.set_xticklabels(xticklabels, rotation = 45, ha="right")

这导致了以下情节:

enter image description here

另一种方法是保持标签水平居中,但也垂直居中。这导致一个相等的间距,但需要进一步调整其垂直位置相对于轴。

ax.set_xticklabels(xticklabels, rotation = 45, va="center", position=(0,-0.28))

enter image description here


enter image description here

如果像问题中那样手动指定刻度(例如通过 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(链接)的文档:

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")旋转。

下面是一个示例(改编自 给你的代码)

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()

情节现在有了正确的走向:

enter image description here

如果旋转角度大约是45度,那么 Ernest 的 ha='right和 gbinux 的 rotation_mode='anchor'就很棒:

ax.set_xticklabels(xticklabels, rotation=45, ha='right', rotation_mode='anchor')

然而,这并不适用于其他旋转角度,例如70度(见左侧子图)。

如果旋转角度不是 ~ 45度,则将 ha='right' ScaledTranslation 组合(参见右侧子图)。

without and with 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)