matplotlib的savefig()保存的图与show()展示的图不同

103

当我使用show()X中绘制图形时,图形看起来非常好。然而,当我开始使用savefig()生成大量的图形时,savefig()生成的图形的字体、线条和多边形都比show()生成的图形要小。我的环境是Ubuntu,show()的后端是Qt4Agg。如何使show()绘图和savefig()绘图看起来一致?

4个回答

110
savefig指定了保存图形的 DPI(如果在您的 .matplotlibrc 中没有指定,默认为 100,请查看 savefigdpi kwarg)。它不会继承原始图形的 DPI。
DPI 影响文本相对大小和线条宽度等。如果想要图像保持完全一致,则将 fig.dpi 传递给 fig.savefig
例如:
import matplotlib.pyplot as plt

fig = plt.figure()
plt.plot(range(10))
fig.savefig('temp.png', dpi=fig.dpi)

1
似乎适用于 .png,但不适用于 .jpg。我发现它适用于 jpg,但我必须添加 bbox_inches='tight' 才能使其正常工作。 - Randy Welt

45

虽然这是一个老问题,但显然谷歌很喜欢它,所以我在研究了这个问题之后想在这里回答一下。

如果您从零开始创建一个图形,您可以在创建时为其指定一个大小选项:

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(3, 6))

plt.plot(range(10)) #plot example
plt.show() #for control

fig.savefig('temp.png', dpi=fig.dpi)

figsize(width,height) 调整您的图表的绝对尺寸,有助于确保两个图表看起来相同。

如其他回答中所述,dpi 选项会影响文本的相对大小和线条宽度等。使用 dpi=fig.dpi 选项可以确保在 show()savefig() 中这些元素的相对大小相同。

或者,也可以在创建后更改图形大小:

fig.set_size_inches(3, 6, forward=True)

forward 能够随时更改大小。

如果您在创建的图像中遇到边框过大的问题,可以使用以下方法进行调整:

plt.tight_layout()
#or:
plt.tight_layout(pad=2)
或者:
fig.savefig('temp.png', dpi=fig.dpi, bbox_inches='tight')
#or:
fig.savefig('temp.png', dpi=fig.dpi, bbox_inches='tight', pad_inches=0.5)

第一个选项只是最小化了布局和边框,而第二个选项允许手动微调边框。这些提示至少帮助我解决了不同savefig()show()图像的问题。


33

你会通过不同的方式来渲染你的 matplotlib 图形(例如通过 Quartz 在屏幕上显示或者通过使用不同的函数(plotsavefig)将其保存为 PDF 文件),这些函数的参数几乎相同,但这些函数的默认参数并不相同。

换句话说,savefig 的默认参数与默认的display参数不同。

如果你想要使它们保持一致,可以在 matplotlib 配置文件 中很容易地完成。模板文件包含在源码包中,并命名为 matplotlibrc.template。如果在安装 matplotlib 时没有创建该文件,可以从 matplotlib 源代码或matplotlib 网站获取此模板。

自定义此文件后,将其重命名为 matplotlibrc(无扩展名)并保存到目录.matplotlib(注意前面的“.”)中,该目录应位于您的主目录中。

在提供的 matplotlibrc.template 文件中,控制 保存图形 参数的部分开始于约 314 行(此部分前的第一行为“### SAVING FIGURES”)。

特别地,您需要查看以下内容:

savefig.dpi       : 100         # figure dots per inch
savefig.facecolor : white       # figure facecolor when saving
savefig.edgecolor : white       # figure edgecolor when saving
savefig.extension : auto        # what extension to use for savefig('foo'), or 'auto'

以下是字体类型和各种图像格式特定参数的设置。

与此同时,这些参数 用于显示,即在 PLT.show() 处开始,位于 matplotlibrc.template 的大约第 277 行(此部分前面有一行注释:### FIGURE):

figure.figsize   : 8, 6          
figure.dpi       : 80            
figure.facecolor : 0.75       
figure.edgecolor : white     

通过比较这两个参数块的值,您可以看到同一图形属性的默认设置在保存图片显示图片时是不同的


更改这些配置不会使show()和savefig()之间的字体大小和行宽保持一致。虽然我想补充说明,从Qt Widget手动保存图表是可以的。唯一不行的情况是使用savefig()。 - leon

4

我在我的matplotlib源代码中修复了这个问题,但解决方法不是很完美。然而,如果你像我一样非常注重图表的外观,那么它是值得的。

问题似乎出现在渲染后端中;它们都获得了正确的linewidth,字体大小等数值,但在渲染为PDF或PNG时,其大小会比show()渲染时略大一些。

我在matplotlib/backends/backend_agg.py文件中添加了几行用于生成PNG的源代码。您可以针对每个使用的后端进行类似的更改,或者找到一种在单个位置进行更智能更改的方法;)

添加到我的matplotlib/backends/backend_agg.py文件:

    # The top of the file, added lines 42 - 44
42  # @warning: CHANGED FROM SOURCE to draw thinner lines
43  PATH_SCALAR = .8
44  FONT_SCALAR = .95

    # In the draw_markers method, added lines 90 - 91
89  def draw_markers(self, *kl, **kw):
90      # @warning: CHANGED FROM SOURCE to draw thinner lines
91      kl[0].set_linewidth(kl[0].get_linewidth()*PATH_SCALAR)
92      return self._renderer.draw_markers(*kl, **kw)

    # At the bottom of the draw_path method, added lines 131 - 132:
130 else:
131     # @warning: CHANGED FROM SOURCE to draw thinner lines
132     gc.set_linewidth(gc.get_linewidth()*PATH_SCALAR)
133     self._renderer.draw_path(gc, path, transform, rgbFace)

    # At the bottom of the _get_agg_font method, added line 242 and the *FONT_SCALAR
241     font.clear()
242     # @warning: CHANGED FROM SOURCE to draw thinner lines
243     size = prop.get_size_in_points()*FONT_SCALAR
244     font.set_size(size, self.dpi)

那对我目前的需求来说很合适,但是根据你所做的工作不同,你可能希望在其他方法中实现类似的更改。或者找到一种更好的方法,在不改变那么多行的情况下完成相同的操作!更新:在Github上向matplotlib项目发布问题后,我能够追踪到我的问题源头:我已经在matplotlibrc文件中更改了figure.dpi设置。如果该值与默认值不同,则即使我将savefig dpi设置为与figure dpi相同,我的savefig()图像也会不同。因此,我没有像上面那样更改源代码,而是将figure.dpi设置保持为默认值80,然后能够使用savefig()生成看起来像show()中的图像。Leon,你也更改了那个设置吗?

刚刚在这里添加了一个问题,希望能够创建一个更好的解决方案:https://github.com/matplotlib/matplotlib/issues/786 - Karmel

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