Câu hỏi Phổ biến xlabel / ylabel cho matplotlib subplots


Tôi có cốt truyện sau:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

và bây giờ tôi muốn cung cấp cho cốt truyện này các nhãn trục x chung và nhãn trục y. Với "phổ biến", tôi có nghĩa là phải có một nhãn x trục lớn bên dưới toàn bộ lưới của các ô con và một nhãn y trục lớn ở bên phải. Tôi không thể tìm thấy bất cứ điều gì về điều này trong tài liệu cho plt.subplots, và googlings của tôi cho thấy rằng tôi cần phải thực hiện một lớn plt.subplot(111) để bắt đầu - nhưng làm thế nào để tôi đặt 5 * 2 tiểu của tôi vào đó bằng cách sử dụng plt.subplots?


76
2018-04-22 15:25


gốc


Với bản cập nhật cho câu hỏi và các nhận xét còn lại trong các câu trả lời bên dưới, đây là bản sao của stackoverflow.com/questions/6963035/… - Hooked
Không thực sự, kể từ khi câu hỏi của tôi là cho plt.subplots (), và câu hỏi bạn liên kết để sử dụng add_subplot - Tôi không thể sử dụng phương pháp đó, trừ khi tôi chuyển sang add_subplot, mà tôi muốn tránh. tôi có thể sử dụng giải pháp plt.text được đưa ra như một giải pháp thay thế trong liên kết của bạn, nhưng nó không phải là giải pháp thanh lịch nhất. - jolindbe
Để xây dựng, theo như tôi hiểu, plt.subplots không thể tạo ra một tập hợp các subplots trong một môi trường trục hiện có, nhưng luôn luôn tạo ra một hình mới. Đúng? - jolindbe
Một giải pháp thanh lịch nhất có thể được tìm thấy ở đây: stackoverflow.com/questions/6963035/… - Mr.H
Liên kết của bạn đã được cung cấp bởi người dùng Được nối hơn 4 năm trước (chỉ một vài nhận xét phía trên của bạn). Như tôi đã nói trước đây, giải pháp đó liên quan đến add_subplot, và không phải là plt.subplots (). - jolindbe


Các câu trả lời:


Điều này trông giống như những gì bạn thực sự muốn. Nó áp dụng cùng một cách tiếp cận câu trả lời này cho trường hợp cụ thể của bạn:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6, 6))

fig.text(0.5, 0.04, 'common X', ha='center')
fig.text(0.04, 0.5, 'common Y', va='center', rotation='vertical')

Multiple plots with common axes label


122
2017-11-12 16:56



rực rỡ, chỉ rực rỡ !! - ThePredator
lưu ý rằng 0,5 cho tọa độ x của nhãn x không đặt nhãn ở trung tâm của subplot trung tâm. bạn cần phải lớn hơn một chút so với tài khoản yticklabels. - dbliss
Hãy xem câu trả lời này cho một phương pháp không sử dụng plt.text. Bạn tạo các subplots của bạn, nhưng sau đó thêm một ô bit, làm cho nó vô hình, và ghi nhãn x và y của nó. - kungfujam
Cảm ơn, làm việc nói chung. Bất kỳ giải pháp nào để vỡ khi sử dụng tight_layout? - serv-inc
@ serv-inc với tight_layout thay thế 0.04 với 0 dường như hoạt động. - divenex


Không có sharex=True, sharey=True bạn lấy:

enter image description here

Với nó, bạn sẽ nhận được nó đẹp hơn:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))

plt.tight_layout()

enter image description here

Nhưng nếu bạn muốn thêm nhãn bổ sung, bạn chỉ nên thêm chúng vào các ô cạnh:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.rand(32,32))
        if i == len(axes2d) - 1:
            cell.set_xlabel("noise column: {0:d}".format(j + 1))
        if j == 0:
            cell.set_ylabel("noise row: {0:d}".format(i + 1))

plt.tight_layout()

