2011-08-05 61 views
102

标签,我有以下情节:pyplot轴的次要情节

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

我希望能够为每两个次要情节的不仅仅是创建轴标签和标题,而且还跨越两个次要情节共同的标签。例如,由于两个图都具有相同的轴,因此我只需要一组x轴和y轴标签。尽管如此,我还是希望为每个子区域创建不同的标题。

我尝试了一些事情,但他们没有工作权

回答

150

您可以创建一个大插曲覆盖两个次要情节,然后设置共同的标签。

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

的另一种方法是使用fig.text()直接设置共同的标签的位置。

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

的suptitle功能使用fig.text()的版本。所以这可能是“官方”的方式呢? – PhML

+2

值得强调的是'ax'必须在'ax1'和'ax2'之前创建,否则大图会掩盖小图。 –

+0

如果全局绘图参数包含(可见)网格,则也需要ax.grid(False)或plt.grid(False)。 –

10

文卫廖的回答是好,如果你不尝试导出矢量图形,或者你已经设置了matplotlib后端忽视无色轴;否则隐藏的轴将出现在导出的图形中。

我的回答suplabel这里类似于使用fig.text功能的fig.suptitle。因此没有斧头艺术家被创造并且变得无色。 但是,如果您尝试多次拨打电话,则会将文本添加到对方的顶部(因为fig.suptitle也会这样做)。廖文伟的答案不是,因为fig.add_subplot(111)将返回相同的轴对象,如果它已经创建。

我的函数也可以在绘图创建后调用。使用subplots

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

一个简单的方法:

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

完美的短! – maggie

+1

这应该是公认的答案 – kungfujam

+0

我同意这是一个很好的答案 –

7

这里是你设置的曲线中的一个的ylabel,所以它垂直居中调节它的位置的解决方案。这样你可以避免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