当前位置: 首页 > 知识库问答 >
问题:

为什么matplotlib不默认保存整个图形?

江睿
2023-03-14

这可能是几乎每个使用matplotlib的人都会遇到的问题。如果您生成一个图形——它通常包含轴标签和图例——并使用默认设置保存它,您将得到一个裁剪后的图像。

演示代码:

import matplotlib.pyplot as plt
def plot():
    plt.figure(figsize=[3,3],linewidth=5,edgecolor='r') 
    ax=plt.subplot()
    ax.plot(range(10),range(10),label='label')
    ax.set_xlabel('xlabel\nxlabel\nxlabel')
    ax.set_ylabel('ylabel\nylabel\nylabel')
    ax.legend(bbox_to_anchor=[1,1])
plot()    
plt.savefig('no_tight_layout.png')

(多亏了stackoverflow),我们知道很少的变通方法,但每种方法都有自己的警告…
变通方法#1:从matplotlib中:使用tight_layout选项。

plot()    
plt.savefig('tight_layout.png',bbox_inches='tight')

它适用于简单的图形。< br >但是,根据我的经验,对于更复杂的多面板图形,这不是一个可靠的选择。< code>tight_layout经常失败,并出现如下错误:

UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
UserWarning: tight_layout not applied: number of rows in subplot specifications must be multiples of one another.

解决方法#2:从matplotlib外部:以SVG格式保存图像,然后转换为png。例如,使用inkscape命令行UI中的< code >-export-area-drawing 选项或inkscape GUI中的“调整页面大小”选项。

但是,在这种情况下,您必须依赖难以在python包中添加为依赖项的外部软件(目前conda仅托管Windows版本的inkscape)。

所以我的问题是。。

为什么 matplotlib 默认不保存整个图形?
如果我在 jupyter 笔记本中生成相同的图,而不使用tight_layout选项,我会看到图的所有元素都包含在图形边界内(以红色显示)。

这个图是在jupyter笔记本(!)的输出单元格中生成的。
那为什么它没有按原样保存?为什么默认情况下保存的图像与jupyter笔记本的图像不同?
在我看来,这是matplotlib的一个非常基本的问题。
如果默认情况下,所有元素都包含在保存的图中,而不需要任何变通方法,这难道不会让用户的生活更容易吗?

共有1个答案

公良高刚
2023-03-14

简而言之,它是matplotlib的一个特性,而不是一个问题。默认情况下,matplotlib为图形设置固定的大小,因此溢出的元素通常会被裁剪掉。

matplotlib提供了4个选项来处理元素的裁剪:

  1. plt.subplots_adjust追溯性地手动调整元素。数字大小不变。
  2. plt.tight_layout自动调整。数字大小不变。
  3. plt.constrained_layout自动调整。通常与fig.tight_layout相似。数字大小不变。
  4. plt.savefig(..,bbox_inches='tight'):调整图形大小以包含所有元素(您在Jupyter Notebook的输出中看到的内容)。图形大小更改。

选项 4 是我需要的,因为我想保存我在 jupyter 笔记本输出中看到的图形,无论图形大小如何。

我在matplotlib的github页面上得到了这个答案(感谢Elan Ernest@ImportanceOfBeingErnest)。

 类似资料:
  • 问题内容: 我开始使用本教程为初学者学习MatPlotLib 。这是第一个例子。 如果我将这三行代码写入我的python文件并在命令行中执行(通过键入),则什么都不会发生。没有错误信息,没有情节。 有人知道我为什么看不到情节吗? 添加 当然我需要用。但是,即使我添加以下3行: 它仍然不产生任何东西。 添加 这是我现在使用的行: 我仍然有相同的结果(什么都没有)。 问题答案: 后端可能有问题。输出是

  • 问题是Java Date对象不存储时区。该值始终使用UTC,并在给定的时区(通常是JVM的默认时区)中进行解析和格式化。 Oracle日期列也不带时区存储,但应该表示用户看到的日期。在99.99%的情况下,这意味着JVM默认时区中的日期。 因此,JDBC驱动程序采用UTC格式的时间戳/日期值,将其转换为默认时区,并将其保存到数据库中。 null 所以最终的问题是,为什么它是这样设计的?原因何在?

  • 最近我一直在尝试java图形,并决定制作一个可以打印拼贴图像的程序。这个程序的构造函数接受一个图像数组和每个图像将显示的宽度。 当我运行程序时,我最初使用以下方法来设置JFrame窗口的大小: 不幸的是,JFrame确实显示了部分图像。JFrame窗口不够低,无法显示所有窗口。为了再次确认我的数学没有出错,我用下面这行代码进行了测试: 同样的问题也发生了。直到我使用了下面的一行,整个图像才显示出来

  • 问题内容: 为什么这段代码会引发SyntaxError? 尽管以下代码段运行时没有可见错误: 问题答案: 必须将所有必需的参数放在任何默认参数之前。仅仅是因为它们是强制性的,而默认参数不是必需的。从语法上讲,如果允许使用混合模式,解释器将 无法 决定哪些值与哪些参数匹配。如果参数的输入顺序不正确,则会引发A : 让我们使用您的函数来查看关键字参数。 假设其允许声明函数如上,然后使用上述声明,我们可

  • 安装节点模块时,我忘记添加的次数太多了。默认情况下是否有附加此选项的方法?这样每当我键入

  • 问题内容: 我在日食中收到很多这样的警告: 变量“ myVariable”必须是私有的,并且具有访问器方法。 我想得到它们是因为我没有在eclipse中手动将protectedAllowed设置为true。但是为什么默认情况下将其设置为false?我不应该使用受保护的属性吗? 问题答案: 从理论上讲,受保护的属性(变量)在面向对象的语言中是一种反模式。如果仅子类需要访问其超类的成员属性,则将属性本