0

The aim of what I've written so far is to have a "Temperature" button in my GUI that when pressed opens up a matplotlib plot that I made separately (mplwidget.py).

However, when I run the code, both the app and the widget open up simultaneously, and the Temperature button appears to have no function (even if I close the widget, pressing the button doesn't open it again).

import sys
from PyQt5.QtCore import QCoreApplication

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QPushButton, QAction, QMessageBox
from PyQt5.uic.properties import QtGui

from mplwidget import animate #import animation widget

class window(QMainWindow):

    def __init__(self):
        super(window, self).__init__()
        self.setGeometry(50, 50, 500, 300)
        self.setWindowTitle('Temperature Control')
        self.setWindowIcon(QIcon('adn.png'))

        extractAction = QAction('&Quit', self)
        extractAction.setShortcut('Ctrl+Q')
        extractAction.setStatusTip('leave the app')
        extractAction.triggered.connect(self.close_application)

        self.statusBar()

        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu('&File')
        fileMenu.addAction(extractAction)

        self.home()

    def home(self):
        btn = QPushButton('quit', self)
        btn.clicked.connect(self.close_application)
        btn.resize(btn.sizeHint())
        btn.move(0, 100)

        button = QPushButton('Temperature',self)
        button.clicked.connect(self.opengraph)
        button.move(50,200)
        self.show()

    def opengraph(self):
        animate()

    def close_application(self):

        choice = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)

        if choice == QMessageBox.Yes:
            sys.exit()
        else:
            pass

if __name__ == "__main__":

    def run():
        app = QApplication(sys.argv)
        Gui = window()
        sys.exit(app.exec_())

run()

mplwidget is below

def GraphWidget():

    fig = plt.figure()
    ax1 = fig.add_subplot(1,1,1)

    Time = []
    Temp = []

    def animate(i):

        x = datetime.datetime.now()
        y = numpy.random.randint(48,52)
        Time.append(x)
        Temp.append(int(y))    

    #    print (Temp)
        ax1.plot(Time,Temp)

    ani = animation.FuncAnimation(fig,animate, interval=1000)
    plt.show()
11
  • You cannot call a module. Instead you would probably call a function inside your module; something like mplwidget.showmywindow(). Commented Aug 12, 2018 at 11:14
  • You can publish the mplwidget.py ? Commented Aug 12, 2018 at 11:18
  • sure, I'll do that now @S.Nick Commented Aug 12, 2018 at 11:34
  • @ImportanceOfBeingErnest is this what you mean?: def opengraph(self): mpl = mplwidget() mpl.show() Commented Aug 12, 2018 at 11:56
  • When you do import mymodule the code directly executes. Instead you want to put it into a function that you can call from within the importing script. Commented Aug 12, 2018 at 11:58

2 Answers 2

2

The problem is that plt.show() cannot start an event loop itself because the event loop is already running due to the QT window being open. In such cases one would need to call fig.show() instead, where fig is the figure in use.

This in turn leads to the problem that the function from the mplwidget.py module actually returns. Once it returns the reference for the animation is lost and will be garbage collected; hence no animation shows up on screen.

The solution is to let the function return the animation and store it somewhere in the main program.

import sys
from PyQt5.QtCore import QCoreApplication

from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QPushButton, QAction, QMessageBox
from PyQt5.uic.properties import QtGui

from mplwidget import showgraph

class window(QMainWindow):

    def __init__(self):
        super(window, self).__init__()
        self.setGeometry(50, 50, 500, 300)
        self.setWindowTitle('Temperature Control')
        self.setWindowIcon(QIcon('adn.png'))

        extractAction = QAction('&Quit', self)
        extractAction.setShortcut('Ctrl+Q')
        extractAction.setStatusTip('leave the app')
        extractAction.triggered.connect(self.close_application)

        self.statusBar()

        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu('&File')
        fileMenu.addAction(extractAction)

        self.home()

    def home(self):
        btn = QPushButton('quit', self)
        btn.clicked.connect(self.close_application)
        btn.resize(btn.sizeHint())
        btn.move(0, 100)

        button = QPushButton('Temperature',self)
        button.clicked.connect(self.opengraph)
        button.move(50,200)
        self.show()

    def opengraph(self):
        self.store = showgraph()

    def close_application(self):

        choice = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)

        if choice == QMessageBox.Yes:
            sys.exit()
        else:
            pass

if __name__ == "__main__":

    def run():
        app = QApplication(sys.argv)
        Gui = window()
        sys.exit(app.exec_())

run()

mplwidget.py:

import matplotlib.pyplot as plt
import datetime
import numpy
import matplotlib.animation as animation

def showgraph():

    fig = plt.figure()
    ax1 = fig.add_subplot(1,1,1)

    Time = []
    Temp = []

    def animate(i):

        x = datetime.datetime.now()
        y = numpy.random.randint(48,52)
        Time.append(x)
        Temp.append(int(y))    

        ax1.plot(Time,Temp)

    ani = animation.FuncAnimation(fig,animate, interval=1000)
    fig.show()
    return fig, ani
Sign up to request clarification or add additional context in comments.

Comments

1

Try it:

import sys
from PyQt5.QtGui     import QIcon
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QAction, QMessageBox

from mplwidget import MplWindow                     # +++

class window(QMainWindow):

    def __init__(self):
        super(window, self).__init__()
        self.setGeometry(50, 50, 500, 300)
        self.setWindowTitle('Temperature Control')
        self.setWindowIcon(QIcon('adn.png'))
        extractAction = QAction('&Quit', self)
        extractAction.setShortcut('Ctrl+Q')
        extractAction.setStatusTip('leave the app')
        extractAction.triggered.connect(self.close_application)
        self.statusBar()
        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu('&File')
        fileMenu.addAction(extractAction)

        self.matplWindow = MplWindow()               # +++

        self.home()


    def home(self):
        btn = QPushButton('quit', self)
        btn.clicked.connect(self.close_application)
        btn.resize(btn.sizeHint())
        btn.move(0, 100)
        button = QPushButton('Temperature',self)
        button.clicked.connect(self.opengraph)
        button.move(50,200)
        self.show()

    def opengraph(self):
        self.matplWindow.funAnimation()              # +++

    def close_application(self):
        choice = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)
        if choice == QMessageBox.Yes:
            sys.exit()
        else:
            pass

if __name__ == "__main__":
    app = QApplication(sys.argv)
    Gui = window()
    sys.exit(app.exec_())

mplwidget.py

import matplotlib.pyplot as plt
import numpy
import datetime
import matplotlib.animation as animation
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout


class MplWindow(QDialog):
    Time = []
    Temp = []
    def __init__(self, parent=None):
        super(MplWindow, self).__init__(parent)

    def funAnimation(self):        
        self.fig = plt.figure()
        self.ax1 = self.fig.add_subplot(1,1,1)
        self.ani = animation.FuncAnimation(self.fig, self.animate, interval=1000)
        plt.show()

    def animate(self, i):
        x = datetime.datetime.now()
        y = numpy.random.randint(48,52)
        self.Time.append(x)
        self.Temp.append(int(y))    
        self.ax1.plot(self.Time, self.Temp)

enter image description here

1 Comment

Thank you! This is really helpful because I think it's very useful that points continue to plot even between opening and closing widgets

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.