matplotlib savefig() 绘图不同于 show()

Posted

技术标签:

【中文标题】matplotlib savefig() 绘图不同于 show()【英文标题】:matplotlib savefig() plots different from show() 【发布时间】:2011-12-15 22:07:49 【问题描述】:

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

【问题讨论】:

【参考方案1】:

savefig 指定已保存图形的 DPI(如果未在 .matplotlibrc 中指定,则默认为 100,请查看 dpi kwarg to savefig)。它不会从原始图形的 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)

【讨论】:

似乎适用于 .png,但不适用于 .jpg。发现它适用于 jpg,我不得不添加 bbox_inches='tight'【参考方案2】:

您将 matplotlib 绘图渲染到不同的设备(例如,通过 Quartz 在屏幕上显示与使用不同功能通过 pdf 的 to-file(plotsavefig) 的参数几乎相同,但两个函数的这些参数的默认值并不相同。

换句话说,savefig默认参数不同于默认显示强>参数。

如果你在 matplotlib 配置文件中对齐它们很简单。模板文件包含在源包中,并命名为 matplotlibrc.template。如果您在安装 matplotlib 时没有创建模板,您可以从 matplotlib 源或 matplotlib website 获取此模板。

一旦你按照你想要的方式自定义了这个文件,把它重命名为 matplotlibrc(没有扩展名)并将它保存到目录 .matplotlib (注意前导的“.”)应该在你的主目录中。

保存数字的配置参数从提供的matplotlibrc.template中的第314行开始(本节之前的第一行是:# ## 保存数据)。

特别是,你会想看看这些:

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(),大​​约从第 277 行开始matplotlibrc.template 中的 a(本节前面有一行:### 图形):

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

通过比较这两个参数块的值可以看出,同一图形属性的默认设置不同 savefigdisplay(显示)。

【讨论】:

更改这些配置仍然与 show() 和 savefig() 之间一致的字体大小和线宽不匹配。虽然我想添加从 Qt Widget 手动保存图表是可以的。只有在使用 savefig() 时才行【参考方案3】:

老问题,但显然谷歌喜欢它,所以我想在对这个问题进行一些研究后在这里给出答案。

如果你从头开始创建一个图形,你可以在创建时给它一个大小选项:

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() 图像不同的问题。

【讨论】:

【参考方案4】:

我已经在我的 matplotlib 源代码中修复了这个问题,但这不是一个很好的修复。但是,如果您像我一样对图表的外观非常讲究,那就值得了。

问题似乎出在渲染后端;它们每个都得到了正确的线宽、字体大小等值,但是当呈现为 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() 图像会不同,即使我将 savefig dpi 设置为与图形 dpi 相同。因此,我没有像上面那样更改源,而是将 figure.dpi 设置保留为默认值 80,并且能够使用 savefig() 生成看起来像 show() 中的图像的图像。

Leon,您是否也更改了该设置?

【讨论】:

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

以上是关于matplotlib savefig() 绘图不同于 show()的主要内容,如果未能解决你的问题,请参考以下文章

matplotlib绘图

Python Matplotlib绘图

matplotlib和seaborn heatmap在Jupyter中呈现不同的savefig(标签截止)

服务器上使用matplotlib.pyplot绘图

如何使用标签和刻度区域透明而不是matplotlib中的主绘图区域保存绘图?

python - 使用 matplotlib 和 boto 将绘图从内存上传到 s3