Create several popup plots with FigureCanvas in PyQt4

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

Answers (1)

eyllanesc
eyllanesc

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

Related Questions