enter image description here

Thêm nhãn cho mỗi ô sẽ làm hỏng nó (có thể có cách để tự động phát hiện các nhãn lặp lại, nhưng tôi không biết một).


27
2018-05-13 18:21



Điều này khó hơn rất nhiều nếu, ví dụ, số lượng ô không xác định (ví dụ: bạn có chức năng tổng quát hóa âm mưu hoạt động đối với bất kỳ số lượng vùng con nào). - naught101


Kể từ khi lệnh:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

bạn đã sử dụng trả về một tuple bao gồm hình và danh sách các cá thể trục, nó đã đủ để làm một cái gì đó như (tâm trí mà tôi đã thay đổi fig,axđến fig,axes):

fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

for ax in axes:
    ax.set_xlabel('Common x-label')
    ax.set_ylabel('Common y-label')

Nếu bạn muốn thay đổi một số chi tiết trên một subplot cụ thể, bạn có thể truy cập nó thông qua axes[i] Ở đâu i lặp lại trên các trang con của bạn.

Nó cũng có thể rất hữu ích để bao gồm một

fig.tight_layout()

ở cuối tệp, trước plt.show(), để tránh các nhãn trùng lặp.


14
2018-04-22 17:49



Tôi xin lỗi tôi là một chút không rõ ràng ở trên. Với "phổ biến" tôi có nghĩa là một nhãn x duy nhất bên dưới tất cả các ô, và một nhãn y duy nhất ở bên trái của các ô, tôi đã cập nhật câu hỏi để phản ánh điều này. - jolindbe
@JohanLindberg: Liên quan đến nhận xét của bạn ở đây và ở trên: Thật vậy plt.subplots() sẽ tạo ra một cá thể hình mới. Nếu bạn muốn gắn bó với lệnh này, bạn có thể dễ dàng thêm big_ax = fig.add_subplot(111), vì bạn đã có một hình và có thể thêm một trục khác. Sau đó, bạn có thể thao tác big_ax cách nó được hiển thị trong liên kết từ Hooked. - Marius
Cảm ơn lời đề nghị của bạn, nhưng nếu tôi làm điều đó, tôi phải thêm big_ax sau plt.subplots (), và tôi nhận được subplot đó trên đầu mọi thứ khác - tôi có thể làm cho nó trong suốt hoặc gửi nó về phía sau bằng cách nào đó không? Ngay cả khi tôi đặt tất cả các màu sắc thành không như trong liên kết của Hooked, nó vẫn là một hộp màu trắng bao phủ tất cả các vùng con của tôi. - jolindbe
@ JohanLindberg, bạn nói đúng, tôi đã không kiểm tra điều đó. Nhưng bạn có thể dễ dàng thiết lập màu nền của trục lớn thành none bằng cách thực hiện: big_ax.set_axis_bgcolor('none') Bạn cũng nên làm cho labelcolor none (trái ngược với ví dụ được liên kết bằng Hooked): big_ax.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off') - Marius
Tôi gặp lỗi: AttributeError: 'numpy.ndarray' object has no attribute 'set_xlabel' trong tuyên bố ax.set_xlabel('Common x-label'). Bạn có thể hình dung về nó? - hengxin


Tôi đã gặp phải vấn đề tương tự trong khi vẽ đồ thị lưới. Các đồ thị bao gồm hai phần (trên và dưới). Nhãn y được cho là tập trung vào cả hai phần.

Tôi không muốn sử dụng một giải pháp phụ thuộc vào việc biết vị trí trong hình bên ngoài (như fig.text ()), vì vậy tôi đã thao tác vị trí y của hàm set_ylabel (). Nó thường là 0,5, giữa cốt truyện nó được thêm vào. Khi phần đệm giữa các phần (hspace) trong mã của tôi bằng không, tôi có thể tính toán phần giữa của hai phần tương ứng với phần trên.

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

