You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决关闭Matplotlib子图后主图停止更新的问题?

问题

我写了一段Python脚本,用Matplotlib实现了一个能循环持续更新的主图。主图窗口里设置了按钮,点击后会弹出第二个子图,子图打开期间主图能正常更新,但关闭子图后,主图的更新循环会意外停止;更奇怪的是,关闭主图窗口后,更新循环又会恢复。请问怎么实现关闭子图后主图仍持续更新?

附上代码:

import sys
import time
import numpy as np
import random
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

def main():
    # Create a figure and axis that we will display the main window on
    fig, ax = plt.subplots()
 
    ax_pop = fig.add_axes([0.2, 0.14, 0.2, 0.04])

    pop_up_window_button = Button(ax=ax_pop, label='Open second window', hovercolor='0.975')

    # A callback function for the button press event
    def pop_up_window(event):
        """
        Pop up a second window
        """
        # Plot some random values to a matplotlib graph
        print("Plotting some more random values in second window")
        x = [random.randint(1, 100) for n in range(100)]
        y = [random.randint(1, 100) for n in range(100)]
        fig1, ax1 = plt.subplots()
        ax1.scatter(x, y) 
        ax1.axis('off')

        plt.pause(0.1)  # Need to pause to allow the image to be displayed


    # Add a callback to the button press event
    pop_up_window_button.on_clicked(pop_up_window)

    live_view = True
    while live_view:
        # Plot some random values to a matplotlib graph
        print("Plotting some random values")
        x = [random.randint(1, 100) for n in range(100)]
        y = [random.randint(1, 100) for n in range(100)]
        ax.clear() 
        ax.scatter(x, y) 
        ax.axis('off')
        ax.set_title('Live view') 

        plt.pause(0.01) # Need to pause to allow the image to be displayed
        time.sleep(1)



    print('Done')

    return True

# Main entry point of script
if __name__ == '__main__':
    if main():
        sys.exit(0)
    else:
        sys.exit(1)

控制台输出示例:

Plotting some random values
Plotting some random values
Plotting some random values
Plotting some random values
Plotting some random values
Plotting some random values
Plotting some more random values in second window  < 这里点击了按钮>
Plotting some random values
Plotting some random values
Plotting some random values
< 关闭第二个图后,控制台输出暂停,主图停止更新
....
....
关闭主图窗口后,控制台输出又开始了>
Plotting some random values  
Plotting some random values
Plotting some random values
Plotting some random values
Plotting some random values

解决方案

问题根源

关闭子图时,全局的plt.pause()会陷入阻塞状态——Matplotlib的事件循环在子图关闭后出现异常,导致主循环里的plt.pause()无法正常执行,直到主窗口关闭才释放阻塞。

修改方案

  1. 为子图添加关闭事件回调,清理引用并避免干扰主图事件循环;
  2. 用窗口独立的fig.canvas.draw()+fig.canvas.flush_events()替代全局的plt.pause(),避免全局状态冲突;
  3. 主循环通过检查主图是否存在来控制终止,替代固定的live_view变量。

修改后的代码

import sys
import time
import random
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

def main():
    # 创建主图窗口
    fig, ax = plt.subplots()
    ax_pop = fig.add_axes([0.2, 0.14, 0.2, 0.04])
    pop_up_window_button = Button(ax=ax_pop, label='打开子图', hovercolor='0.975')

    def pop_up_window(event):
        print("在子图中绘制随机数据")
        x = [random.randint(1, 100) for _ in range(100)]
        y = [random.randint(1, 100) for _ in range(100)]
        # 创建子图
        fig1, ax1 = plt.subplots()
        ax1.scatter(x, y)
        ax1.axis('off')
        
        # 子图关闭时的回调,清理引用并确保事件循环正常
        def on_subplot_close(evt):
            nonlocal fig1, ax1
            fig1 = None
            ax1 = None
        
        fig1.canvas.mpl_connect('close_event', on_subplot_close)
        # 独立绘制子图并刷新事件
        fig1.canvas.draw()
        fig1.canvas.flush_events()

    pop_up_window_button.on_clicked(pop_up_window)

    # 主更新循环
    while True:
        # 检查主图是否已关闭,若关闭则终止循环
        if not plt.fignum_exists(fig.number):
            break
        
        print("更新主图数据")
        x = [random.randint(1, 100) for _ in range(100)]
        y = [random.randint(1, 100) for _ in range(100)]
        ax.clear()
        ax.scatter(x, y)
        ax.axis('off')
        ax.set_title('实时视图')
        
        # 独立绘制主图并刷新事件,替代全局plt.pause()
        fig.canvas.draw()
        fig.canvas.flush_events()
        time.sleep(1)

    print('程序结束')
    return True

if __name__ == '__main__':
    if main():
        sys.exit(0)
    else:
        sys.exit(1)

关键说明

  • 窗口独立的绘制逻辑:每个窗口用自己的canvas.draw()和flush_events()处理绘制和事件,避免全局plt状态的冲突;
  • 子图关闭回调:清理子图引用,防止事件循环出现异常;
  • 主循环终止条件:通过plt.fignum_exists()检查主图是否存在,确保主窗口关闭时循环正常终止。

内容的提问来源于stack exchange,提问作者Diarmaid O Cualain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:25:38