当交互式绘图在后台运行时如何防止 Python 中的垃圾收集(Python,matplotlib)?

How to prevent garbage collection in Python when an interactive plot runs in the background (Python, matplotlib)?

我有一个使用 matplotlib 和 Button 小部件的代码。 一切正常,但是当将此代码编写为函数时,按钮停止工作。 这是因为函数运行后,按钮对象将被垃圾收集器删除。

这里有一个 代码不能正常工作的例子:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

def fun():
    def Prev(x):
        print("Prev")
    def Next(x):
        print("Next")

    freqs = np.arange(2, 20, 3)
    fig, ax = plt.subplots()
    plt.subplots_adjust(bottom=0.2)
    t = np.arange(0.0, 1.0, 0.001)
    s = np.sin(2*np.pi*freqs[0]*t)
    l, = plt.plot(t, s, lw=2)
    axprev = plt.axes([0.7, 0.05, 0.1, 0.075])
    axnext = plt.axes([0.81, 0.05, 0.1, 0.075])
    bnext = Button(axnext, 'Next')
    bnext.on_clicked(Next)
    bprev = Button(axprev, 'Previous')
    bprev.on_clicked(Prev)

fun()

这是我的不太优雅的解决方案

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

def fun():
    def Prev(x):
        print("Prev")
    def Next(x):
        print("Next")

    freqs = np.arange(2, 20, 3)
    fig, ax = plt.subplots()
    plt.subplots_adjust(bottom=0.2)
    t = np.arange(0.0, 1.0, 0.001)
    s = np.sin(2*np.pi*freqs[0]*t)
    l, = plt.plot(t, s, lw=2)
    axprev = plt.axes([0.7, 0.05, 0.1, 0.075])
    axnext = plt.axes([0.81, 0.05, 0.1, 0.075])
    bnext = Button(axnext, 'Next')
    bnext.on_clicked(Next)
    bprev = Button(axprev, 'Previous')
    bprev.on_clicked(Prev)
    return bnext,bprev

b1,b2=fun()

对于此类问题是否有更好的最佳实践解决方案?

正如您正确假设的那样,关键是在外部范围内保持对按钮的引用。如果您不想 return 按钮集合,您可以将按钮添加为图形的属性。对于仅绘制一个图形这样的事情,我不会说有最佳实践,对于更复杂的 UI,可能会有更好的解决方案。但是此代码解决了这个特定问题,而无需显式 returning 按钮引用。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button
import  matplotlib
matplotlib.use("TkAgg")


def fun():
    def Prev(x):
        print("Prev")
    def Next(x):
        print("Next")

    freqs = np.arange(2, 20, 3)
    fig, ax = plt.subplots()
    plt.subplots_adjust(bottom=0.2)
    t = np.arange(0.0, 1.0, 0.001)
    s = np.sin(2*np.pi*freqs[0]*t)
    l, = plt.plot(t, s, lw=2)
    axprev = plt.axes([0.7, 0.05, 0.1, 0.075])
    axnext = plt.axes([0.81, 0.05, 0.1, 0.075])
    bnext = Button(axnext, 'Next')
    bnext.on_clicked(Next)
    bprev = Button(axprev, 'Previous')
    bprev.on_clicked(Prev)
    fig.bnext = bnext    # add button references to figure object
    fig.bprev = bprev


if __name__ == "__main__":
    fun()
    plt.show()