Reputation: 5791
Following code creates a Widget with a Button and a Progressbar. When Button is pressed and Progressbar reaches 100%, 3 plots are shown (by Matplotlib.pyplot):
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import matplotlib.pyplot as plt
import pandas as pd
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
self.setGeometry(500, 300, 820, 350)
self.setWindowTitle("Program")
#Buttons
btnposx = 30
btnposy = 50
self.btn4 = QPushButton('Load', self)
self.btn4.move(btnposx,btnposy+220)
self.btn4.released.connect(self.thread)
#ProgressBar
self.pb = QProgressBar(self)
self.pb.move(btnposx+150,btnposy+220)
self.pb.resize(470,27)
self.show()
@pyqtSlot(float)
def load(self, val):
self.pb.setValue(val)
@pyqtSlot(object)
def plot(self, pq):
pq.plot(grid = 1)
plt.show()
def thread(self):
self.thread_ = Thread()
self.thread_.pb_signal.connect(self.load, Qt.QueuedConnection)
self.thread_.plot_signal.connect(self.plot, Qt.QueuedConnection)
self.thread_.start()
class Thread(QThread):
pb_signal = pyqtSignal(float)
plot_signal = pyqtSignal(object)
def __init__(self, *args, **kwargs):
QThread.__init__(self, *args, **kwargs)
def __del__(self):
self.wait()
@pyqtSlot()
def run(self):
val = 0
self.pb_signal.emit(20)
l = range(50000000)
for i in l:
val += 1
self.pb_signal.emit(60)
self.pb_signal.emit(100)
pq = pd.DataFrame(data = {'col1':[1,2,3,4,5,6], 'col2':[6,5,4,3,2,1]})
self.plot_signal.emit(pq)
self.plot_signal.emit(pq)
self.plot_signal.emit(pq)
return
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
How do I do the exact same Thing with FigureCanvas? I don't want to make one window, in that 3 plots are embedded but 3 seperate figures. The Information online about how to use FigureCanvas this way is very scarce.
Upvotes: 1
Views: 515
Reputation: 243993
FigureCanvas is a specialized QWidget that can contain a Figure of matplotlib, and in that Figure you can make the plots, so the solution is to create one for each emission, in addition to that the plotting functions have an additional argument that receives the axes where it will be drawn, so you must pass the axes created inside Figure:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import pandas as pd
from matplotlib.backends.backend_qt4agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
self.setGeometry(500, 300, 820, 350)
self.setWindowTitle("Program")
#Buttons
btnposx = 30
btnposy = 50
self.btn4 = QPushButton('Load', self)
self.btn4.move(btnposx,btnposy+220)
self.btn4.released.connect(self.thread)
#ProgressBar
self.pb = QProgressBar(self)
self.pb.move(btnposx+150,btnposy+220)
self.pb.resize(470,27)
self.canvas = []
self.show()
@pyqtSlot(float)
def load(self, val):
self.pb.setValue(val)
@pyqtSlot(object)
def plot(self, pq):
cv = FigureCanvas(Figure(figsize=(5, 3)))
ax = cv.figure.subplots()
pq.plot(grid = 1, ax=ax)
cv.show()
# avoid garbage collector
self.canvas.append(cv)
def thread(self):
self.thread_ = Thread()
self.thread_.pb_signal.connect(self.load, Qt.QueuedConnection)
self.thread_.plot_signal.connect(self.plot, Qt.QueuedConnection)
self.thread_.start()
class Thread(QThread):
pb_signal = pyqtSignal(float)
plot_signal = pyqtSignal(object)
def __del__(self):
self.wait()
@pyqtSlot()
def run(self):
val = 0
self.pb_signal.emit(20)
l = range(50000000)
for i in l:
val += 1
self.pb_signal.emit(60)
self.pb_signal.emit(100)
pq = pd.DataFrame(data = {'col1':[1,2,3,4,5,6], 'col2':[6,5,4,3,2,1]})
self.plot_signal.emit(pq)
self.plot_signal.emit(pq)
self.plot_signal.emit(pq)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
Note: only the list has been created to prevent the garbage collector from deleting the plots
Upvotes: 2