常见问题#

我没有看到图窗窗口#

请参阅 调试图窗窗口未显示问题

为什么刻度线这么多,和/或为什么它们是乱序的?#

导致意外刻度行为的一个常见原因是传入的是字符串列表,而不是数字或日期时间对象。这在读取逗号分隔的文本文件时很容易在不经意间发生。Matplotlib 将字符串列表视为分类变量(绘制分类变量),默认情况下,每个类别放置一个刻度,并按它们提供的顺序进行绘制。

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(1, 2, layout='constrained', figsize=(6, 2))

ax[0].set_title('Ticks seem out of order / misplaced')
x = ['5', '20', '1', '9']  # strings
y = [5, 20, 1, 9]
ax[0].plot(x, y, 'd')
ax[0].tick_params(axis='x', labelcolor='red', labelsize=14)

ax[1].set_title('Many ticks')
x = [str(xx) for xx in np.arange(100)]  # strings
y = np.arange(100)
ax[1].plot(x, y)
ax[1].tick_params(axis='x', labelcolor='red', labelsize=14)

(源代码, 2x.png, png)

解决方案是将字符串列表转换为数字或日期时间对象(通常是 np.asarray(numeric_strings, dtype='float')np.asarray(datetime_strings, dtype='datetime64[s]'))。

更多信息请参阅修复过多刻度线

确定图窗中图元的范围#

有时我们想知道图元的范围。Matplotlib Artist 对象有一个方法 Artist.get_window_extent,它通常会返回图元在像素中的范围。然而,有些图元,特别是文本,必须至少渲染一次才能知道其范围。Matplotlib 提供了 Figure.draw_without_rendering,应在调用 get_window_extent 之前调用此方法。

检查图窗是否为空#

空实际上可能意味着不同的事情。图窗是否包含任何图元?一个带有空 Axes 的图窗是否仍算作空?如果图窗渲染为纯白色(可能存在图元,但它们可能在绘图区域之外或透明),图窗是否为空?

在此,我们将“空”定义为:“图窗不包含任何图元,除了其背景补丁。”背景的例外是必要的,因为默认情况下,每个图窗都包含一个 Rectangle 作为其背景补丁。可以通过以下方式检查此定义:

def is_empty(figure):
    """
    Return whether the figure contains no Artists (other than the default
    background patch).
    """
    contained_artists = figure.get_children()
    return len(contained_artists) <= 1

我们决定不将其作为图窗方法,因为这只是定义“空”的一种方式,并且上述检查很少有必要。通常,处理图窗的用户或程序知道他们是否已向图窗添加了内容。

检查图窗是否会渲染为空的唯一可靠方法是实际执行一次这样的渲染并检查结果。

查找图窗中特定类型的所有对象#

每个 Matplotlib 图元(请参阅 图元教程)都有一个名为 findobj() 的方法,可用于递归搜索图元中可能包含的符合某些条件(例如,匹配所有 Line2D 实例或匹配某个任意过滤函数)的任何图元。例如,以下代码片段会查找图窗中所有具有 set_color 属性的对象,并将其设为蓝色

def myfunc(x):
    return hasattr(x, 'set_color')

for o in fig.findobj(myfunc):
    o.set_color('blue')

您也可以根据类实例进行过滤

import matplotlib.text as text
for o in fig.findobj(text.Text):
    o.set_fontstyle('italic')

防止刻度标签带有偏移#

默认格式化器将使用偏移来减少刻度标签的长度。若要按轴禁用此功能,请执行以下操作:

ax.xaxis.get_major_formatter().set_useOffset(False)

rcParams["axes.formatter.useoffset"] 设置为(默认值:True),或使用不同的格式化器。详见 ticker

保存透明图窗#

savefig() 命令有一个关键字参数 transparent,如果设置为 'True',则在保存时会将图窗和坐标轴的背景设为透明,但不会影响屏幕上显示的图像。

如果您需要更精细的控制,例如,不希望完全透明,或者也想影响屏幕上显示的版本,您可以直接设置 alpha 属性。图窗有一个名为 patchRectangle 实例,坐标轴也有一个名为 patch 的 Rectangle 实例。您可以直接设置它们的任何属性(facecolor, edgecolor, linewidth, linestyle, alpha)。例如:

fig = plt.figure()
fig.patch.set_alpha(0.5)
ax = fig.add_subplot(111)
ax.patch.set_alpha(0.5)

如果您需要图窗中的所有元素都透明,目前没有全局 alpha 设置,但您可以单独设置每个元素的 alpha 通道,例如:

ax.plot(x, y, alpha=0.5)
ax.set_xlabel('volts', alpha=0.5)

将多个绘图保存到一个 PDF 文件#

许多图像文件格式每个文件只能包含一张图像,但有些格式支持多页文件。目前,Matplotlib 仅通过 backend_pdf.PdfPagesbackend_pgf.PdfPages 类,通过 pdf 或 pgf 后端提供多页输出到 pdf 文件。

为刻度标签留出空间#

