轴类 - 在给定的单位中明确设置轴的大小(宽度/高度)

38

我希望使用matplotlib创建一个图形,可以明确指定轴的大小,即我想设置轴的宽度和高度。

我已经搜索了很多地方,但找不到解决方法。通常我找到的是如何调整整个图形的大小(包括刻度和标签),例如使用fig, ax = plt.subplots(figsize=(w, h))

这对我非常重要,因为我想要轴的1:1比例,即纸上的1个单位等于现实中的1个单位。例如,如果x范围为0到10,主要刻度= 1,x轴为10cm,则1个主要刻度= 1cm。我将保存此图形作为pdf以导入到latex文档中。

这个问题提出了一个类似的话题,但答案不能解决我的问题(使用plt.gca().set_aspect('equal', adjustable='box')代码)

从这个其他的问题中,我看到可能可以获取轴的大小,但无法显式修改它们。

有什么想法可以设置轴箱的大小而不仅仅是图形大小。图形大小应适应轴的大小。

谢谢!

对于熟悉LaTeX中pgfplots的人来说,它将类似于scale only axis选项(例如,请参见这里)。

4个回答

41
图轴的大小由图形大小和图形间距决定,可以使用figure.subplots_adjust()进行设置。反过来说,这意味着您可以通过设置图形大小并考虑图形间距来设置图轴的大小。
import matplotlib.pyplot as plt

def set_size(w,h, ax=None):
    """ w, h: width, height in inches """
    if not ax: ax=plt.gca()
    l = ax.figure.subplotpars.left
    r = ax.figure.subplotpars.right
    t = ax.figure.subplotpars.top
    b = ax.figure.subplotpars.bottom
    figw = float(w)/(r-l)
    figh = float(h)/(t-b)
    ax.figure.set_size_inches(figw, figh)
          
fig, ax=plt.subplots()

ax.plot([1,3,2])

set_size(5,5)

plt.show()

非常感谢 @ImportanceOfBeingErnest 的帮助!!!这似乎在生成的 PDF 中非常有效(就像魔术一样!)。一个重要的注意事项是,set_size 应该在保存图形之前执行,以便考虑标签和刻度中的所有更改。但是我注意到两个问题:(1)如果图形的大小太小,则标签会被裁剪,(2)当我打印 PDF 时,大小与实际比例不符。为什么会这样?请注意,我使用 \includegraphics 将 PDF 作为图形调用到 latex 文档中,然后打印生成的 PDF。 - Gabriel
我使用PDF测量工具来检查LaTeX PDF的大小,它是正确的,但在激光打印机上打印后并不准确。 - Gabriel
我明白了。但是由于LaTeX PDF具有正确的大小,我认为我们无法在StackOverflow上提供打印问题的支持。请检查您的打印机设置,在其他页面上寻找类似的问题,可能在superuser.stackexchange上或者在那里提问。 - ImportanceOfBeingErnest
你好@ImportanceOfBeingErnest,我发现当在图中使用colorbar时,该函数无法正常工作。你怎么处理colorbar呢? - Gabriel
2
你可以使用add_axes为色条添加一个轴,并使用subplots_adjust为其留出一些空间。 - ImportanceOfBeingErnest
显示剩余2条评论

7

4
我发现在使用matplotlib生成出版准备图时,将该图形大小调整以调整轴大小的ImportanceofBeingErnests答案提供的结果不一致。最终图形大小存在轻微错误,并且我无法找到解决他的方法。对于大多数用例,我认为这不是问题,但当结合多个pdf进行出版时,这些错误就会变得明显。

为了避免开发最小工作示例以查找图形调整方法的真正问题,我找到了一个解决方法,即使用固定轴大小并利用divider类。

