【问题标题】:Matplotlib: fixed spacing between left edge of figure and y-axisMatplotlib:图形左边缘和y轴之间的固定间距
【发布时间】:2015-11-02 21:04:34
【问题描述】:

我在 Matplotlib 中使用 Python 2.7 制作了 2 个图。绘图保存为 *.png 文件。保存后,两张图片的分辨率相同 - 宽度 = 1099 像素,高度 = 619 像素。

但是,当我垂直对齐保存的 *.png 图像时(附在下面),y 轴和图像最左边的点之间的间距不一样 - 请参阅 a和下图中的b

我的意思是,图像左侧到y轴的距离不一样(a不等于b)。

点击图片放大查看。

问题: 有没有办法强制 y 轴从相对于图像左侧的特定位置开始?

注意: 我不关心刻度标签和轴标签之间的空间 - 我可以使用 ax.yaxis.labelpad(25) 之类的东西来调整它。但是,我不知道如何修复图像左侧和 y 轴之间的空间。

注意 2: 我使用以下方法创建我的情节:

fig = plt.figure(1)
ax = fig.add_subplot(111)
fig.tight_layout()

【问题讨论】:

  • 这正是tight_layout() 应该调整的。在内部,Figure 中的艺术家被放置/调整大小为 [0, 1] 单位空间。在渲染时,该空间被转换为屏幕/像素空间。您看到的是tight_layout功能,而不是错误。如果你不想要这个不要使用tight_layout.
  • 相关:更改axis and its corresponding label之间的距离
  • @tacaswell 你的评论对我很有帮助。谢谢!

标签: python python-2.7 matplotlib plot


【解决方案1】:

如果我想很好地控制 matplotlib 中图形边距的大小,我通常会这样设置代码。此外,我还展示了如何设置 ylabel 的位置,以便您可以轻松地将两个图形的 ylabels 对齐。

import matplotlib.pyplot as plt

plt.close('all')

#---- create figure ----

fwidth = 8.  # total width of the figure in inches
fheight = 4. # total height of the figure in inches

fig = plt.figure(figsize=(fwidth, fheight))

#---- define margins -> size in inches / figure dimension ----

left_margin  = 0.95 / fwidth
right_margin = 0.2 / fwidth
bottom_margin = 0.5 / fheight
top_margin = 0.25 / fheight

#---- create axes ----

# dimensions are calculated relative to the figure size

x = left_margin    # horiz. position of bottom-left corner
y = bottom_margin  # vert. position of bottom-left corner
w = 1 - (left_margin + right_margin) # width of axes
h = 1 - (bottom_margin + top_margin) # height of axes

ax = fig.add_axes([x, y, w, h])

#---- Define the Ylabel position ----

# Location are defined in dimension relative to the figure size  

xloc =  0.25 / fwidth 
yloc =  y + h / 2.  

ax.set_ylabel('yLabel', fontsize=16, verticalalignment='top',
              horizontalalignment='center')             
ax.yaxis.set_label_coords(xloc, yloc, transform = fig.transFigure)

plt.show(block=False)
fig.savefig('figure_margins.png')

这会产生一个 8 英寸 x 4 英寸的图形,在图形的左侧、右侧、底部和顶部的边距正好为 0.95、0.2、0.5 和 0.25 英寸。这种方法的一个好处是边距的大小以绝对单位(英寸)定义,这意味着即使您更改图形的大小,它们也将保持一致。

对于ylabel,在水平方向上,标签的顶部位于离图形左边缘0.25英寸处,而在垂直方向上,标签的中心对应于斧头的中心。请注意,由于 ylabel 旋转了 90 度,verticalalignmenthorizontalalignment 的含义实际上是相反的。

下面显示了上述代码的输出,其中 y 轴范围分别设置为 [0, 1] 和 [0, 18]。

【讨论】:

  • 非常感谢。您的代码w = 1 - (left_margin + right_margin) 是我所缺少的基本理解。设置ax.set_ylim([0,18.0])的时候也可以显示图来对比吗?
  • @WR 很高兴它有帮助。第二个情节的好主意,我已经添加了。
  • 你能否解释一下你的第三行最后一行 - 这个ax.yaxis.set_label_coords(xloc, yloc, transform = fig.transFigure)
  • @WR 默认情况下,"set_label_coords" 采用 (x, y) 相对于轴大小的维度。在您的情况下,我认为如果它是在相对于图形大小的维度上定义的,那将是一个更好的设计。这就是我添加fig.transFigure 的原因。这允许使用与其余代码一致的方法设置标签位置。此外,即使您更改图形的大小,位置也应该保持良好。
  • @WR 在这种情况下,如果您的 4 个子图具有相同的水平尺寸,我将在相对于轴的坐标中手动定义 y 轴位置,如下所示:stackoverflow.com/questions/19277324/…。它需要手动调整 x 位置。使用get_ticklabel_extents 方法可以实现更自动化的方法。
【解决方案2】:

我认为您可以在创建轴(将_axes 添加到图形对象)时设置此属性(图形边缘和轴之间的空间)。下面是一些简单的示例代码,它可以生成两个轴,在所有边上都有很大的间距:

import matplotlib.pyplot as plt

f1 = plt.figure()
ax1 = f1.add_axes([0.2, 0.2, 0.6, 0.6]) # List is [left, bottom, width, height]
ax1.axis([0, 1, 0, 1])
plt.savefig('ax1.png')

f2 = plt.figure()
ax2 = f2.add_axes([0.2, 0.2, 0.6, 0.6])
ax2.axis([0, 1000, 0, 1000])
plt.savefig('ax2.png')

你可以在这里找到更多信息:
http://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure.add_axes

编辑: 您可以使用 subplots_adjust 获得类似的结果。使用您的示例代码:

fig = plt.figure(1)
ax = fig.add_subplot(111)
fig.tight_layout()
plt.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8)

【讨论】:

  • 我正在使用fig = plt.figure(1)ax = fig.add_subplot(111) 添加一个子情节。有没有办法让我在其中构建.add_axes()
  • 查看我在原始帖子中的编辑,了解我如何创建情节的详细信息。让我知道你的想法。
  • @WR 您是否有理由不能或不想按照 jwinterm 的建议将 ax = fig.add_subplot(111) 替换为 ax = fig.add_axes([x, y, w, h])?似乎是控制边距大小的合理解决方案。
  • @jwinterm:你能解释一下这个[0.2, 0.1, 1, 1] 会给出什么吗?据我了解,y 轴将从图左边缘向右 20% 开始,x 轴将从图底边缘向上 10% 开始。这是正确的解释吗?另外,我不确定文档中最后 2 个值的含义 - 它们只是上下缩放宽度和高度吗?
  • 您对第一部分的解释是正确的,[0.2, 0.1... 确实意味着它将从左侧开始 20%,从底部开始 10%,但是 ...1, 1] 会使轴的宽度和高度为图形的 100%,有效地使轴的一部分脱离图形的边缘。因此, [0.0, 0.0, 1.0, 1.0] 将在图形上创建一个从左下角开始并占据整个事物的轴,并且 [0.15, 0.15, 0.8, 0.8] 可能是更典型的默认行为(其中轴标签等有空间。