Reputation: 15
I am new in Python and I would like to ask you a help to solve a problem in my code. I used QtDesigner to create my UI and then I converted using pyuic4 to a test.py file. I also have the mplwidget.py and the modules.py files as shown bellow:
test.py
from PyQt4 import QtCore, QtGui
from numpy import *
import threading, thread
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(617, 588)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.tabWidget = QtGui.QTabWidget(self.centralwidget)
self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
self.tab = QtGui.QWidget()
self.tab.setObjectName(_fromUtf8("tab"))
self.verticalLayout_2 = QtGui.QVBoxLayout(self.tab)
self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
self.pushButton = QtGui.QPushButton(self.tab)
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.verticalLayout_2.addWidget(self.pushButton)
self.pushButton_2 = QtGui.QPushButton(self.tab)
self.pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
self.verticalLayout_2.addWidget(self.pushButton_2)
self.tabWidget.addTab(self.tab, _fromUtf8(""))
self.tab_2 = QtGui.QWidget()
self.tab_2.setObjectName(_fromUtf8("tab_2"))
self.verticalLayout_3 = QtGui.QVBoxLayout(self.tab_2)
self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3"))
self.widget = MplWidget(self.tab_2)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
self.widget.setSizePolicy(sizePolicy)
self.widget.setObjectName(_fromUtf8("widget"))
self.verticalLayout_3.addWidget(self.widget)
self.tabWidget.addTab(self.tab_2, _fromUtf8(""))
self.verticalLayout.addWidget(self.tabWidget)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
self.tabWidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.pushButton.setText(_translate("MainWindow", "PushButton I", None))
self.pushButton_2.setText(_translate("MainWindow", "PushButton II", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Tab 1", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Tab 2", None))
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("pressed()")), self.ploting1)
QtCore.QObject.connect(self.pushButton_2, QtCore.SIGNAL(_fromUtf8("pressed()")), self.calling)
def calling(self):
from modules import MyForm
arg="yes",
tmain=threading.Thread(target=MyForm().ploting2,args=(arg))
tmain.start()
def ploting1(self,plot="yes"):
if plot != "no":
t = logspace(1E-6,1,132,base=1E-6)
y1 = exp(-t/1E-3)
self.widget.canvas.fig.clear()
self.widget.canvas.ax = self.widget.canvas.fig.add_axes([0.15, 0.15, 0.7, 0.7])
self.widget.canvas.ax.set_xlabel('t')
self.widget.canvas.ax.set_ylabel('corr')
label1='y1'
self.widget.canvas.ax.semilogx(t,y1,'ro-',label=label1)
self.widget.canvas.ax.legend(loc='lower left')
self.widget.canvas.ax.tick_params(axis='y', colors='red')
self.widget.canvas.draw()
self.tabWidget.setCurrentIndex(1)
from mplwidget import MplWidget
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_())
modules.py
from numpy import *
from test import Ui_MainWindow
from mplwidget import MplWidget
class MyForm(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MyForm, self).__init__(parent)
self.setupUi(self)
def ploting2(self,plot="yes"):
if plot != "no":
t = logspace(1E-6,1,132,base=1E-6)
y1 = exp(-t/1E-3)
self.widget.canvas.fig.clear()
self.widget.canvas.ax = self.widget.canvas.fig.add_axes([0.15, 0.15, 0.7, 0.7])
self.widget.canvas.ax.set_xlabel('t')
self.widget.canvas.ax.set_ylabel('corr')
label1='y1'
self.widget.canvas.ax.semilogx(t,y1,'ro-',label=label1)
self.widget.canvas.ax.legend(loc='lower left')
self.widget.canvas.ax.tick_params(axis='y', colors='red')
self.widget.canvas.draw()
self.tabWidget.setCurrentIndex(1)
mplwidget.py
from PyQt4 import QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class MplCanvas(FigureCanvas):
"""Class to represent the FigureCanvas widget"""
def __init__(self, parent=None, name=None, width=5, height=4, dpi=100, bgcolor=None):
self.parent = parent
if self.parent:
bgc = parent.backgroundBrush().color()
bgcolor = float(bgc.red())/255.0, float(bgc.green())/255.0, float(bgc.blue())/255.0
self.fig = Figure(figsize=(width, height), dpi=dpi, facecolor=bgcolor, edgecolor=bgcolor)
self.ax = self.fig.add_subplot(111)
self.ax.hold(False)
FigureCanvas.__init__(self, self.fig)
FigureCanvas.setSizePolicy(self,
QtGui.QSizePolicy.Expanding,
QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
class MplWidget(QtGui.QWidget):
"""Widget defined in Qt Designer"""
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.canvas = MplCanvas()
self.vbl = QtGui.QVBoxLayout()
self.vbl.addWidget(self.canvas)
self.setLayout(self.vbl)
Well, as you can see in the main window I have two buttons. The first is connected to the function (ploting1) defined in test.py and plots a graphic in tab2. The problem arises in button 2 where I call, using a Thread, the function (ploting2) defined in modules.py. I am using Thread because I need to perform some calculations at same time plotting the curve. Both functions are the same, but the one called from modules.py doesn’t show the plot. Any hint on what I am doing wrong?
Thanks in advance for the help.
PS: I get no error message, everything works fine, apart from button 2 that doesn’t show the plot.
Upvotes: 0
Views: 172
Reputation: 11849
You have several issues here. The first two centre around this line:
tmain=threading.Thread(target=MyForm().ploting2,args=(arg))
tmain
is a local variable. When the calling
method finishes,
the thread will be garbage collected. So it won't runMyForm()
in an argument to the theading.Thread
call, but don't save a reference. to the object created. As such, the GUI contained within your object will be garbage collected, and will cease to exist.So you could fix these problems by storing the variables in the parent object (E.g. self.tmain = ...
, etc.) but this is pointless as you will see from the next problem
I strongly suggest you reconsider your use of threads. If you must use threads, do not call any Qt methods from the thread (this includes matplotlib plotting calls).
Update in response to comment
Since I am performing a very long calculation I thought the best way was using Threading. But I would also like to plot the parameters in real time obtained during calculation. Do you have any idea about the best way to do that?
You can still do your long running calculation in a thread, so that the rest of your GUI stays responsive. You will then need to communicate the results of the calculation to the main thread, where you will call the actual plotting functions. You can pass data to the main thread in a number of ways. Either by emitting a Qt signal (requires the use of QThreads), explicitly posting a Qt event to the main thread (use QCoreApplication.postEvent()
or a putting data in a Python Queue.
Some relevant links (not necessarily giving plotting examples, but should give the general idea):
Upvotes: 1