如何在Matplotlib中获得固定的像素高度、固定的数据x/y纵横比以及自动删除水平空白边距?

如何在Matplotlib中获得固定的像素高度、固定的数据x/y纵横比以及自动删除水平空白边距?,matplotlib,Matplotlib,让我们以此为出发点,基于: 这让我可以做: ./main.py 400 && identify main.png 要生成正确的所需高度为400像素的图像,请执行以下操作: main.png PNG 533x400 533x400+0+0 8-bit sRGB 6058B 0.000u 0:00.000 然而,在绘图的左侧和右侧都有很多空白。这个空间是由于1的固定纵横比造成的,这也是我想要的(x和y数据具有相同的大小)。我们可以通过删除set\u aspect调用来确认,该调

让我们以此为出发点,基于:

这让我可以做:

./main.py 400 && identify main.png
要生成正确的所需高度为400像素的图像,请执行以下操作:

main.png PNG 533x400 533x400+0+0 8-bit sRGB 6058B 0.000u 0:00.000

然而,在绘图的左侧和右侧都有很多空白。这个空间是由于
1
的固定纵横比造成的,这也是我想要的(x和y数据具有相同的大小)。我们可以通过删除
set\u aspect
调用来确认,该调用提供了一个具有合理大小的边距的数字:

但是我也想要1/1的纵横比

我曾尝试用几种方法从中删除此空间:但没有一种方法满足了我的要求

例如,如果我添加:

plt.savefig(bbox_inches='tight',
我得到了想要的图像:

但高度不再是我想要的400:

main.png PNG 189x345 189x345+0+0 8-bit sRGB 4792B 0.000u 0:00.000
或者,如果我尝试添加:

plt.tight_layout(pad=0)
高度正确,但未删除水平空间:

我可以做的一件事是显式设置宽度,如下所示:

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

h = int(sys.argv[1])
w = int(sys.argv[2])
fig, ax = plt.subplots(nrows=2, ncols=1)
wi, hi = fig.get_size_inches()
fig.set_size_inches(hi*(w/h), hi)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.tight_layout(pad=1)
plt.savefig(
    'main.png',
    format='png',
    dpi=h/hi,
    facecolor='y',
)
并将其与:

./main.py 400 250 && identify main.png
其中250是通过反复试验选择的,这确实给出了精确的像素尺寸和好看的输出:

但是我不希望通过反复试验来找到值250,我希望它由matplotlib自动确定

这可能就是问题所在,但如果没有具体的例子就很难确定


在matplotlib==3.2.2上测试。

我不知道是否理解您的问题,但如果您想限制1x2子地块布局图形中的空白,只需创建一个宽度为高度一半的图形:

h = 400
nrows = 2
w = h/nrows
dpi = 100

fig, ax = plt.subplots(nrows=nrows, ncols=1, figsize=(w/dpi, h/dpi), dpi=dpi)

t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.tight_layout(pad=1)
plt.savefig(
    'main.png',
    format='png',
    dpi=dpi,
    facecolor='y',
)
>识别main.png

main.png png 200x400 200x400+0+0 8位sRGB 6048B 0.000u 0:00.000


我不知道我是否理解你的问题,但如果你想用1x2子地块布局限制图形中的空白,你只需创建一个宽度为高度一半的图形:

h = 400
nrows = 2
w = h/nrows
dpi = 100

fig, ax = plt.subplots(nrows=nrows, ncols=1, figsize=(w/dpi, h/dpi), dpi=dpi)

t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.tight_layout(pad=1)
plt.savefig(
    'main.png',
    format='png',
    dpi=dpi,
    facecolor='y',
)
>识别main.png

main.png png 200x400 200x400+0+0 8位sRGB 6048B 0.000u 0:00.000


SVG输出+
plt.savefig(bbox\u inches='tight'
+Inkscape转换

这太糟糕了,但它做了我想要的,没有很多额外的样板,所以我们开始:

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

h = int(sys.argv[1])
fig, ax = plt.subplots(nrows=2, ncols=1)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.savefig(
    'main.svg',
    format='svg',
    dpi=h/fig.get_size_inches()[1],
    facecolor='y',
    bbox_inches='tight',
)
然后:

inkscape -b FFF -e main.png -h 400 main.svg
输出:

bbox\u inches='tight'
提供了一个外观不错的图像,没有太多的边框,但会使我丢失确切的大小,因此我们使用SVG输出作为解决这一问题的方法

这应该可以很好地工作,因为SVG是一种矢量格式,因此应该无缝地扩展到任何大小

我使用Inkscape进行转换,因为Imagemagick需要您手动计算分辨率:


在Inkscape 0.92.5上测试。

SVG输出+
plt.savefig(bbox\u inches='tight'
+Inkscape转换

这太糟糕了,但它做了我想要的,没有很多额外的样板,所以我们开始:

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

h = int(sys.argv[1])
fig, ax = plt.subplots(nrows=2, ncols=1)
t = np.arange(-10., 10., 1.)
a = ax[0]
a.set_aspect(1)
a.plot(t, t, '.')
a = ax[1]
a.plot(t, -t, '.')
a.set_aspect(1)
plt.savefig(
    'main.svg',
    format='svg',
    dpi=h/fig.get_size_inches()[1],
    facecolor='y',
    bbox_inches='tight',
)
然后:

inkscape -b FFF -e main.png -h 400 main.svg
输出:

bbox\u inches='tight'
提供了一个外观不错的图像,没有太多的边框,但会使我丢失确切的大小,因此我们使用SVG输出作为解决这一问题的方法

这应该可以很好地工作,因为SVG是一种矢量格式,因此应该无缝地扩展到任何大小

我使用Inkscape进行转换,因为Imagemagick需要您手动计算分辨率:


在Inkscape 0.92.5上测试。

好的,我应该用它进行更多的测试。这个解决方案是合理的。但是,自己进行nrow/ncol操作有点烦人。如果添加了其他垂直非绘图区域元素,空间也会返回,例如
a.set_title('a',fontdict=dict(fontsize='75'))
。虽然在实践中这可能并不常见(字体大小过大)。我现在还注意到,在更一般的情况下,纵横比也需要考虑(这个答案适用于
a.set\u aspect(1)
)。好的,我应该对此进行更多的测试。这个解决方案是合理的。但我自己必须进行nrow/ncol操作有点烦人。如果添加了其他垂直非绘图区域元素,空间也会返回,例如
a.set_title('a',fontdict=dict(fontsize='75'))
。尽管在实践中这可能并不常见(字体太大了)。我现在还注意到,在更一般的情况下,纵横比也需要考虑(这个答案适用于
a.set\u aspect(1)
)的特定情况)。