Заголовки рядків і стовпців у підпрограмах matplotlib


89

Яка найкраща практика додавання рядка та заголовка стовпця до сітки підзаголовків, створених у циклі matplotlib? Я можу подумати про пару, але не особливо акуратну:

  1. Для стовпців із лічильником вашого циклу ви можете використовувати set_title()лише перший рядок. Для рядків це не працює. Вам довелося б малювати textпоза сюжетами.
  2. Ви додаєте додатковий рядок додаткових сюжетів зверху та додатковий стовпець підгрупп ліворуч і малюєте текст в середині цього підзагортання.

Чи можете ви запропонувати кращу альтернативу?

введіть тут опис зображення

Відповіді:


116

Є кілька способів зробити це. Найпростіший спосіб - використати ярлики y та заголовки сюжету, а потім використовувати, fig.tight_layout()щоб звільнити місце для міток. Крім того, ви можете розмістити додатковий текст у потрібному місці за допомогою, annotateа потім зробити його напівручно.


Якщо на осях немає ярликів y, легко використати заголовок та ярлик y першого рядка та стовпця осей.

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

введіть тут опис зображення


Якщо у вас є мітки y, або якщо ви віддаєте перевагу трохи більшій гнучкості, ви можете використовувати annotateдля розміщення міток. Це складніше, але дозволяє вам мати окремі заголовки ділянок, ярлики тощо, крім міток рядків і стовпців.

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

введіть тут опис зображення


8
Методи is_first_col(), is_last_col(), is_first_row()а is_last_row()також можуть бути зручні в цьому контексті.
gerrit

1
Також як примітка, анотувати matplotlib дійсно має опцію обертання, тому, якщо ви хочете повернути свою мітку на 90 градусів, просто додайте аргументrotation = 90
mathishard.butweloveit

2

Наведена відповідь працює. Тільки не те, що у другій версії відповіді у вас є:

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

замість:

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')
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.