2011-08-05 34 views
102

Tôi có cốt truyện như sau:pyplot trục nhãn cho subplots

import matplotlib.pyplot as plt 

fig2 = plt.figure() 
ax3 = fig2.add_subplot(2,1,1) 
ax4 = fig2.add_subplot(2,1,2) 
ax4.loglog(x1, y1) 
ax3.loglog(x2, y2) 
ax3.set_ylabel('hello') 

Tôi muốn để có thể tạo nên những trục nhãn và tiêu đề không chỉ dành riêng cho mỗi người trong số hai ô phụ, mà còn nhãn phổ biến mà span cả ô phụ. Ví dụ, vì cả hai ô đều có các trục giống hệt nhau, tôi chỉ cần một bộ nhãn x và y. Tuy nhiên, tôi muốn các tiêu đề khác nhau cho mỗi tiểu nhóm.

Tôi đã thử một vài điều nhưng không ai trong số họ làm việc đúng

Trả lời

150

Bạn có thể tạo ra một âm mưu phụ lớn bao gồm hai ô phụ và sau đó thiết lập các nhãn phổ biến.

import random 
import matplotlib.pyplot as plt 

x = range(1, 101) 
y1 = [random.randint(1, 100) for _ in xrange(len(x))] 
y2 = [random.randint(1, 100) for _ in xrange(len(x))] 

fig = plt.figure() 
ax = fig.add_subplot(111) # The big subplot 
ax1 = fig.add_subplot(211) 
ax2 = fig.add_subplot(212) 

# Turn off axis lines and ticks of the big subplot 
ax.spines['top'].set_color('none') 
ax.spines['bottom'].set_color('none') 
ax.spines['left'].set_color('none') 
ax.spines['right'].set_color('none') 
ax.tick_params(labelcolor='w', top='off', bottom='off', left='off', right='off') 

ax1.loglog(x, y1) 
ax2.loglog(x, y2) 

# Set common labels 
ax.set_xlabel('common xlabel') 
ax.set_ylabel('common ylabel') 

ax1.set_title('ax1 title') 
ax2.set_title('ax2 title') 

plt.savefig('common_labels.png', dpi=300) 

common_labels.png

Một cách khác là sử dụng fig.text() để thiết lập vị trí của các nhãn phổ biến trực tiếp.

import random 
import matplotlib.pyplot as plt 

x = range(1, 101) 
y1 = [random.randint(1, 100) for _ in xrange(len(x))] 
y2 = [random.randint(1, 100) for _ in xrange(len(x))] 

fig = plt.figure() 
ax1 = fig.add_subplot(211) 
ax2 = fig.add_subplot(212) 

ax1.loglog(x, y1) 
ax2.loglog(x, y2) 

# Set common labels 
fig.text(0.5, 0.04, 'common xlabel', ha='center', va='center') 
fig.text(0.06, 0.5, 'common ylabel', ha='center', va='center', rotation='vertical') 

ax1.set_title('ax1 title') 
ax2.set_title('ax2 title') 

plt.savefig('common_labels_text.png', dpi=300) 

common_labels_text.png

+1

Chức năng suptitle sử dụng phiên bản fig.text(). Vì vậy, đây có thể là cách "chính thức" để làm điều đó? – PhML

+2

Cần nhấn mạnh rằng 'ax' phải được tạo trước' ax1' và 'ax2', nếu không ô lớn sẽ che phủ các ô nhỏ. –

+0

ax.grid (False) hoặc plt.grid (False) cũng cần thiết nếu các thông số âm mưu toàn cục bao gồm lưới (có thể nhìn thấy). –

10

Wen-wei câu trả lời Liao là tốt nếu bạn không cố gắng để xuất khẩu đồ họa vector hoặc rằng bạn đã thiết lập backends matplotlib bạn bỏ qua các trục không màu; nếu không các trục ẩn sẽ hiển thị trong đồ họa đã xuất.

