matplotlib.widgets.TextBox 当图包含多个子图时交互很慢

matplotlib.widgets.TextBox interaction is slow when figure contains several subplots

下面是 python 演示问题的代码。
如果有 2 行和 2 列的图像,例如,文本框中的 typing/erasing 是相当快的。但是,如果有 5 行和 5 列,文本框中的 typing/erasing 是相当慢的。如果绘制 xticks 和 yticks,交互甚至更慢。所以,好像整个图形在每次击键后都会重新绘制。
是否有解决方案(除了将文本框放在单独的图形上)?
(我的开发平台是 MacOS Mojave,Python 3.7.5。)

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from matplotlib.widgets import TextBox

class Textbox_Demo(object):
    def __init__(self):
        self.fig = plt.figure(figsize=(8,8))
        self.string = 'label'

        self.rows = 5   # reducing rows speeds up textbox interaction
        self.cols = 5   # reducing cols speeds up textbox interaction
        self.plot_count = self.rows * self.cols
        self.gs = gridspec.GridSpec(self.rows, self.cols,
            left=0.05, right=1-0.02, top=1-.02,  bottom=0.10, wspace=0.3, hspace=0.4)
        for k in range(self.plot_count):
            ax = self.fig.add_subplot(self.gs[k])
            #ax.set_xticks([])  # showing axes slows textbox interaction
            #ax.set_yticks([])  # showing axes slows textbox interaction
            data = np.atleast_2d(np.sin(np.linspace(1,255,255) * 50))
            ax.imshow(data, aspect="auto", cmap='ocean')

        # this is the user-input textbox
        tb_axis = plt.axes([0.125, 0.02, 0.8, 0.05])
        self.tb = TextBox(tb_axis, 'Enter label:', initial=self.string, label_pad=0.01)
        self.tb.on_submit(self.on_submit)

        plt.show()

    def on_submit(self, text):
        pass

if __name__ == "__main__":
    Textbox_Demo()

Matplotlib 的TextBox 本身就很慢,因为它使用了matplotlib 本身提供的绘图工具,因此在更改时重新绘制完整的图形。

我建议改用 GUI 工具包的文本框。例如对于 PyQt 这可能看起来像:

import numpy as np
import sys
from matplotlib.backends.backend_qt5agg import (
        FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.backends.qt_compat import QtCore, QtWidgets
import matplotlib.gridspec as gridspec
from matplotlib.figure import Figure


class Textbox_Demo(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self._main = QtWidgets.QWidget()
        self.setCentralWidget(self._main)
        layout = QtWidgets.QVBoxLayout(self._main)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(0)

        self.fig = Figure(figsize=(8,8))
        self.canvas = FigureCanvas(self.fig)
        layout.addWidget(self.canvas)
        self.addToolBar(NavigationToolbar(self.canvas, self))

        self._textwidget = QtWidgets.QWidget()
        textlayout = QtWidgets.QHBoxLayout(self._textwidget)
        self.textbox = QtWidgets.QLineEdit(self)
        self.textbox.editingFinished.connect(self.on_submit)
        # or, if wanting to have changed apply directly:
        # self.textbox.textEdited.connect(self.on_submit)
        textlayout.addWidget(QtWidgets.QLabel("Enter Text: "))
        textlayout.addWidget(self.textbox)
        layout.addWidget(self._textwidget)

        self.fill_figure()

    def fill_figure(self):
        self.string = 'label'

        self.rows = 5   # reducing rows speeds up textbox interaction
        self.cols = 5   # reducing cols speeds up textbox interaction
        self.plot_count = self.rows * self.cols
        self.gs = gridspec.GridSpec(self.rows, self.cols,
            left=0.05, right=1-0.02, top=1-.02,  bottom=0.10, wspace=0.3, hspace=0.4)
        for k in range(self.plot_count):
            ax = self.fig.add_subplot(self.gs[k])
            #ax.set_xticks([])  # showing axes slows textbox interaction
            #ax.set_yticks([])  # showing axes slows textbox interaction
            data = np.atleast_2d(np.sin(np.linspace(1,255,255) * 50))
            ax.imshow(data, aspect="auto", cmap='ocean')

    def on_submit(self):
        text = self.textbox.text()
        print(text)
        pass


if __name__ == "__main__":
    qapp = QtWidgets.QApplication(sys.argv)
    app = Textbox_Demo()
    app.show()
    qapp.exec_()