![](/img/trans.png)
[英]PyQt4 How to draw border around embedded Matplotlib FigureCanvas
[英]Matplotlib callbacks don't work when matplotlib.FigureCanvas is embedded in a PyQt5 application?
Prithee,StackOverflow 的干癟長老,
我正在嘗試使用 PyQt5 制作一個小型 GUI 應用程序,將 matplotlib.FigureCanvas 對象用作小部件來顯示數據,我還想通過使用 matplotlib 的回調函數使數據更具交互性。 但是,這些回調似乎不適用於嵌入在 PyQt5 窗口中的 FigureCanvas。
我認為實例化 Qt5 應用程序可能會干擾 matplotlib 的事件處理程序,但我不確定如何繼續。 有沒有辦法讓 matplotlib 事件引發 Qt5 信號? 我可以有兩個單獨的線程,兩個事件處理程序都可以在其中運行嗎?
下面的示例是我可以縮減的最簡單的事情,它說明了這個問題。
案例 A:在 Matplotlib 窗口中運行
首先按原樣運行,注意所需的行為: onclick
函數在圖形彈出后在單擊時調用。 (還要注意第二個代碼塊,案例 B 不會在第一個之后運行)
案例 B:在 PyQt5 中運行
現在,注釋掉 Case A 代碼塊,然后運行:點擊圖中沒有調用回調函數。
import sys
import numpy as np
from PyQt5 import QtCore, QtWidgets, uic
import matplotlib
matplotlib.use('QT5Agg')
import matplotlib.pylab as plt
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
matplotlib.rcParams["toolbar"] = "toolmanager"
def onclick(event):
'''example callback function'''
print('got click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
( event.button, event.x, event.y, event.xdata, event.ydata))
class MPLWidget(QtWidgets.QWidget):
'''
Widget which should act like a matplotlib FigureCanvas, but embedded in PyQt5
'''
def __init__(self, parent=None, **kwargs):
super().__init__(parent, **kwargs)
# Making Matplotlib figure object with data
fig, ax = plt.subplots()
fig.suptitle("Plot in PyQt5: click and look in console")
ax.plot(np.linspace(0,1,2))
# Attaching matplotlib callback function which doesnt seem to work
cid = fig.canvas.mpl_connect('button_press_event', onclick)
self.layout = QtWidgets.QVBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.plotWidget = FigureCanvas(fig)
self.toolbar = NavigationToolbar(self.plotWidget, self)
self.layout.addWidget(self.toolbar)
self.layout.addWidget(self.plotWidget)
class TestWindow(QtWidgets.QMainWindow):
'''Window which is a stand in for the larger PyQt5 application which needs a plot embedded'''
def __init__(self):
super().__init__()
self.mplwidget = MPLWidget(self)
self.setCentralWidget(self.mplwidget)
if __name__ == '__main__':
# Case A: Using matplotlib without PyQt5,
# Note that the callback is triggered and something is printed when you click in the figure
fig, ax = plt.subplots()
fig.suptitle("Standalone matplotlib: click and look in console")
ax.plot(np.linspace(0,1,2))
cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()
# Case B: Running PyQt5 + Matplotlib widget
# Note that nothing is printed when you click in the figure
app = QtWidgets.QApplication(sys.argv)
window = TestWindow()
window.show()
sys.exit(app.exec_())
如果您要使用 pyqt5 中的 FigureCanvas,則不必使用“plt”,而是使用 Figure() 進行構建,如官方示例所示:
import sys
import numpy as np
from PyQt5 import QtCore, QtWidgets
import matplotlib
matplotlib.use("QT5Agg")
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
matplotlib.rcParams["toolbar"] = "toolmanager"
from matplotlib.figure import Figure
def onclick(event):
"""example callback function"""
print(
"got click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f"
% (event.button, event.x, event.y, event.xdata, event.ydata)
)
class MPLWidget(QtWidgets.QWidget):
"""
Widget which should act like a matplotlib FigureCanvas, but embedded in PyQt5
"""
def __init__(self, parent=None, **kwargs):
super().__init__(parent, **kwargs)
# Making Matplotlib figure object with data
self.canvas = FigureCanvas(Figure())
ax = self.canvas.figure.add_subplot(111)
ax.set_title("Plot in PyQt5: click and look in console")
ax.plot(np.linspace(0, 1, 2))
cid = self.canvas.mpl_connect("button_press_event", onclick)
self.layout = QtWidgets.QVBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.toolbar = NavigationToolbar(self.canvas, self)
self.layout.addWidget(self.toolbar)
self.layout.addWidget(self.canvas)
class TestWindow(QtWidgets.QMainWindow):
"""Window which is a stand in for the larger PyQt5 application which needs a plot embedded"""
def __init__(self):
super().__init__()
self.mplwidget = MPLWidget(self)
self.setCentralWidget(self.mplwidget)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = TestWindow()
window.show()
sys.exit(app.exec_())
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.