英文:
matplotlib.widgets.TextBox interaction is slow when figure contains several subplots
问题
以下是演示问题的Python代码。
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-0.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()
英文:
Below is python code to demonstrate the problem.<br>
If there are 2 rows and 2 columns of images, for example, typing/erasing in the textbox is reasonably fast. However, if there are 5 rows and 5 columns, typing/erasing in the textbox is quite slow. If the xticks and yticks are drawn, interaction is even slower. So, it seems as if the entire figure is redrawn after every keystroke.<br>
Is there a solution for this (apart from putting the textbox on a separate figure)?<br>
(My development platform is 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()
答案1
得分: 2
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_()
英文:
Matplotlib's TextBox
is inherently slow, because it uses the drawing tools provided by matplotlib itself and hence redraws the complete figure upon changes.
I would propose to use a text box of a GUI kit instead. For example for PyQt this might look like:
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_()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论