Matplotlib의 하위 그림에서 행 및 열 머리글
루프에서 생성된 하위 플롯의 그리드에 행과 열 헤더를 추가하는 가장 좋은 방법은 무엇입니까?matplotlib
? 두 사람을 생각할 수는 있지만, 특별히 단정하지는 않습니다.
- 열의 경우 루프에 대한 카운터를 사용하여
set_title()
맨 앞줄만행의 경우에는 작동하지 않습니다.당신은 그림을 그려야 할 것입니다.text
줄거리 밖에서 - 위에 부분구 행을 추가하고 왼쪽에 부분구 열을 추가한 다음 해당 부분구 중간에 텍스트를 그립니다.
더 좋은 대안을 제시해 주실 수 있습니까?
이렇게 하는 방법에는 여러 가지가 있습니다.쉬운 방법은 그림의 y 레이블과 제목을 이용한 다음 사용하는 것입니다.fig.tight_layout()
라벨을 넣을 공간을 만들기 위해.또는 추가 텍스트를 올바른 위치에 배치한 다음 반수동으로 공간을 만들 수 있습니다.
축에 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
라벨을 붙일 수 있습니다.이것은 더 복잡하지만 행 및 열 레이블 외에도 개별 플롯 제목, ylabel 등을 가질 수 있습니다.
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()
Joe Kington의 답변을 바탕으로 코드 베이스 전체에서 재사용할 수 있는 함수를 올렸습니다.
인수는 다음과 같습니다.
fig
: 작업할 축을 포함하는 그림row_headers
,col_headers
: 머리말로 쓸 일련의 문자열row_pad
,col_pad
:int
패딩을 조정할 값rotate_row_headers
: 행 헤더를 90° 회전할지 여부**text_kwargs
: 에 전달된ax.annotate(...)
기능: 아래 예:
import numpy as np
def add_headers(
fig,
*,
row_headers=None,
col_headers=None,
row_pad=1,
col_pad=5,
rotate_row_headers=True,
**text_kwargs
):
# Based on https://stackoverflow.com/a/25814386
axes = fig.get_axes()
for ax in axes:
sbs = ax.get_subplotspec()
# Putting headers on cols
if (col_headers is not None) and sbs.is_first_row():
ax.annotate(
col_headers[sbs.colspan.start],
xy=(0.5, 1),
xytext=(0, col_pad),
xycoords="axes fraction",
textcoords="offset points",
ha="center",
va="baseline",
**text_kwargs,
)
# Putting headers on rows
if (row_headers is not None) and sbs.is_first_col():
ax.annotate(
row_headers[sbs.rowspan.start],
xy=(0, 0.5),
xytext=(-ax.yaxis.labelpad - row_pad, 0),
xycoords=ax.yaxis.label,
textcoords="offset points",
ha="right",
va="center",
rotation=rotate_row_headers * 90,
**text_kwargs,
)
다음은 표준 그리드(축이 여러 행/콜에 걸쳐 있지 않음)에서 사용하는 예입니다.
import random
import matplotlib.pyplot as plt
mosaic = [
["A0", "A1", "A2"],
["B0", "B1", "B2"],
]
row_headers = ["Row A", "Row B"]
col_headers = ["Col 0", "Col 1", "Col 2"]
subplots_kwargs = dict(sharex=True, sharey=True, figsize=(10, 6))
fig, axes = plt.subplot_mosaic(mosaic, **subplots_kwargs)
font_kwargs = dict(fontfamily="monospace", fontweight="bold", fontsize="large")
add_headers(fig, col_headers=col_headers, row_headers=row_headers, **font_kwargs)
plt.show()
일부 축이 여러 행/콜에 걸쳐 있는 경우 행/콜 헤더를 올바르게 할당하는 것이 약간 간단해집니다.기능 내부에서 잘 정리하지는 못했지만, 기본적으로 주의해야 합니다.row_headers
그리고.col_headers
인수를 사용하면 쉽게 작동할 수 있습니다.
mosaic = [
["A0", "A1", "A1", "A2"],
["A0", "A1", "A1", "A2"],
["B0", "B1", "B1", "B2"],
]
row_headers = ["A", "A", "B"] # or
row_headers = ["A", None, "B"] # or
row_headers = {0: "A", 2: "B"}
col_headers = ["0", "1", "1", "2"] # or
col_headers = ["0", "1", None, "2"] # or
col_headers = {0: "0", 1: "1", 3: "2"}
fig, axes = plt.subplot_mosaic(mosaic, **subplots_kwargs)
add_headers(fig, col_headers=col_headers, row_headers=row_headers, **font_kwargs)
plt.show()
위의 답변이 효과가 있습니다.답변의 두 번째 버전에서는 다음과 같은 내용이 있습니다.
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')
Joe의 답변의 연장선상에서 Y-label 접근법을 사용할 수 있습니다. 기존 Y-label을 사용하는 것보다 훨씬 쉽다고 생각합니다.annotate
, 특히 축이 일반 그리드에 있지 않을 경우.
이를 위해 축을 쌍으로 연결하여 왼쪽으로 이동할 수 있습니다.
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=3, ncols=3,
sharex=True, sharey=True)
cols = [1, 2, 3]
rows = ['A', 'B', 'C']
# set existing Y label
axes[0][0].set_ylabel('Y label')
for c, ax in zip(cols, axes[0]):
ax.set_title(c, size='large')
for r, ax in zip(rows, axes[:, 0]):
ax2 = ax.twinx()
# move extra axis to the left, with offset
ax2.yaxis.set_label_position('left')
ax2.spines['left'].set_position(('axes', -0.4))
# hide spine and ticks, set group label
ax2.spines['left'].set_visible(False)
ax2.set_yticks([])
ax2.set_ylabel(r, rotation=0, size='large',
ha='right', va='center')
또는 기존 타이틀도 가지고 있다면 X축과 동일한 작업을 수행하여 상단에 레이블을 추가할 수도 있습니다.
출력:
비정규 그리드의 출력:
언급URL : https://stackoverflow.com/questions/25812255/row-and-column-headers-in-matplotlibs-subplots
'programing' 카테고리의 다른 글
(ExpressJS 사용) AJAX Call 후 EJS 템플릿에서 배열을 루프하는 적절한 방법은 무엇입니까? (0) | 2023.10.24 |
---|---|
도커 컨테이너가 과도하게 작동하지 않는 것에 대해 우려해야 합니까? (0) | 2023.10.24 |
Oracle AQ SYS의 내용을 표시합니다.AQ$_JMS_TEXT_MESSAGE (0) | 2023.10.24 |
JSON 경로-값 쌍에서 보는 MariaDB 레코드를 반환하려면 어떻게 해야 합니까? (0) | 2023.10.24 |
MySQL SERVER 8.0에서 Password 기능이 작동하지 않음 (0) | 2023.10.24 |