0

0

Sphinx Doctest与Matplotlib绘图:避免交互式阻塞的策略

霞舞

霞舞

发布时间:2025-12-02 13:13:01

|

781人浏览过

|

来源于php中文网

原创

sphinx doctest与matplotlib绘图:避免交互式阻塞的策略

本文旨在解决Sphinx doctest 在处理包含Matplotlib绘图示例的文档字符串时,因 plt.show() 导致测试中断的问题。核心策略是通过重构绘图函数,使其接受可选的 Axes 对象并移除 plt.show() 的直接调用,从而将绘图逻辑与图形显示解耦。这种方法不仅提升了函数的复用性,也确保了 doctest 能够顺畅运行,实现自动化测试与文档生成。

理解问题:Sphinx Doctest与Matplotlib的交互式困境

在Python项目中,Sphinx是一个广泛使用的文档生成工具,其内置的 doctest 扩展能够从文档字符串中的示例代码直接运行测试,确保代码示例的准确性。然而,当这些文档字符串包含Matplotlib绘图代码,并且在函数内部调用了 plt.show() 时,doctest 可能会遇到一个常见的阻塞问题。

plt.show() 函数的作用是显示当前活动的Matplotlib图形窗口。在交互式环境中,这通常是期望的行为。但在自动化测试(如 doctest)或非交互式脚本中,plt.show() 会暂停程序执行,直到用户手动关闭图形窗口。这对于自动化流程来说是不可接受的,因为它需要人工干预,严重阻碍了测试的连续性。

考虑以下一个典型的Matplotlib绘图函数及其文档字符串:

import matplotlib.pyplot as plt

def plot_numbers_problematic(x):
    """
    显示一组数字的折线图。

    参数
    ----------
    x : list
        要绘制的数字列表。

    示例
    -------
    >>> import your_module # 假设此函数在your_module中
    >>> x_data = [1, 2, 5, 6, 8.1, 7, 10.5, 12]
    >>> your_module.plot_numbers_problematic(x_data)
    """
    _, ax = plt.subplots()
    ax.plot(x, marker="o", mfc="red", mec="red")
    ax.set_xlabel("X轴标签")
    ax.set_ylabel("Y轴标签")
    ax.set_title("图表标题")

    plt.show() # 此处会导致doctest阻塞

当 sphinx-build -b doctest . _build 命令执行到 your_module.plot_numbers_problematic(x_data) 这一行时,plt.show() 会弹出一个图形窗口,并暂停 doctest 的执行,直到该窗口被手动关闭。

核心策略:解耦绘图与显示

解决此问题的关键在于将Matplotlib函数的绘图逻辑图形显示行为进行解耦。一个设计良好的Matplotlib绘图函数不应该自行决定何时显示图形,而应该将这一控制权交给调用者。这样,函数可以更灵活地应用于各种场景,包括:

  1. 交互式显示: 调用者在函数执行后手动调用 plt.show()。
  2. 非交互式保存: 调用者在函数执行后将图形保存到文件,而不显示。
  3. 子图组合: 调用者在同一个 Figure 上创建多个 Axes,并将这些 Axes 传递给不同的绘图函数。
  4. 自动化测试: 测试框架可以调用绘图函数而不显示图形,只检查返回的 Axes 对象或其内容。

实现这一解耦的常用方法是让绘图函数接受一个可选的 Axes 对象作为参数。如果提供了 Axes 对象,函数就在其上绘图;如果没有提供,函数则自行创建一个新的 Figure 和 Axes。最重要的是,从函数内部移除 plt.show() 的调用。

优化Matplotlib绘图函数

以下是优化后的 plot_numbers 函数示例:

EasySub – AI字幕生成翻译工具
EasySub – AI字幕生成翻译工具

EasySub 是一款在线 AI 字幕生成器。 它提供AI语音识别、AI字幕生成、AI字幕翻译,本来就很简单的视频剪辑。

下载
import matplotlib.pyplot as plt

def plot_numbers(x, *, ax=None):
    """
    显示一组数字的折线图。

    参数
    ----------
    x : list
        要绘制的数字列表。
    ax : matplotlib.axes.Axes, 可选
        用于绘制数字的Matplotlib Axes对象。如果未提供,将创建一个新的Figure和Axes。

    返回
    -------
    matplotlib.axes.Axes
        绘制了数据的Axes对象。

    示例
    -------
    >>> import your_module # 假设此函数在your_module中
    >>> x_data = [1, 2, 5, 6, 8.1, 7, 10.5, 12]
    >>> # 在doctest中,这不会打开窗口。
    >>> # 如果需要在交互式环境中显示,请在调用函数后手动调用 plt.show()。
    >>> ax_result = your_module.plot_numbers(x_data)
    >>> # plt.show() # 在需要显示图形时取消注释
    >>> # 验证 Axes 对象是否已创建
    >>> assert isinstance(ax_result, plt.Axes)
    >>> # 进一步的doctest可以检查ax_result的属性,例如标题、标签等
    >>> ax_result.get_title()
    '图表标题'
    """
    if ax is None:
        # 如果没有提供Axes,则创建一个新的Figure和Axes
        _, ax = plt.subplots()

    # 在提供的或新创建的Axes上进行绘图
    ax.plot(x, marker="o", mfc="red", mec="red")
    ax.set_xlabel("X轴标签")
    ax.set_ylabel("Y轴标签")
    ax.set_title("图表标题")

    return ax # 返回Axes对象,以便调用者进行进一步操作