默认情况下,Matplotlib 在子图周围使用固定百分比边距。这可能导致标签重叠或在图窗边界处被截断。有多种方法可以解决此问题:

在多个子图中对齐我的 y 轴标签#

如果您有多个子图相互堆叠,并且 y 轴数据具有不同的比例,您通常会发现 y 轴标签在多个子图之间无法垂直对齐,这可能不太美观。默认情况下,Matplotlib 会将 y 轴标签的 x 位置放置在不与任何 y 轴刻度线重叠的位置。您可以通过指定标签的坐标来覆盖此默认行为。要了解如何操作,请参阅 对齐 y 轴标签

控制绘图元素的绘制顺序#

绘图元素的绘制顺序,从而决定哪些元素将在上方,由 set_zorder 属性决定。详见 Zorder 演示 以获取详细说明。

使绘图的纵横比相等#

坐标轴属性 set_aspect() 控制坐标轴的纵横比。您可以将其设置为 'auto'、'equal' 或某个控制比例的值

ax = fig.add_subplot(111, aspect='equal')

详见 相等坐标轴纵横比 以获取完整示例。

绘制多个 y 轴刻度#

一个常见的需求是为左右 y 轴设置两个刻度,这可以通过使用 twinx() 来实现(目前不支持两个以上刻度,但这已列入愿望清单)。这效果很好,但在尝试交互式平移和缩放时存在一些问题,因为两个刻度都没有接收到信号。

该方法使用 twinx()(及其姐妹函数 twiny())来使用两个不同的坐标轴,关闭第二个坐标轴的矩形框架以防止其遮挡第一个,并根据需要手动设置刻度位置和标签。您可以根据需要使用单独的 matplotlib.ticker 格式化器和定位器,因为这两个坐标轴是独立的。

(源代码, 2x.png, png)

详见 不同刻度的绘图 以获取完整示例。

生成图像而不显示窗口#

只需不调用 show,直接将图窗保存为所需格式即可

import matplotlib.pyplot as plt
plt.plot([1, 2, 3])
plt.savefig('myfig.png')
plt.close()

另请参阅

参阅 嵌入到 Web 应用程序服务器中 (Flask),获取有关在 Web 应用程序中运行 Matplotlib 的信息。

使用线程#

Matplotlib 不是线程安全的:事实上,存在已知的竞态条件会影响某些图元。因此,如果您使用线程,您有责任设置适当的锁以序列化对 Matplotlib 图元的访问。

您可能可以在单独的线程中处理不同的图窗。然而,在这种情况下,您必须使用非交互式后端(通常是 Agg),因为大多数 GUI 后端也要求在主线程中运行。

获取帮助#

有许多不错的资源可以帮助您解决 Matplotlib 的问题。很有可能您的问题已经有人问过

如果您无法通过搜索找到问题的答案,请在发送给邮件列表的电子邮件中提供以下信息

  • 您的操作系统(Linux/Unix 用户:请发布 uname -a 的输出)。

  • Matplotlib 版本

    python -c "import matplotlib; print(matplotlib.__version__)"
    
  • 您从何处获取 Matplotlib(例如,您的 Linux 发行版软件包、GitHub、PyPI 或 Anaconda)。

  • 对您的 matplotlibrc 文件的任何自定义(详见 使用样式表和 rcParams 自定义 Matplotlib)。

  • 如果问题是可重现的,请尝试提供一个最小的、独立的 Python 脚本来演示该问题。这是关键的步骤。如果您无法发布一段我们能够运行并重现您的错误的代码,那么获得帮助的机会将大大减少。很多时候,仅仅是尝试将您的代码最小化到产生错误的最小部分,就能帮助您在自己的代码中找到导致问题的错误。

  • Matplotlib 通过 logging 库提供调试信息,以及一个设置日志级别的辅助函数:可以调用

    plt.set_loglevel("info")  # or "debug" for more info
    

    以获取此调试信息。

    logging 模块中的标准函数也适用;例如,即使在导入 Matplotlib 之前,也可以调用 logging.basicConfig(level="DEBUG")(这对于获取 Matplotlib 导入期间发出的日志信息尤为必要),或者将自定义处理程序附加到“matplotlib”日志器。如果您使用自定义日志配置,这可能很有用。

如果您自行编译了 Matplotlib,请一并提供

  • 您的编译器版本——例如,gcc --version

  • 的输出

    pip install --verbose
    

    构建输出的开头包含大量关于您平台的详细信息,这些信息对于 Matplotlib 开发人员诊断您的问题很有用。

如果您使用预 Meson 构建系统编译了 Matplotlib 的旧版本,则请提供

  • 您对 setup.py/setupext.py 所做的任何更改,

  • 的输出

    rm -rf build
    python setup.py build
    

在您发送给邮件列表的第一封电子邮件中包含这些信息将节省大量时间。

您写信给邮件列表可能会比在 bug 跟踪器中提交 bug 获得更快的响应。大多数开发人员只定期检查 bug 跟踪器。如果您的问被确定为 bug 且无法迅速解决,您可能会被要求在跟踪器中提交 bug,以免问题丢失。