# Create outer and inner grid
outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1])
somePlot = gridspec.GridSpecFromSubplotSpec(2, 1,
               subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0)

# Add two partial plots
partA = plt.subplot(somePlot[0])
partB = plt.subplot(somePlot[1])

# No x-ticks for the upper plot
plt.setp(partA.get_xticklabels(), visible=False)

# The center is (height(top)-height(bottom))/(2*height(top))
# Simplified to 0.5 - height(bottom)/(2*height(top))
mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0])
# Place the y-label
partA.set_ylabel('shared label', y = mid)

plt.show()

hình ảnh

Nhược điểm:

  • Khoảng cách ngang đến cốt truyện được dựa trên phần trên cùng, các dấu tích dưới cùng có thể mở rộng vào nhãn.

  • Công thức không chiếm không gian giữa các phần.

  • Ném một ngoại lệ khi chiều cao của phần trên cùng là 0.

Có lẽ là một giải pháp chung có tính đệm giữa các số liệu.


2
2017-07-27 16:35



Này, tôi đã tìm ra cách để làm điều này rất nhiều trong tĩnh mạch câu trả lời của bạn, nhưng có thể giải quyết một số vấn đề này; xem stackoverflow.com/a/44020303/4970632 (phía dưới) - Luke Davis


Tôi đã khám phá ra một phương pháp mạnh mẽ hơn:

Nếu bạn biết bottom và top kwargs đã đi vào một GridSpec khởi tạo, hoặc bạn biết các vị trí cạnh của các trục của bạn Figure tọa độ, bạn cũng có thể chỉ định vị trí ylabel trong Figure tọa độ với một số phép thuật "biến đổi" ưa thích. Ví dụ:

import matplotlib.transforms as mtransforms
bottom, top = .1, .9
f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top)
avepos = (bottom+top)/2
a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory(
       mtransforms.IdentityTransform(), f.transFigure # specify x, y transform
       )) # changed from default blend (IdentityTransform(), a[0].transAxes)
a[0].yaxis.label.set_position((0, avepos))
a[0].set_ylabel('Hello, world!')

... và bạn sẽ thấy rằng nhãn vẫn điều chỉnh thích hợp trái-phải để tránh trùng lặp với các dấu ticklabels, giống như bình thường - nhưng bây giờ nó sẽ điều chỉnh để luôn luôn chính xác giữa các subplots mong muốn.

Hơn nữa, nếu bạn thậm chí không sử dụng set_position, ylabel sẽ hiển thị theo mặc định chính xác nửa chừng hình. Tôi đoán điều này là bởi vì khi nhãn cuối cùng được rút ra, matplotlib sử dụng 0,5 cho y-coordinate mà không kiểm tra xem biến đổi tọa độ cơ bản đã thay đổi chưa.


1
2018-05-17 09:07





Nó sẽ trông đẹp hơn nếu bạn dành không gian cho các nhãn thông thường bằng cách tạo các nhãn vô hình cho subplot ở góc dưới cùng bên trái. Nó cũng tốt để vượt qua trong phông chữ từ rcParams. Bằng cách này, các nhãn thông thường sẽ thay đổi kích thước bằng thiết lập rc của bạn và các trục cũng sẽ được điều chỉnh để rời khỏi không gian cho các nhãn thông thường.

fig_size = [8, 6]
fig, ax = plt.subplots(5, 2, sharex=True, sharey=True, figsize=fig_size)
# Reserve space for axis labels
ax[-1, 0].set_xlabel('.', color=(0, 0, 0, 0))
ax[-1, 0].set_ylabel('.', color=(0, 0, 0, 0))
# Make common axis labels
fig.text(0.5, 0.04, 'common X', va='center', ha='center', fontsize=rcParams['axes.labelsize'])
fig.text(0.04, 0.5, 'common Y', va='center', ha='center', rotation='vertical', fontsize=rcParams['axes.labelsize'])

enter image description here enter image description here


0
2018-05-30 17:57