Фон
В настоящее время я работаю над проектом, в котором я хочу встроить график matplotlib в pyqt5 GUI. Сюжет является интерактивным и позволяет рисовать закрашенные прямоугольники.
Проблема
Проблема в том, что график не интерактивен, когда он встроен в окно pyqt. Когда я запускаю программу, строка 147 в приведенном ниже коде (plt.show () в классе mplWidget) отображает график matplotlib, и затем я могу нарисовать прямоугольник, как вы можете видеть здесь:
![matplotlib plot](https://i.stack.imgur.com/GHGpE.png)
However, when this window closes and the plot is embedded in the pyqt window, it becomes uneditable
![pyqt uneditable plot](https://i.stack.imgur.com/5ms9v.png)
I want the GUI plot to function as the matplotlib figure does.
Proposed solution / Question
I know that this has to do with the fact that I have to provide the pyqt functionality with connect()
statements, but I don't know where those go / how they would fit in to this program.
I don't know how to connect to a matplotlib. Do I just use connect()
statements to the mplWidget class functions?
Any help is appreciated!
(I realize that I will need to take line 147 out (plt.show()) so that the figure frame does not pop up before the gui, but I just had it temporarily to show that the mpl class still functions as intended, and the problem is that it becomes "static" upon embedding)
Code
import numpy as np
import matplotlib.pyplot as plt
from PyQt5 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import (FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar)
class topLevelWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# Add a central widget to the main window and lay it out in a grid
self.centralwidget = QtWidgets.QWidget(self)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_5 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_5.setObjectName("gridLayout_5")
# Create mainTabs object as well as the displayFrame and displaySettingsFrame that go in the central widget
# Display Frame and Display settings frames
self.displayFrame = QtWidgets.QFrame(self.centralwidget)
self.verticalLayout_22 = QtWidgets.QVBoxLayout(self.displayFrame)
self.verticalLayout_22.setObjectName("verticalLayout_22")
self.gridLayout_5.addWidget(self.displayFrame, 1, 0, 1, 1)
self.devConstructor = mplWidget()
self.dynamic_canvas = FigureCanvasQTAgg(self.devConstructor.fig)
self.verticalLayout_22.addWidget(self.dynamic_canvas)
self._dynamic_ax = self.devConstructor.ax
self.setCentralWidget(self.centralwidget)
# Perform final windows setup (set buddies, translate, tab order, initial tabs, etc)
_translate = QtCore.QCoreApplication.translate
self.setWindowTitle(_translate("MainWindow", "MainWindow")) # Was self.setWindowTitle
QtCore.QMetaObject.connectSlotsByName(self)
self.show()
class mplWidget(QtWidgets.QWidget): # n.b. changed this from Object to QWidget and added a super()
def setSnapBase(self, base):
return lambda value: int(base*round(float(value)/base))
def onclick(self, event):
if self.plotSnap is False:
self.bottomLeftX = event.xdata
self.bottomLeftY = event.ydata
else:
self.calculateSnapCoordinates = self.setSnapBase(self.plotSnap)
self.bottomLeftX = self.calculateSnapCoordinates(event.xdata)
self.bottomLeftY = self.calculateSnapCoordinates(event.ydata)
try:
self.aspan.remove()
except:
pass
self.moving = True
def onrelease(self, event):
if self.plotSnap is False:
self.topRightX = event.xdata
self.topRightY = event.ydata
else:
try:
calculateSnapCoordinates = self.setSnapBase(self.plotSnap)
self.topRightX = calculateSnapCoordinates(event.xdata)
self.topRightY = calculateSnapCoordinates(event.ydata)
except:
pass
self.x = np.array([self.bottomLeftX, self.bottomLeftX, self.topRightX, self.topRightX, self.bottomLeftX])
self.y = np.array([self.bottomLeftY, self.topRightY, self.topRightY, self.bottomLeftY, self.bottomLeftY])
self.myPlot.set_xdata(self.x)
self.myPlot.set_ydata(self.y)
# ax.fill_between(x, y, color=defaultColors[0, :], alpha=.25)
ylimDiff = self.ax.get_ylim()[1] - self.ax.get_ylim()[0]
self.aspan = self.ax.axvspan(self.bottomLeftX, self.topRightX,
(self.bottomLeftY-self.ax.get_ylim()[0])/ylimDiff,
(self.topRightY-self.ax.get_ylim()[0])/ylimDiff,
color=self.defaultColors[0, :], alpha=.25)
self.moving = False
self.fig.canvas.draw()
def onmotion(self, event):
if self.moving is False:
return
if event.inaxes is None:
return
if event.button != 1:
return
if self.plotSnap is False:
self.topRightX = event.xdata
self.topRightY = event.ydata
else:
self.calculateSnapCoordinates = self.setSnapBase(self.plotSnap)
self.topRightX = self.calculateSnapCoordinates(event.xdata)
self.topRightY = self.calculateSnapCoordinates(event.ydata)
self.x = np.array([self.bottomLeftX, self.bottomLeftX, self.topRightX, self.topRightX, self.bottomLeftX])
self.y = np.array([self.bottomLeftY, self.topRightY, self.topRightY, self.bottomLeftY, self.bottomLeftY])
self.myPlot.set_xdata(self.x)
self.myPlot.set_ydata(self.y)
self.fig.canvas.draw()
def __init__(self):
super(mplWidget, self).__init__()
# Set default colors array
self.defaultColors = np.array([[0, 0.4470, 0.7410], [0.8500, 0.3250, 0.0980], [0.9290, 0.6940, 0.1250],
[0.4660, 0.6740, 0.1880], [0.6350, 0.0780, 0.1840], [0.4940, 0.1840, 0.5560],
[0.3010, 0.7450, 0.9330]])
# Create a figure with axes
self.fig = plt.figure()
self.ax = self.fig.gca()
# Form the plot and shading
self.bottomLeftX = 0; self.bottomLeftY = 0; self.topRightX = 0; self.topRightY = 0
self.x = np.array([self.bottomLeftX, self.bottomLeftX, self.topRightX, self.topRightX, self.bottomLeftX])
self.y = np.array([self.bottomLeftY, self.topRightY, self.topRightY, self.bottomLeftY, self.bottomLeftY])
self.myPlot, = self.ax.plot(self.x, self.y, color=self.defaultColors[0, :])
self.aspan = self.ax.axvspan(self.bottomLeftX, self.topRightX, color= self.defaultColors[0, :], alpha=0)
# Set moving flag false (determines if mouse is being clicked and dragged inside plot). Set graph snap
self.moving = False
self.plotSnap = 5
# Set up connectivity
self.cid = self.fig.canvas.mpl_connect('button_press_event', self.onclick)
self.cid = self.fig.canvas.mpl_connect('button_release_event', self.onrelease)
self.cid = self.fig.canvas.mpl_connect('motion_notify_event', self.onmotion)
# Set plot limits and show it
plt.ylim((-100, 100))
plt.xlim((-100, 100))
plt.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = topLevelWindow()
sys.exit(app.exec_())