web-dev-qa-db-fra.com

Comment puis-je faire pivoter xticklabels dans matplotlib afin que l'espacement entre chaque xticklabel soit égal?

Comment puis-je faire pivoter xticklabels dans matplotlib afin que l'espacement entre chaque xticklabel soit égal?

Par exemple avec ce code:

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

J'obtiens:

enter image description here

L'espacement entre chaque xticklabel est inégal. Par exemple, l'espacement entre "Full" et "token emb" est beaucoup plus grand que l'espacement entre "feed forward" et "ANN".

J'utilise Matplotlib 2.0.0 et Python 3.5 64 bits sur Windows 7 SP1 x64 Ultimate.

15

Les étiquettes sont centrées à la position de la coche. Leurs boîtes de délimitation sont de largeur inégale et peuvent même se chevaucher, ce qui les rend espacées de manière inégale.

enter image description here

Étant donné que vous souhaitez toujours que les étiquettes soient liées à leurs graduations, la modification de l'espacement n'est pas vraiment une option.

Cependant, vous souhaiterez peut-être les aligner de sorte que le coin supérieur droit soit la référence pour leur positionnement sous la coche.

Utilisez l'argument horizontalalignment ou ha pour cela et définissez-le sur "right":

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

Il en résulte le tracé suivant:

enter image description here

Une alternative peut être de garder les ticklabels centrés horizontalement, mais aussi de les centrer verticalement. Cela conduit à un espacement égal mais nécessaire pour ajuster davantage leur position verticale par rapport à l'axe.

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

enter image description here


enter image description here

Ce qui précède peut être utilisé si les graduations sont spécifiées manuellement comme dans la question (par exemple via plt.xticks ou via ax.set_xticks) ou si un tracé catégoriel est utilisé.
Si, au contraire, les étiquettes sont affichées automatiquement, une ne doit pas utiliser set_xticklabels. Cela laissera généralement les étiquettes et les positions des ticks désynchronisées, car set_xticklabels définit le formateur des axes sur FixedFormatter, tandis que le localisateur reste le AutoLocator automatique ou tout autre localisateur automatique.

Dans ces cas, utilisez soit plt.setp pour définir la rotation et l'alignement des étiquettes existantes,

plt.setp(ax.get_xticklabels(), ha="right", rotation=45)

ou boucle sur eux pour définir les propriétés respectives,

for label in ax.get_xticklabels():
    label.set_ha("right")
    label.set_rotation(45)

Un exemple serait

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