Tiêu đề hàng và cột trong các ô con của matplotlib


82

Cách tốt nhất để thêm một hàng và một tiêu đề cột vào một lưới các ô con được tạo trong một vòng lặp trong là matplotlibgì? Tôi có thể nghĩ về một vài, nhưng không đặc biệt gọn gàng:

  1. Đối với các cột, với bộ đếm vòng lặp, bạn chỉ có thể sử dụng set_title()cho hàng đầu tiên. Đối với các hàng, điều này không hoạt động. Bạn sẽ phải vẽ textbên ngoài các âm mưu.
  2. Bạn thêm một hàng ô phụ ở trên cùng và một cột ô phụ ở bên trái, và vẽ văn bản ở giữa ô phụ đó.

Bạn có thể đề xuất một giải pháp thay thế tốt hơn không?

nhập mô tả hình ảnh ở đây

Câu trả lời:


109

Có nhiều hướng khác nhau để làm điều đó. Cách dễ dàng là khai thác các nhãn y và tiêu đề của cốt truyện và sau đó sử dụng fig.tight_layout()để nhường chỗ cho các nhãn. Ngoài ra, bạn có thể đặt văn bản bổ sung vào đúng vị trí annotatevà sau đó nhường chỗ cho văn bản đó một cách bán thủ công.


Nếu bạn không có nhãn y trên các trục của mình, bạn có thể dễ dàng khai thác tiêu đề và nhãn y của hàng và cột đầu tiên của trục.

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

nhập mô tả hình ảnh ở đây


Nếu bạn có nhãn y hoặc nếu bạn muốn linh hoạt hơn một chút, bạn có thể sử dụng annotateđể đặt nhãn. Điều này phức tạp hơn, nhưng cho phép bạn có các tiêu đề, nhãn ylabels, v.v. riêng lẻ ngoài các nhãn hàng và cột.

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

nhập mô tả hình ảnh ở đây


8
Các phương pháp is_first_col(), is_last_col(), is_first_row()is_last_row()cũng có thể thuận tiện trong bối cảnh này.
gerrit

1
Cũng như một lưu ý, chú thích matplotlib không có tùy chọn xoay, vì vậy nếu bạn muốn xoay nhãn của mình 90 độ, chỉ cần thêm đối sốrotation = 90
mathishard.butweloveit

2

Câu trả lời trên hoạt động. Không phải vậy, trong phiên bản thứ hai của câu trả lời, bạn có:

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

thay vì:

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')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.