from mpl_toolkits.axes_grid1 import Divider, Size
def fix_axes_size_incm(axew, axeh):
    axew = axew/2.54
    axeh = axeh/2.54

    #lets use the tight layout function to get a good padding size for our axes labels.
    fig = plt.gcf()
    ax = plt.gca()
    fig.tight_layout()
    #obtain the current ratio values for padding and fix size
    oldw, oldh = fig.get_size_inches()
    l = ax.figure.subplotpars.left
    r = ax.figure.subplotpars.right
    t = ax.figure.subplotpars.top
    b = ax.figure.subplotpars.bottom

    #work out what the new  ratio values for padding are, and the new fig size.
    neww = axew+oldw*(1-r+l)
    newh = axeh+oldh*(1-t+b)
    newr = r*oldw/neww
    newl = l*oldw/neww
    newt = t*oldh/newh
    newb = b*oldh/newh

    #right(top) padding, fixed axes size, left(bottom) pading
    hori = [Size.Scaled(newr), Size.Fixed(axew), Size.Scaled(newl)]
    vert = [Size.Scaled(newt), Size.Fixed(axeh), Size.Scaled(newb)]

    divider = Divider(fig, (0.0, 0.0, 1., 1.), hori, vert, aspect=False)
    # the width and height of the rectangle is ignored.

    ax.set_axes_locator(divider.new_locator(nx=1, ny=1))

    #we need to resize the figure now, as we have may have made our axes bigger than in.
    fig.set_size_inches(neww,newh)

需要注意的事项:

  • 一旦在轴实例上调用set_axes_locator()函数,将会破坏tight_layout()函数。
  • 您选择的原始图形大小将无关紧要,最终图形大小由您选择的轴大小以及标签/刻度标签/外向刻度的大小决定。
  • 此方法不适用于颜色比例尺。
  • 这是我第一次发布stackoverflow帖子。

2
我的答案不会给出不准确的结果。但是你当然可以用一个例子来证明你的说法。 - ImportanceOfBeingErnest
2
好的,经过进一步测试,我发现使用基本的rcParams,你的代码可以生成准确的PDF文件(交互式图至少有1x1英寸的错误)。我怀疑我不会再花时间去找出哪个特定的参数导致了这些问题,因为我已经有一个适用于我的用例的解决方案,但如果我要猜测的话,那就是'text.usetex = True'。我编辑了我的答案以反映这一点。 - BongaCodeBuddy

3

使用fig.add_axes方法的另一种方法也相当精确。 我还包括了1厘米的网格。

import matplotlib.pyplot as plt
import matplotlib as mpl

# This example fits a4 paper with 5mm margin printers

# figure settings
figure_width = 28.7 # cm
figure_height = 20 # cm
left_right_magrin = 1 # cm
top_bottom_margin = 1 # cm

# Don't change
left   = left_right_magrin / figure_width # Percentage from height
bottom = top_bottom_margin / figure_height # Percentage from height
width  = 1 - left*2
height = 1 - bottom*2
cm2inch = 1/2.54 # inch per cm

# specifying the width and the height of the box in inches
fig = plt.figure(figsize=(figure_width*cm2inch,figure_height*cm2inch))
ax = fig.add_axes((left, bottom, width, height))

# limits settings (important)
plt.xlim(0, figure_width * width)
plt.ylim(0, figure_height * height)

# Ticks settings
ax.xaxis.set_major_locator(mpl.ticker.MultipleLocator(5))
ax.xaxis.set_minor_locator(mpl.ticker.MultipleLocator(1))
ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(5))
ax.yaxis.set_minor_locator(mpl.ticker.MultipleLocator(1))

# Grid settings
ax.grid(color="gray", which="both", linestyle=':', linewidth=0.5)

# your Plot (consider above limits)
ax.plot([1,2,3,5,6,7,8,9,10,12,13,14,15,17])

# save figure ( printing png file had better resolution, pdf was lighter and better on screen)
plt.show()
fig.savefig('A4_grid_cm.png', dpi=1000)
fig.savefig('tA4_grid_cm.pdf')

结果:

在此输入图片描述

(注:该图片无法翻译,请自行查看原图)

请查看 这里 以了解如何编写一个好的答案。 - AzyCrw4282

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接