关键改动点说明:

  1. ax=None 参数: 函数现在接受一个可选的 ax 参数,类型为 matplotlib.axes.Axes。* 用作分隔符,表示 ax 是一个仅限关键字参数,提高了API的清晰度。
  2. 条件性 plt.subplots(): 如果 ax 为 None,函数会调用 plt.subplots() 创建一个新的 Figure 和 Axes。这意味着函数既可以在现有 Axes 上绘图,也可以作为独立的绘图函数使用。
  3. 移除 plt.show(): 最重要的改变是移除了 plt.show() 的调用。现在,函数只负责在 Axes 上绘制内容。
  4. 返回 ax: 函数现在返回绘制数据的 Axes 对象。这使得调用者能够访问和操作 Axes,例如保存图形、修改属性或在交互式环境中显示。
  5. 更新文档字符串示例: doctest 示例也相应更新,以接收返回的 ax 对象,并注释掉 plt.show(),明确告知用户在 doctest 环境下不会显示图形。

Doctest中的应用与优势

通过上述优化,当 doctest 运行时,它会执行 your_module.plot_numbers(x_data),函数会正常执行绘图逻辑并返回一个 Axes 对象,但不会弹出图形窗口,从而避免了阻塞。

这种方法带来了多方面的好处:

  • 无缝自动化测试: doctest 和其他测试框架(如 pytest)可以无障碍地运行包含Matplotlib示例的测试。
  • 更高的函数复用性: 绘图函数变得更加通用,可以轻松地集成到更复杂的图形布局(例如,使用 plt.figure().add_subplot() 或 plt.subplots() 创建的多个子图)或自定义的应用程序中。
  • 清晰的职责分离: 函数专注于“如何绘图”,而“何时显示”的职责则交给了调用者,这符合软件设计的单一职责原则。
  • 更好的控制: 调用者可以根据需要选择显示图形、将其保存到文件(fig.savefig(...))或在更高级的GUI应用程序中嵌入它。

注意事项与最佳实践

  1. 谁来调用 plt.show()? 在优化后的设计中,plt.show() 应该由最终的用户代码或顶层脚本来调用,而不是由库函数内部调用。例如:

    import matplotlib.pyplot as plt
    # 假设 plot_numbers 是优化后的函数
    import your_module
    
    if __name__ == "__main__":
        x_data = [1, 3, 2, 4, 5]
        # 在新的Figure和Axes上绘图并显示
        ax1 = your_module.plot_numbers(x_data)
        ax1.set_title("第一个图")
    
        # 在同一个Figure上创建另一个Axes,并用另一个函数绘图
        fig, (ax2, ax3) = plt.subplots(1, 2)
        your_module.plot_numbers([5, 4, 3, 2, 1], ax=ax2)
        ax2.set_title("第二个图")
        your_module.plot_numbers([10, 8, 6, 4, 2], ax=ax3)
        ax3.set_title("第三个图")
    
        plt.tight_layout() # 调整子图布局
        plt.show() # 在这里统一显示所有图形
  2. 文档清晰度: 在函数的文档字符串中明确说明 ax 参数的作用,以及函数不会自行调用 plt.show()。

  3. 参考官方指南: Matplotlib官方文档也推荐了这种编写辅助函数的方式,例如在其“Making a helper functions”部分(https://www.php.cn/link/dda4087216e15d1784efc310005dd683)中有所提及。虽然该示例可能要求 ax 参数是强制的,但核心思想是相同的:将 Axes 对象作为参数传递。

总结

通过将Matplotlib绘图函数的职责限制在纯粹的绘图操作上,并移除内部的 plt.show() 调用,我们可以有效地解决Sphinx doctest 在遇到交互式图形窗口时的阻塞问题。这种设计模式不仅使测试自动化成为可能,还显著提高了绘图函数的灵活性、可复用性和API的清晰度,是编写高质量Matplotlib库代码的重要实践。开发者应养成习惯,让绘图函数返回 Axes 对象,并将图形的显示或保存逻辑留给调用者处理。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

758

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

639

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

761

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1265

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

548

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

708

2023.08.11

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 3.3万人学习

Django 教程
Django 教程

共28课时 | 3.2万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号