pyplot axes labels for subplots

匿名 (未验证) 提交于 2019-12-03 08:48:34

问题:

I have the following plot:

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

I want to be able to create axes labels and titles not just for each of the two subplots, but also common labels that span both subplots. For example, since both plots have identical axes, I only need one set of x and y- axes labels. I do want different titles for each subplot though.

I tried a few things but none of them worked right

回答1:

You can create a big subplot that covers the two subplots and then set the common labels.

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) 

Another way is using fig.text() to set the locations of the common labels directly.

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) 



回答2:

One simple way using 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") 


回答3:

Wen-wei Liao's answer is good if you are not trying to export vector graphics or that you have set up your matplotlib backends to ignore colorless axes; otherwise the hidden axes would show up in the exported graphic.

My answer suplabel here is similar to the fig.suptitle which uses the fig.text function. Therefore there is no axes artist being created and made colorless. However, if you try to call it multiple times you will get text added on top of each other (as fig.suptitle does too). Wen-wei Liao's answer doesn't, because fig.add_subplot(111) will return the same Axes object if it is already created.

My function can also be called after the plots have been created.

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) 


回答4:

Here is a solution where you set the ylabel of one of the plots and adjust the position of it so it is centered vertically. This way you avoid problems mentioned by 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 



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!