不同方法的比较
这里是我尝试过的一些方法的快速比较,图片显示了所提供的内容。
不尝试设置图像尺寸的基准示例
只是为了有个比较点:
base.py
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax = plt.subplots()
print('fig.dpi = {}'.format(fig.dpi))
print('fig.get_size_inches() = ' + str(fig.get_size_inches())
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig('base.png', format='png')
运行:
./base.py
identify base.png
输出:
fig.dpi = 100.0
fig.get_size_inches() = [6.4 4.8]
base.png PNG 640x480 640x480+0+0 8-bit sRGB 13064B 0.000u 0:00.000
到目前为止我最好的方法:plt.savefig(dpi=h/fig.get_size_inches()[1] 仅高度控制
我认为这是我大部分时间都会使用的,因为它简单且可扩展:
get_size.py
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
height = int(sys.argv[1])
fig, ax = plt.subplots()
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
'get_size.png',
format='png',
dpi=height/fig.get_size_inches()[1]
)
运行:
./get_size.py 431
输出:
get_size.png PNG 574x431 574x431+0+0 8-bit sRGB 10058B 0.000u 0:00.000
和
./get_size.py 1293
输出:
main.png PNG 1724x1293 1724x1293+0+0 8-bit sRGB 46709B 0.000u 0:00.000
我倾向于只设置高度,因为我通常最关心图像将在文本中间占据多少垂直空间。
plt.savefig(bbox_inches='tight' 改变图片大小
我总觉得图片周围留白太多,倾向于加bbox_inches='tight' from:
Removing white space around a saved image in matplotlib
但是,这可以通过裁剪图像来实现,并且您不会获得所需的尺寸。
相反,在同一个问题中提出的另一种方法似乎效果很好:
plt.tight_layout(pad=1)
plt.savefig(...
它给出了高度等于 431 的确切期望高度:
固定高度,set_aspect,自动调整宽度和小边距
Ermmm,set_aspect 又搞砸了,阻止 plt.tight_layout 实际删除边距...
提问于:How to obtain a fixed height in pixels, fixed data x/y aspect ratio and automatically remove remove horizontal whitespace margin in Matplotlib?
plt.savefig(dpi=h/fig.get_size_inches()[1] + 宽度控制
如果您真的需要除高度之外的特定宽度,这似乎可以正常工作:
宽度.py
#!/usr/bin/env python3
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()
wi, hi = fig.get_size_inches()
fig.set_size_inches(hi*(w/h), hi)
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
'width.png',
format='png',
dpi=h/hi
)
运行:
./width.py 431 869
输出:
width.png PNG 869x431 869x431+0+0 8-bit sRGB 10965B 0.000u 0:00.000
对于小宽度:
./width.py 431 869
输出:
width.png PNG 211x431 211x431+0+0 8-bit sRGB 6949B 0.000u 0:00.000
所以看起来字体缩放是正确的,我们只是在标签被切断的非常小的宽度上遇到了一些麻烦,例如左上角的100。
我设法解决了 Removing white space around a saved image in matplotlib 的问题
plt.tight_layout(pad=1)
给出:
width.png PNG 211x431 211x431+0+0 8-bit sRGB 7134B 0.000u 0:00.000
由此我们也看到tight_layout去除了图片顶部的很多空白空间,所以我只是一般一直使用它。
固定魔法基础高度,dpi on fig.set_size_inches 和 plt.savefig(dpi= 缩放
我相信这和上面提到的方法是等价的:https://stackoverflow.com/a/13714720/895245
magic.py
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
magic_height = 300
w = int(sys.argv[1])
h = int(sys.argv[2])
dpi = 80
fig, ax = plt.subplots(dpi=dpi)
fig.set_size_inches(magic_height*w/(h*dpi), magic_height/dpi)
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
'magic.png',
format='png',
dpi=h/magic_height*dpi,
)
运行:
./magic.py 431 231
输出:
magic.png PNG 431x231 431x231+0+0 8-bit sRGB 7923B 0.000u 0:00.000
然后看看它是否可以很好地扩展:
./magic.py 1291 693
输出:
magic.png PNG 1291x693 1291x693+0+0 8-bit sRGB 25013B 0.000u 0:00.000
所以我们看到这种方法也很有效。我唯一遇到的问题是您必须设置 magic_height 参数或等效参数。
固定 DPI + set_size_inches
这种方法给出了一个稍微错误的像素大小,并且很难无缝缩放所有内容。
set_size_inches.py
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
w = int(sys.argv[1])
h = int(sys.argv[2])
fig, ax = plt.subplots()
fig.set_size_inches(w/fig.dpi, h/fig.dpi)
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(
0,
60.,
'Hello',
# Keep font size fixed independently of DPI.
# https://stackoverflow.com/questions/39395616/matplotlib-change-figsize-but-keep-fontsize-constant
fontdict=dict(size=10*h/fig.dpi),
)
plt.savefig(
'set_size_inches.png',
format='png',
)
运行:
./set_size_inches.py 431 231
输出:
set_size_inches.png PNG 430x231 430x231+0+0 8-bit sRGB 8078B 0.000u 0:00.000
所以高度稍微偏离了,图像:
如果我把它放大 3 倍,像素大小也是正确的:
./set_size_inches.py 1291 693
输出:
set_size_inches.png PNG 1291x693 1291x693+0+0 8-bit sRGB 19798B 0.000u 0:00.000
但我们从中了解到,要使这种方法很好地缩放,您需要使每个 DPI 相关设置与以英寸为单位的大小成比例。
在前面的示例中,我们只使“Hello”文本成比例,它的高度确实保持在我们预期的 60 到 80 之间。但是我们没有这样做的所有东西看起来都很小,包括:
SVG
我找不到如何为 SVG 图像设置它,我的方法仅适用于 PNG,例如:
get_size_svg.py
#!/usr/bin/env python3
import sys
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
height = int(sys.argv[1])
fig, ax = plt.subplots()
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
'get_size_svg.svg',
format='svg',
dpi=height/fig.get_size_inches()[1]
)
运行:
./get_size_svg.py 431
并且生成的输出包含:
<svg height="345.6pt" version="1.1" viewBox="0 0 460.8 345.6" width="460.8pt"
并确定说:
get_size_svg.svg SVG 614x461 614x461+0+0 8-bit sRGB 17094B 0.000u 0:00.000
如果我在 Chromium 86 中打开它,浏览器调试工具鼠标图像悬停确认高度为 460.79。
当然,由于 SVG 是一种矢量格式,理论上一切都应该按比例缩放,因此您可以在不损失分辨率的情况下转换为任何固定大小的格式,例如:
inkscape -h 431 get_size_svg.svg -b FFF -e get_size_svg.png
给出准确的高度:
TODO 重新生成图像,不知何故搞砸了上传。
我在这里使用 Inkscape 而不是 Imagemagick 的 convert,因为您还需要使用 -density 来使用 ImageMagick 获得锐利的 SVG 大小调整:
在 HTML 上设置 <img height="" 也应该只适用于浏览器。
在 matplotlib==3.2.2 上测试。