I am willing to integrate a matplotlib figure into a GUI designed with pyqt5:
I wrote the code above:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
import random
class Ui_MainWindow(QMainWindow):
def setupUi(self, MainWindow):
self.vbox = QtWidgets.QVBoxLayout()
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1056, 600)
self.vbox2 = MainWindow.layout()
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.lineEdit_x = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_x.setGeometry(QtCore.QRect(550, 430, 40, 20))
self.lineEdit_x.setObjectName("lineEdit_x")
self.lineEdit_x.setText(str(1))
self.lineEdit_y = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_y.setGeometry(QtCore.QRect(595, 430, 40, 20))
self.lineEdit_y.setObjectName("lineEdit_y")
self.lineEdit_y.setText(str(1))
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(490, 430, 66, 13))
self.label_3.setObjectName("label_3")
self.figure = plt.figure()#figsize=(40, 10), dpi=18)
self.canvas = FigureCanvas(self.figure)
#self.canvas.mpl_connect("button_release_event", self.on_release)
self.canvas.mpl_connect("button_press_event", self.on_press)
self.canvas.setGeometry(QtCore.QRect(0,30, 400, 400))
self.toolbar = NavigationToolbar(self.canvas, self)
self.vbox2.addWidget(self.toolbar)
self.vbox2.addWidget(self.canvas)
self.plot()
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1056, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def plot(self):
data = [random.random() for i in range(23)]
ax = self.figure.add_subplot(111)
ax.plot(data, 'r-', linewidth=0.5)
ax.set_title('PyQt Matplotlib Example')
self.canvas.draw()
def on_press(self, event):
self.lineEdit_x.setText(str(event.x))
self.lineEdit_y.setText(str(event.y))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_3.setText(_translate("MainWindow", "Center (x,y)"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
as one can see I have 2 issues:
the menu bar is detached from the figure and reduced
the axes are smaller than the figure field.
so can someone please check my code to address these two issues with minimum modifications
thanks
There are many issues with your code, and most of them are caused by the fact that you're editing a pyuic file, which is considered a bad practice, and one of the many reasons of that consideration is that the class pyuic provides is often being used in the wrong way, like in this case.
First of all, you're creating instances for both QMainWindow and Ui_MainWindow, which already inherits from QMainWindow, so the first one is completely pointless.
Then, you're trying to access the main window layout, but that's also wrong, as QMainWindow has its own private layout. The only proper way to add widgets to a main window is using the provided API, and, in your case:
setCentralWidget() to set the central widget, which is the main content of the window, and set its layout to which the actual widgets are being added;
addToolBar() to add tool bars;
So, this is a proper rewriting of your expected result.
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.resize(1056, 600)
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.canvas.mpl_connect('button_press_event', self.on_press)
self.toolbar = NavigationToolbar(self.canvas, self)
self.addToolBar(self.toolbar)
self.label = QtWidgets.QLabel('Center (x,y)')
self.lineEdit_x = QtWidgets.QLineEdit()
self.lineEdit_x.setText(str(1))
self.lineEdit_y = QtWidgets.QLineEdit()
self.lineEdit_y.setText(str(1))
central = QtWidgets.QWidget(self)
self.setCentralWidget(central)
mainLayout = QtWidgets.QVBoxLayout(central)
mainLayout.addWidget(self.canvas)
bottomLayout = QtWidgets.QHBoxLayout()
mainLayout.addLayout(bottomLayout)
bottomLayout.addWidget(self.label)
bottomLayout.addWidget(self.lineEdit_x)
bottomLayout.addWidget(self.lineEdit_y)
self.plot()
def plot(self):
data = [random.random() for i in range(23)]
ax = self.figure.add_subplot(111)
ax.plot(data, 'r-', linewidth=0.5)
ax.set_title('PyQt Matplotlib Example')
self.canvas.draw()
def on_press(self, event):
self.lineEdit_x.setText(str(event.x))
self.lineEdit_y.setText(str(event.y))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
Note that if you still want to use Designer, then keep in mind that:
as said above, you should not edit the pyuic generated file (but, instead, follow the official guidelines about using Designer;
add the canvas by code, or use a promoted widget (do some research on the subject);
always use layout managers for all widgets;
Related
I'm currently learning how can I use pyqt5 with matplotlib together so implement this code which will popup after I press a pushbutton in another window
I create another class called canvas in order to create multiple graphs in the future like bar chart and histogram
when I run this code the windows will appear and the pushButton also will appear but not the canvas that I did create
how can I show the canvas ( pie chart ) in the main window
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
import PyQt5
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
class window(QtWidgets.QMainWindow):
def setupUi(self,Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(900, 500)
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(0, 380, 141, 61))
self.pushButton.setObjectName("pushButton")
self.canvas = Canvas(self, width=8, height=4)
self.canvas.move(0,0)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "output window"))
class Canvas(FigureCanvas):
def __init__(self, parent = None, width = 5, height = 5, dpi = 100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self.plot()
def plot(self):
x = np.array([50, 30,40])
labels = ["Apples", "Bananas", "Melons"]
ax = self.figure.add_subplot(111)
ax.pie(x, labels=labels)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = window()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
The problem is caused because you are modifying the code generated by Qt Designer without understanding the consequences of it. The class generated by QtDesigner is not the window but a class that just populates the window. For example in your case with the window modification it is QMainWindow that has the canvas but you have created another widget called Dialog which is the one you show (if you check the QPushButton it is a child of Dialog so it is also shown). On the other hand, you only have to create a single axes.
Therefore, you should not modify the class generated by QtDesigner but rather create another class that inherits from a widget, and use the previous class to fill it.
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
import PyQt5
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
class Ui_Dialog:
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(900, 500)
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(0, 380, 141, 61))
self.pushButton.setObjectName("pushButton")
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "output window"))
class Canvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=5, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self.plot()
def plot(self):
x = np.array([50, 30, 40])
labels = ["Apples", "Bananas", "Melons"]
self.axes.pie(x, labels=labels)
self.draw()
class Dialog(QtWidgets.QDialog, Ui_Dialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.canvas = Canvas(self, width=8, height=4)
self.canvas.move(0, 0)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())
Using the code below, I can plot basic matplotlib plots in a gui designed in pyqt5 (such as giving it a list of xs and ys and it plots the points). However, I cannot plug in advanced modules such as seaborn or networkx (lets focus on seaborn) that utilize the plotting functionality of matplotlib to display the data you generate with the functions.
from PyQt5 import QtCore, QtGui, QtWidgets
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.widget = MplWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(200, 110, 391, 311))
self.widget.setObjectName("widget")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(250, 40, 231, 61))
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(50, 180, 113, 32))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.pushButton.clicked.connect(self.Graphitdude)
def Graphitdude(self):
Lister3 = pd.read_csv("Betadata.csv",index_col=[0])#just a collection of labels and assorted correlation values ranging from 0 to 1 to be constructed into a heatmap.
plot = sns.heatmap(Lister3) # This is the problematic function, it does it, and I can display it IN LINE but not in the gui canvas?
plt.yticks(rotation=0)
self.widget.canvas.ax.plot()#if passed discreet x and y values, it graphs it, but it doesnt like to pass the seaborn figure?
self.widget.canvas.draw()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:24pt; font-weight:600;\">Test</span></p></body></html>"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
from mplwidget import MplWidget
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
mplwidget.py is as follows:
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
import matplotlib
matplotlib.use('QT5Agg')
# Matplotlib canvas class to create figure
class MplCanvas(Canvas):
def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
Canvas.__init__(self, self.fig)
Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
Canvas.updateGeometry(self)
# Matplotlib widget
class MplWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent) # Inherit from QWidget
self.canvas = MplCanvas() # Create canvas object
self.vbl = QtWidgets.QVBoxLayout() # Set box for plotting
self.vbl.addWidget(self.canvas)
self.setLayout(self.vbl)
My best idea is that these functions are designing their own matplotlib figure (or subplot, not sure), and this figure cannot be supplied to the widget code by the methods I have tried.
sns.heatmap(xxxx) returns "ax", which should be able to be used by the mplwidget.py script, right? Can I pass these to the canvas to display seaborn graphics?
According to the documentation:
seaborn.heatmap(data, vmin=None, vmax=None, cmap=None, center=None, robust=False, annot=None, fmt='.2g', annot_kws=None, linewidths=0, linecolor='white', cbar=True, cbar_kws=None, cbar_ax=None, square=False, xticklabels='auto', yticklabels='auto', mask=None, ax=None, **kwargs)
[...]
ax : matplotlib Axes, optional
Axes in which to draw the plot, otherwise use the currently-active Axes.
So then you should just pass the AxesSubplot of MplCanvas as parameter ax:
def Graphitdude(self):
Lister3 = pd.read_csv("Betadata.csv",index_col=[0])
plot = sns.heatmap(Lister3, ax=self.widget.canvas.ax)
plt.yticks(rotation=0)
self.widget.canvas.draw()
I have used many functions similar to heatmap and always provide that parameter.
I built a Matplotlib GUI with Qt Designer basically following this tutorial. I am using python 3.5.2 and pyqt 5.6.0 . The code you can see below is working. However when changing the plots the memory used by my system increases, at least according to Windows 10 Task Manager. To recreate this a little better one can increase the number of random values used in the plot commands.
It seems like the self.canvas.close() command inside the rmmppl function is not enough to actually free the used memory.
How can I prevent the increasing memory usage?
edit: here is a Screenshot of the GUI
from PyQt5 import QtCore, QtGui, QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
import window
import numpy as np
class Plotter(QtWidgets.QMainWindow, window.Ui_MainWindow):
def __init__(self):
super(Plotter, self).__init__()
self.setupUi(self)
self.fig_dict = {}
self.mplfigs.itemClicked.connect(self.changefig)
def addmpl(self, fig):
self.canvas = FigureCanvas(fig)
self.mplvl.addWidget(self.canvas)
self.canvas.draw()
self.toolbar = NavigationToolbar(self.canvas,self.mplwindow, coordinates = True)
self.mplvl.addWidget(self.toolbar)
def rmmppl(self):
self.mplvl.removeWidget(self.canvas)
self.canvas.close()
self.mplvl.removeWidget(self.toolbar)
self.toolbar.close()
def addfig(self, name, fig):
self.fig_dict[name]=fig
self.mplfigs.addItem(name)
def changefig(self,item):
text = item.text()
self.rmmppl()
self.addmpl(self.fig_dict[text])
def main():
import sys
fig1 = Figure()
ax1f1= fig1.add_subplot(111)
ax1f1.plot(np.random.rand(5))
fig2 = Figure()
ax1f2 = fig2.add_subplot(121)
ax1f2.plot(np.random.rand(5))
ax1f2 = fig2.add_subplot(122)
ax1f2.plot(np.random.rand(10))
app=QtWidgets.QApplication(sys.argv)
main=Plotter()
main.addmpl(fig1)
main.addfig('Figure 1', fig1)
main.addfig('Figure 2', fig2)
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The window.py which is the Basic GUI structure:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 432)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.mplwindow = QtWidgets.QWidget(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mplwindow.sizePolicy().hasHeightForWidth())
self.mplwindow.setSizePolicy(sizePolicy)
self.mplwindow.setObjectName("mplwindow")
self.mplvl = QtWidgets.QVBoxLayout(self.mplwindow)
self.mplvl.setContentsMargins(0, 0, 0, 0)
self.mplvl.setObjectName("mplvl")
self.horizontalLayout.addWidget(self.mplwindow)
self.mplfigs = QtWidgets.QListWidget(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mplfigs.sizePolicy().hasHeightForWidth())
self.mplfigs.setSizePolicy(sizePolicy)
self.mplfigs.setMaximumSize(QtCore.QSize(200, 16777215))
self.mplfigs.setMinimumSize(QtCore.QSize(200, 0))
self.mplfigs.setObjectName("mplfigs")
self.horizontalLayout.addWidget(self.mplfigs)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 31))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
I have executed your code on Linux and I have observed the same memory leak.
Try with this:
Import the garbage collector with:
import gc
Then modify your rmmppl method:
def rmmppl(self):
self.canvas.close()
self.canvas.deleteLater()
self.toolbar.close()
self.toolbar.deleteLater()
gc.collect()
Here is the documentation for deleteLater QObject Class Documentation
I'm new in Python and I want to developp a GUI program.
I have installed pythonxy and I have developped a QT4 GUI that I have transformed in py with pyuic4.
In my program, I would like to update the mplwidget with new variables when I click on the button. I would like to update only the widget without restart the ui. How can I modify the solution below in order to update only the widget.
Thank you very much for your help and indications
from PyQt4 import QtCore, QtGui
from matplotlibwidget import MatplotlibWidget
import numpy as np
global y
global x
x=[1,2,3]
y=[1, 2, 1]
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.mplwidget = MatplotlibWidget(self.centralwidget)
self.mplwidget.setGeometry(QtCore.QRect(170, 150, 400, 300))
self.mplwidget.setObjectName("mplwidget")
self.mplwidget.setFocus()
self.mplwidget.axes.plot(x,y)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.pushButton = QtGui.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(170, 60, 75, 23))
self.pushButton.setObjectName("pushButton")
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), self.plot)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def plot(self):
global y
global x
x = [2,3,4]
y = [2,2,1]
self.replot()
def replot(self):
Ui_MainWindow()
ui.setupUi(MainWindow)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
I am not familiar with matplotlibwidget, so there may be an easier way to do this, but you can grab the Axes object and do what ever you want to it:
def replot_(self, x, y):
# plot the data and keep a reference to the `Line2D` object
ln, = self.matplotlibwidget.axes.plot(x, y)
# force the canvas to re-draw,
# matplotlibwidget may provide more direct access to the canvas
self.matplotlibwidget.axes.figure.canvas.draw()
return ln
What is the best way to embed an interactive 3D plot in a PySide GUI? I have looked at some examples on here of 2D plots embedded in a PySide GUI:
Getting PySide to Work With Matplotlib
Matplotlib Interactive Graph Embedded In PyQt
Python/Matplotlib/Pyside Fast Timetrace Scrolling
However, the functionality that I'm looking for is not quite the same. The figure needs to rotate and zoom based on mouse input from the user in the same way as if it were drawn in a separate window.
I'm trying to avoid having to go in manually and write functions for transforming mouse click + move into a figure rotate and canvas repaint--even if that's the only way, I'm not even sure how to do that. But I figure (no pun intended) that there should be a way to reuse the functionality already present for creating 3D plots in their own windows.
Here's my code. It works as intended, but the plot is not interactive. Any advice is appreciated!
EDIT: I fixed the use of FigureCanvas according to tcaswell's corrections. I also added a bit from the matplotlib Event Handling and Picking documentation to show that the figure seems to be getting the events upon mouseclick.
Final Edit: The following code now produces the plot as desired.
# -*- coding: utf-8 -*-
from PySide import QtCore, QtGui
import numpy as np
import matplotlib
import sys
# specify the use of PySide
matplotlib.rcParams['backend.qt4'] = "PySide"
# import the figure canvas for interfacing with the backend
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg \
as FigureCanvas
# import 3D plotting
from mpl_toolkits.mplot3d import Axes3D # #UnusedImport
from matplotlib.figure import Figure
# Auto-generated code from QT Designer ----------------------------------------
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(750, 497)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout_2 = QtGui.QHBoxLayout(self.centralwidget)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.frame_2 = QtGui.QFrame(self.centralwidget)
self.frame_2.setFrameShape(QtGui.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtGui.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.verticalLayout = QtGui.QVBoxLayout(self.frame_2)
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtGui.QLabel(self.frame_2)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.label_2 = QtGui.QLabel(self.frame_2)
self.label_2.setObjectName("label_2")
self.verticalLayout.addWidget(self.label_2)
self.lineEdit = QtGui.QLineEdit(self.frame_2)
sizePolicy = QtGui.QSizePolicy(
QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(
self.lineEdit.sizePolicy().hasHeightForWidth())
self.lineEdit.setSizePolicy(sizePolicy)
self.lineEdit.setObjectName("lineEdit")
self.verticalLayout.addWidget(self.lineEdit)
spacerItem = QtGui.QSpacerItem(
20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout_2.addWidget(self.frame_2)
self.frame_plot = QtGui.QFrame(self.centralwidget)
self.frame_plot.setMinimumSize(QtCore.QSize(500, 0))
self.frame_plot.setFrameShape(QtGui.QFrame.StyledPanel)
self.frame_plot.setFrameShadow(QtGui.QFrame.Raised)
self.frame_plot.setObjectName("frame_plot")
self.horizontalLayout_2.addWidget(self.frame_plot)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QtGui.QApplication.translate(
"MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.label.setText(QtGui.QApplication.translate("MainWindow",
"This is a qlabel.", None, QtGui.QApplication.UnicodeUTF8))
self.label_2.setText(QtGui.QApplication.translate("MainWindow",
"And this is another one.", None, QtGui.QApplication.UnicodeUTF8))
self.lineEdit.setText(QtGui.QApplication.translate("MainWindow",
"Text goes here.", None, QtGui.QApplication.UnicodeUTF8))
# Auto-generated code from QT Designer ----------------------------------------
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
# intialize the window
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# create the matplotlib widget and put it in the frame on the right
self.ui.plotWidget = Mpwidget(parent=self.ui.frame_plot)
class Mpwidget(FigureCanvas):
def __init__(self, parent=None):
self.figure = Figure(facecolor=(0, 0, 0))
super(Mpwidget, self).__init__(self.figure)
self.setParent(parent)
# plot random 3D data
self.axes = self.figure.add_subplot(111, projection='3d')
self.data = np.random.random((3, 100))
self.axes.plot(self.data[0, :], self.data[1, :], self.data[2, :])
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mw = MainWindow()
mw.show()
# adjust the frame size so that it fits right after the window is shown
s = mw.ui.frame_plot.size()
mw.ui.plotWidget.setGeometry(1, 1, s.width() - 2, s.height() - 2)
sys.exit(app.exec_())
You are not using FigureCanvas right:
class Mpwidget(FigureCanvas):
def __init__(self, parent=None):
self.figure = Figure(facecolor=(0, 0, 0))
super(Mpwidget, self).__init__(self.figure) # this object _is_ your canvas
self.setParent(parent)
# plot random 3D data
self.axes = self.figure.add_subplot(111, projection='3d')
self.data = np.random.random((3, 100))
self.axes.plot(self.data[0, :], self.data[1, :], self.data[2, :])
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
mw = MainWindow()
mw.show()
# adjust the frame size so that it fits right after the window is shown
s = mw.ui.frame_plot.size()
mw.ui.plotWidget.setGeometry(1, 1, s.width() - 2, s.height() - 2)
sys.exit(app.exec_())
Every time you called FigureCanvas(..) you were attaching the figure to a new canvas (which were not the FigureCanvas you were seeing) hence the call-backs were never firing (because they were listening on a FigureCanvas that you couldn't see).
1) Create the FigureCanvas before adding the axes. See https://stackoverflow.com/a/9007892/3962328
canvas = FigureCanvas(fig)
ax = figure.add_subplot(111, projection='3d')
or
class MyFigureCanvas(FigureCanvas):
def __init__(self):
self.figure = Figure()
super(FigureCanvas, self).__init__(self.figure)
self.axes = self.figure.add_subplot(111, projection='3d')
2) Try ax.mouse_init() to restore the connection:
...
ax = fig.gca(projection="3d")
...
canvas = FigureCanvas(fig)
ax.mouse_init()