Search code examples
pythonmatplotlibpyqt5breakpoints

matplotlib giving empty figure during debugging of a pyqt5 app


I learned from Debugging a pyQT4 app? how to be able to avoid the

QCoreApplication::exec: The event loop is already running

when running a PyQt5 application and using breakpoints. This works fine for doing prints to the console, but I still have trouble if I want to run matplotlib plt.show() during that breakpoint. Then I get the message above and just an empty figure.

Any idea how to overcome that?

Solved: replace plt.show() with plt.pause(0.01). Thank you @jared.

Below is a full example code. The breakpoint is triggered by pushing the button and I have commented under the breakpoint what I am typing on the console to get the empty figure.

import sys

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import (
    QMainWindow, QWidget, QHBoxLayout, QPushButton, QLabel
    )

class MainWindow(QMainWindow):
    """Class main window."""

    def __init__(self):
        super().__init__()

        self.setWindowTitle('test')
        self.widget = QWidget()

        box = QHBoxLayout()
        self.widget.setLayout(box)
        self.lbl = QLabel('Hello')
        box.addWidget(self.lbl)

        self.btn = QPushButton('Push to breakpoint')
        box.addWidget(self.btn)
        self.btn.clicked.connect(self.run_script1)

        self.setCentralWidget(self.widget)

    def run_script1(self):
        breakpoint()
        #import matplotlib.pyplot as plt
        #plt.plot([1,2,3])
        #plt.show() / should be: plt.pause(0.01)

    def exit_app(self):
        """Exit app by menu."""
        sys.exit()

def prepare_debug():
    """Set a tracepoint in PDB that works with Qt."""
    # https://stackoverflow.com/questions/1736015/debugging-a-pyqt4-app
    from PyQt5.QtCore import pyqtRemoveInputHook
    import pdb
    pyqtRemoveInputHook()
    # set up the debugger
    debugger = pdb.Pdb()
    debugger.reset()
    # custom next to get outside of function scope
    debugger.do_next(None)  # run the next command
    users_frame = sys._getframe().f_back  # frame where user invoked `pyqt_set_trace()`
    debugger.interaction(users_frame, None)

if __name__ == '__main__':
    prepare_debug()
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec()

Solution

  • While debugging, if you want to show a pyplot figure, you can use the plt.pause(0.01) command (the time doesn't really matter). As per the documentation,

    If there is an active figure, it will be updated and displayed before the pause, and the GUI event loop (if any) will run during the pause.

    If you're interested in understanding the difference between pause and show, the documentation includes the links to their source code. For convenience, I have included those links below.