Quelle est la meilleure pratique pour ajouter une ligne et un en-tête de colonne à une grille de sous-tracés générés dans une boucle dans matplotlib
? Je peux penser à un couple, mais pas particulièrement soigné:
set_title()
pour la première ligne uniquement. Pour les lignes, cela ne fonctionne pas. Vous devriez dessiner text
en dehors des tracés.Pouvez-vous suggérer une meilleure alternative?
Il y a plusieurs moyens de le faire. Le moyen le plus simple est d'exploiter les étiquettes y et les titres de l'intrigue, puis d'utiliser fig.tight_layout()
pour faire de la place aux étiquettes. Alternativement, vous pouvez placer du texte supplémentaire au bon endroit avec annotate
, puis faire de la place semi-manuellement.
Si vous n'avez pas d'étiquettes y sur vos axes, il est facile d'exploiter le titre et l'étiquette y de la première ligne et colonne des axes.
import matplotlib.pyplot as plt
cols = ['Column {}'.format(col) for col in range(1, 4)]
rows = ['Row {}'.format(row) for row in ['A', 'B', 'C', 'D']]
fig, axes = plt.subplots(nrows=4, ncols=3, figsize=(12, 8))
for ax, col in Zip(axes[0], cols):
ax.set_title(col)
for ax, row in Zip(axes[:,0], rows):
ax.set_ylabel(row, rotation=0, size='large')
fig.tight_layout()
plt.show()
Si vous avez des étiquettes y ou si vous préférez un peu plus de flexibilité, vous pouvez utiliser annotate
pour placer les étiquettes. Ceci est plus compliqué, mais vous permet d'avoir des titres de tracé, des étiquettes, etc. en plus des étiquettes de ligne et de colonne.
import matplotlib.pyplot as plt
from matplotlib.transforms import offset_copy
cols = ['Column {}'.format(col) for col in range(1, 4)]
rows = ['Row {}'.format(row) for row in ['A', 'B', 'C', 'D']]
fig, axes = plt.subplots(nrows=4, ncols=3, figsize=(12, 8))
plt.setp(axes.flat, xlabel='X-label', ylabel='Y-label')
pad = 5 # in points
for ax, col in Zip(axes[0], cols):
ax.annotate(col, xy=(0.5, 1), xytext=(0, pad),
xycoords='axes fraction', textcoords='offset points',
size='large', ha='center', va='baseline')
for ax, row in Zip(axes[:,0], rows):
ax.annotate(row, xy=(0, 0.5), xytext=(-ax.yaxis.labelpad - pad, 0),
xycoords=ax.yaxis.label, textcoords='offset points',
size='large', ha='right', va='center')
fig.tight_layout()
# tight_layout doesn't take these labels into account. We'll need
# to make some room. These numbers are are manually tweaked.
# You could automatically calculate them, but it's a pain.
fig.subplots_adjust(left=0.15, top=0.95)
plt.show()
La réponse ci-dessus fonctionne. Mais pas que dans la deuxième version de la réponse, vous avez:
for ax, row in Zip(axes[:,0], rows):
ax.annotate(col, xy=(0, 0.5), xytext=(-ax.yaxis.labelpad-pad,0),
xycoords=ax.yaxis.label, textcoords='offset points',
size='large', ha='right', va='center')
au lieu de:
for ax, row in Zip(axes[:,0], rows):
ax.annotate(row,xy=(0, 0.5), xytext=(-ax.yaxis.labelpad-pad,0),
xycoords=ax.yaxis.label, textcoords='offset points',
size='large', ha='right', va='center')