2

When I run my setup_plot and dataq functions on their own the pyplot window behaves as expected, i.e. after the run finishes the buttons (pan/zoom etc) in the navigation toolbar are active. However, when I import the functions and call them from a button event handler in my main program the pyplot window stays active after the run finishes: it is still accepting data and the toolbar buttons are inactive. How should I stop plotting without closing the plot window? Here is a snippet:

class MyWindowClass(QtGui.QWidget, form_class):
    def __init__(self, parent=None):
       QtGui.QWidget.__init__(self, parent)
       self.setupUi(self)
       self.pushButton_Run.clicked.connect(self.pushbutton_run_clicked)
       self.pushButton_Stop.clicked.connect(self.pushbutton_stop_clicked)

    def pushbutton_run_clicked(self):
        # get line edit values here 
        functions.setup_plot()
        functions.dataq(steptime, runtime, CO2_1, CO2_2)
Drew
  • 29
  • 7
  • Do you think you could produce a a Minimal, Complete, and Verifiable example of your problem (see http://stackoverflow.com/help/mcve)? It is difficult to pinpoint the problem from the limited amount of information we have presently. – Jean-Sébastien Aug 14 '15 at 06:18

1 Answers1

1

I tried to reproduce your problem by creating a simple MCVE based on the code snippet you gave us. The only thing I could find that would make my simple application to behave as you described is if I do not set the backend of matplotlib to Qt4Agg.

from PyQt4 import QtGui
import sys
import numpy as np

import matplotlib as mpl
mpl.use('Qt4Agg')
import matplotlib.pyplot as plt

class MyWindowClass(QtGui.QWidget):
    def __init__(self, parent=None):
       super(MyWindowClass, self).__init__(parent)

       pushButton_Run = QtGui.QPushButton('Run')
       pushButton_Run.clicked.connect(self.pushbutton_run_clicked)

       layout = QtGui.QGridLayout()
       layout.addWidget(pushButton_Run, 0, 0)
       self.setLayout(layout)

    def pushbutton_run_clicked(self):

        fig, ax = setup_plot()                        
        dataq(fig, ax)

def setup_plot():

    fig, ax = plt.subplots()
    fig.canvas.manager.show()

    return fig, ax

def dataq(fig, ax):
    for i in range(200):
        ax.plot(np.random.rand(1), np.random.rand(1), 'o')
        fig.canvas.draw()
        fig.canvas.flush_events()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)    
    mywindow = MyWindowClass()
    mywindow.show()      
    sys.exit(app.exec_())

enter image description here

Update - Second Example:

This is another way to setup your artists that may allow you to more easily used them within multiple functions and can make their manipulation more convenient.

from PyQt4 import QtGui
import sys
import numpy as np

import matplotlib as mpl
mpl.use('Qt4Agg')
import matplotlib.pyplot as plt

class MyWindowClass(QtGui.QWidget):
    def __init__(self, parent=None):
       super(MyWindowClass, self).__init__(parent)

       #---- generate some data ----

       self.x = np.random.rand(50)
       self.y = np.random.rand(50)

       #---- create a layout ----

       pushButton_Run = QtGui.QPushButton('Run')
       pushButton_Run.clicked.connect(self.pushbutton_run_clicked)

       pushButton_Clear = QtGui.QPushButton('Clear')
       pushButton_Clear.clicked.connect(self.clear_plot)

       layout = QtGui.QGridLayout()
       layout.addWidget(pushButton_Run, 0, 0)
       layout.addWidget(pushButton_Clear, 1, 0)
       self.setLayout(layout)

       #---- init artists ----

       self.fig, self.ax = plt.subplots()
       self.fig.canvas.manager.show()

    def clear_plot(self):
        self.ax.cla()
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()

    def pushbutton_run_clicked(self):
        self.setEnabled(False)
        self.ax.cla()   
        dataq(self.fig, self.ax, self.x, self.y)
        dataq2(self.fig, self.ax, self.x, self.y)
        self.setEnabled(True)

def dataq(fig, ax, x, y):            
    for i in range(len(x)):
        ax.plot(x[i], y[i], 'o')
        fig.canvas.draw()
        fig.canvas.flush_events()

def dataq2(fig, ax, x, y):
    for i in range(len(x)-1):
        ax.plot(x[i:i+2], y[i:i+2], '-')
        fig.canvas.draw()
        fig.canvas.flush_events()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)    
    mywindow = MyWindowClass()
    mywindow.show()      
    sys.exit(app.exec_())
Jean-Sébastien
  • 2,649
  • 1
  • 16
  • 21
  • Changing the backend setting had no effect for me: your example worked both ways. However, the structure of your code revealed my mistake. I had defined `fig` and `ax` outside of `setup_plot` because they were used by multiple functions. Moving them inside fixed the problem. Thanks! – Drew Aug 14 '15 at 17:16
  • @Drew Glad it helped. Do you mean by "defined fig and ax outside of setup_plot" that they were defined as global variables? – Jean-Sébastien Aug 14 '15 at 18:20
  • Yes they were defined globally in `functions`. I'm working on cleaning this up. As you can probably tell I'm a beginner. – Drew Aug 14 '15 at 18:29
  • @Drew Ah ok, I understand. You can still define `fig` and `ax` outside of `setup_plot` if you want and if it allows you to more easily used them within multiple functions. I've updated my answer with a second example that shows how this could be done by defining your artists as class variables. – Jean-Sébastien Aug 14 '15 at 18:35
  • Using class variables as you suggested works for me. Thanks again! – Drew Aug 17 '15 at 16:00