不同方法的比较
这是我尝试过的一些方法的快速比较,图片显示了所提供的内容。
未尝试设置图像尺寸的基线示例
只是有一个比较点:
基础.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'
:
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
实际删除边距......
提问:如何在 Matplotlib 中获得固定的像素高度、固定的数据 x/y 纵横比并自动移除移除水平空白边距?
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
左上角的。
我设法解决了那些在 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
开启fig.set_size_inches
和plt.savefig(dpi=
缩放
我相信这相当于提到的方法:https ://stackoverflow.com/a/13714720/895245
魔法.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 大小调整:
<img height=""
HTML 上的设置也应该适用于浏览器。
在 matplotlib==3.2.2 上测试。