为什么将matplotlib绘制的图形以.eps格式保存并进行光栅化后,文件大小会急剧增加?

3
我有以下演示代码,其中我创建了一个简单的散点图,并将其保存为png、完全矢量化的eps和部分光栅化的eps
对于大量的点,我期望矢量化的eps文件大小比png文件要大得多(至少在合理的dpi下),这也是我观察到的。当我将散点图光栅化时,我希望文件大小能够回到png的大小,因为实际上我只是在eps中“嵌入”了png,对吗?然而,光栅化版本的文件大小却完全膨胀了约20倍: png: 48K,完全矢量化的eps: 184K,光栅化的eps: 3.8M(在Linux openSUSE上,使用python 3.4.6matplotlib 2.2.2)。
这是什么原因呢?我的理解是当我们将整个图形光栅化时,它会变成像png一样小,这种理解是错误的吗?当我将png放入inkscape并导出为eps时,我得到的文件(显然是光栅化的)比原始的png文件稍微大一点。
演示代码:
import matplotlib.pyplot as plt
import numpy as np

# Prepare some random data
N = 10000
x = np.random.rand(N)
y = np.random.rand(N)

dpi = 150

# Create a figure and plot some points
fig = plt.figure()
ax = fig_mesh.add_subplot(111)

scatter = ax.scatter(x, y, zorder=0.5)

# Save it as png or unrasterized eps
fig_mesh.savefig('mesh.png', dpi=dpi) # 184K
fig_mesh.savefig('mesh.eps') # 48 K

# Save it with rasterized points
ax_mesh.set_rasterization_zorder(1)
fig_mesh.savefig('mesh_rasterized.eps', dpi=dpi, rasterized=True) # 3.8M!

提前感谢您!


我可以想象,存储在eps文件中的光栅图像不是压缩的png而是位图,因为eps通常需要无损。与png相比,位图通常非常大。因此,当将某些随机图像保存为png时,我得到了100 kB的文件大小,而将相同的图像保存为bmp时,它的大小为2 MB。 - ImportanceOfBeingErnest
@ImportanceOfBeingErnest确实,经过检查eps文件,我发现大部分文件由bmp组成。事实证明,我的光栅化理解是错误的:虽然我认为光栅化部分会被转换为固定分辨率的png样式图像,但它们仍然具有无限的分辨率。只是没有光栅化,我们会得到许多绘制矩形的向量指令(这可能需要长时间渲染,取决于查看器),而有了光栅化,我们得到一个巨大的位图,可能更快地呈现。现在回答自己的问题是否好的礼节? - kuadrat
我猜礼貌的方式是先问问评论者是否愿意回答,但在这种情况下,你可以安全地假设如果我真的想要回答,我会这样做的,所以请继续回答,然后别忘了在两天内接受那个答案。 - ImportanceOfBeingErnest
谢谢你的提示。实际上,我想更礼貌地提出我的最后一个问题,包括对你回答的内在建议,但是我已经没有足够的字符空间了,所以我想“算了”,缩短一下 ;) - kuadrat
1个回答

0
我将在此回答自己的问题,但感谢@ImportanceOfBeingErnest指引我正确的方向。 简短回答是:我对matplotlib中的rasterized关键字(以及栅格化)的理解有误。
文件大小增加的原因很简单,即无论栅格化什么内容,都必须将其作为无压缩位图放入结果eps中。根据所请求的dpi,这可能比我们在未栅格化情况下拥有的矢量指令集占用更少的空间,也可能占用更多的空间。 可以通过将问题演示代码中的dpi值更改为不同的值来进行测试。例如,在dpi = 10时,栅格化图像明显较小-尽管在这种情况下绘制点的分辨率难以忍受。但是,在矩形网格的情况下,例如由pcolormesh生成的情况下,可以设置较低的dpi而不会失去pcolormesh数据的“分辨率”。
为了完整起见,我添加了一个使用pcolormesh的示例,其中使用低dpi设置的结果栅格化eps比矢量版本小:
import matplotlib.pyplot as plt
import numpy as np

# Prepare some random data
n = 100
N = n*n
data = np.random.rand(N).reshape(n,n)

dpi = 50

# Create a figure and plot some points
fig = plt.figure()
ax = fig.add_subplot(111)

mesh = ax.pcolormesh(data, zorder=0.5)

# Save it as png or unrasterized eps
fig.savefig('mesh.png', dpi=dpi)
fig.savefig('mesh.eps')

# Save it with rasterized points
ax.set_rasterization_zorder(1)
fig.savefig('mesh_rasterized.eps', dpi=dpi, rasterized=True)

此外,在我的研究中,我发现了一个简单的“黑客”方法,可以使用 epstopdf 和 pdftops 命令(在 Linux 上测试)轻松地减小 eps 文件大小(似乎没有损失),希望对一些人有用:
$ epstopdf my.eps #Creates file my.pdf
$ pdftops -eps my.pdf # Creates smaller my.eps (overwriting the old one!)

最后,这些相关问题也帮助我理解了一些内容:


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