Matplotlib subplots_adjust hspace以避免标题和x轴标签重叠?

73 投票
2 回答
168950 浏览
提问于 2025-04-15 20:15

在使用matplotlib绘制3行子图的时候,某一行的横坐标标签可能会和下一行的标题重叠。这时候就需要调整一下pl.subplots_adjust(hspace),这真的很麻烦。

有没有什么方法可以设置hspace,让它避免重叠,并且适用于任意行数呢?

""" matplotlib xlabels overlap titles ? """
import sys
import numpy as np
import pylab as pl

nrow = 3
hspace = .4  # of plot height, titles and xlabels both fall within this ??
exec "\n".join( sys.argv[1:] )  # nrow= ...

y = np.arange(10)
pl.subplots_adjust( hspace=hspace )

for jrow in range( 1, nrow+1 ):
    pl.subplot( nrow, 1, jrow )
    pl.plot( y**jrow )
    pl.title( 5 * ("title %d " % jrow) )
    pl.xlabel( 5 * ("xlabel %d " % jrow) )

pl.show()

我的版本信息:

  • matplotlib 0.99.1.1,
  • Python 2.6.4,
  • Mac OSX 10.4.11,
  • 后端:Qt4AggTkAgg会在Tkinter回调中出错)

(如果能多给点分数的话,有人能简单介绍一下matplotlib的打包器/间隔器是怎么工作的吗?可以参考Tcl/Tk书中的第17章“打包器”)

2 个回答

46

Jose发的链接已经更新,现在pylab里有一个叫做tight_layout()的功能,可以自动处理这个问题(在matplotlib 1.1.0版本中)。

http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.tight_layout

http://matplotlib.org/users/tight_layout_guide.html#plotting-guide-tight-layout

31

我觉得这个问题有点棘手,但在MatPlotLib的常见问题解答上有一些信息可以参考。这个过程比较麻烦,需要了解每个元素(比如刻度标签)占用的空间...

更新: 页面上提到,使用tight_layout()这个函数是最简单的方法,它会自动调整间距。

如果不使用这个函数,页面还提供了一些方法来获取各种元素(例如标签)的大小,这样你就可以手动调整坐标轴元素的间距和位置。下面是来自上述常见问题解答的一个例子,它计算了一个非常宽的y轴标签的宽度,并相应地调整了坐标轴的宽度:

import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(10))
ax.set_yticks((2,5,7))
labels = ax.set_yticklabels(('really, really, really', 'long', 'labels'))

def on_draw(event):
   bboxes = []
   for label in labels:
       bbox = label.get_window_extent()
       # the figure transform goes from relative coords->pixels and we
       # want the inverse of that
       bboxi = bbox.inverse_transformed(fig.transFigure)
       bboxes.append(bboxi)

   # this is the bbox that bounds all the bboxes, again in relative
   # figure coords
   bbox = mtransforms.Bbox.union(bboxes)
   if fig.subplotpars.left < bbox.width:
       # we need to move it over
       fig.subplots_adjust(left=1.1*bbox.width) # pad a little
       fig.canvas.draw()
   return False

fig.canvas.mpl_connect('draw_event', on_draw)

plt.show()

撰写回答