Câu trả lời của tôi suplabel ở đây tương tự như fig.suptitle sử dụng chức năng fig.text. Do đó không có nghệ sĩ rìu nào được tạo ra và tạo ra không màu. Tuy nhiên, nếu bạn cố gắng gọi nó nhiều lần, bạn sẽ nhận được văn bản được thêm vào đầu trang của nhau (như fig.suptitle cũng vậy). Câu trả lời của Wen-wei Liao không, bởi vì fig.add_subplot(111) sẽ trả về cùng một đối tượng Trục nếu nó đã được tạo.

Chức năng của tôi cũng có thể được gọi sau khi các ô đã được tạo.

def suplabel(axis,label,label_prop=None, 
      labelpad=5, 
      ha='center',va='center'): 
    ''' Add super ylabel or xlabel to the figure 
    Similar to matplotlib.suptitle 
    axis  - string: "x" or "y" 
    label  - string 
    label_prop - keyword dictionary for Text 
    labelpad - padding from the axis (default: 5) 
    ha   - horizontal alignment (default: "center") 
    va   - vertical alignment (default: "center") 
    ''' 
    fig = pylab.gcf() 
    xmin = [] 
    ymin = [] 
    for ax in fig.axes: 
     xmin.append(ax.get_position().xmin) 
     ymin.append(ax.get_position().ymin) 
    xmin,ymin = min(xmin),min(ymin) 
    dpi = fig.dpi 
    if axis.lower() == "y": 
     rotation=90. 
     x = xmin-float(labelpad)/dpi 
     y = 0.5 
    elif axis.lower() == 'x': 
     rotation = 0. 
     x = 0.5 
     y = ymin - float(labelpad)/dpi 
    else: 
     raise Exception("Unexpected axis: x or y") 
    if label_prop is None: 
     label_prop = dict() 
    pylab.text(x,y,label,rotation=rotation, 
       transform=fig.transFigure, 
       ha=ha,va=va, 
       **label_prop) 
52

Một cách đơn giản sử dụng subplots:

import matplotlib.pyplot as plt 

fig, axes = plt.subplots(3, 4, sharex=True, sharey=True) 
# add a big axes, hide frame 
fig.add_subplot(111, frameon=False) 
# hide tick and tick label of the big axes 
plt.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off') 
plt.grid(False) 
plt.xlabel("common X") 
plt.ylabel("common Y") 
+0

hoàn toàn ngắn! – maggie

+1

Đây phải là câu trả lời được chấp nhận – kungfujam

+0

Tôi đồng ý rằng đây là câu trả lời tuyệt vời –

7

Đây là một giải pháp mà bạn thiết lập ylabel của một trong những âm mưu và điều chỉnh vị trí của nó để nó tập trung theo chiều dọc. Bằng cách này bạn tránh các vấn đề được đề cập bởi KYC.

import numpy as np 
import matplotlib.pyplot as plt 

def set_shared_ylabel(a, ylabel, labelpad = 0.01): 
    """Set a y label shared by multiple axes 
    Parameters 
    ---------- 
    a: list of axes 
    ylabel: string 
    labelpad: float 
     Sets the padding between ticklabels and axis label""" 

    f = a[0].get_figure() 
    f.canvas.draw() #sets f.canvas.renderer needed below 

    # get the center position for all plots 
    top = a[0].get_position().y1 
    bottom = a[-1].get_position().y0 

    # get the coordinates of the left side of the tick labels 
    x0 = 1 
    for at in a: 
     at.set_ylabel('') # just to make sure we don't and up with multiple labels 
     bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer) 
     bboxes = bboxes.inverse_transformed(f.transFigure) 
     xt = bboxes.x0 
     if xt < x0: 
      x0 = xt 
    tick_label_left = x0 

    # set position of label 
    a[-1].set_ylabel(ylabel) 
    a[-1].yaxis.set_label_coords(tick_label_left - labelpad,(bottom + top)/2, transform=f.transFigure) 

length = 100 
x = np.linspace(0,100, length) 
y1 = np.random.random(length) * 1000 
y2 = np.random.random(length) 

f,a = plt.subplots(2, sharex=True, gridspec_kw={'hspace':0}) 
a[0].plot(x, y1) 
a[1].plot(x, y2) 
set_shared_ylabel(a, 'shared y label (a. u.)') 

enter image description here

Các vấn đề liên quan