Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Matplotlib interfering with PyQt



  • I have a situation where after displaying a dialogue box, setting parameters, then handling a callback for a button click that closes the dialogue and returns the values to be used for plotting in matplotlib. The issue is that combobox widgets will stay visible, sometimes the dialogue box will stay visible, etc. and interfering with plots.

    Here's an example. I modified one of the examples and added a some plotting functions. When you run the script and choose one of the options of the combobox (in the upper left part of the GUI) the choices will remain visible (please refer to the screen shots). I really don't understand what's happening, it seems like such an easy thing to do.

    =================================

    from PyQt5.QtCore import QDateTime, Qt, QTimer
    from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QDateTimeEdit,
            QDial, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
            QProgressBar, QPushButton, QRadioButton, QScrollBar, QSizePolicy,
            QSlider, QSpinBox, QStyleFactory, QTableWidget, QTabWidget, QTextEdit,
            QVBoxLayout, QWidget)
    from PyQt5.QtWidgets import *
    
    
    import sys
    import matplotlib
    import matplotlib.pyplot as plt
    import matplotlib.ticker as ticker
    import pandas as pd
    import numpy as np
    from time import time, sleep, strftime, gmtime
    
    
    
    class WidgetGallery(QDialog):
        def __init__(self, parent=None):
            super(WidgetGallery, self).__init__(parent)
    
            self.originalPalette = QApplication.palette()
    
            styleComboBox = QComboBox()
            styleComboBox.addItems(QStyleFactory.keys())
    
            styleLabel = QLabel("&Style:")
            styleLabel.setBuddy(styleComboBox)
    
            self.useStylePaletteCheckBox = QCheckBox("&Use style's standard palette")
            self.useStylePaletteCheckBox.setChecked(True)
    
            disableWidgetsCheckBox = QCheckBox("&Disable widgets")
    
            self.createTopLeftGroupBox()
            self.createTopRightGroupBox()
            self.createBottomLeftTabWidget()
            self.createBottomRightGroupBox()
            self.createProgressBar()
    
            styleComboBox.activated[str].connect(self.changeStyle)
            self.useStylePaletteCheckBox.toggled.connect(self.changePalette)
            disableWidgetsCheckBox.toggled.connect(self.topLeftGroupBox.setDisabled)
            disableWidgetsCheckBox.toggled.connect(self.topRightGroupBox.setDisabled)
            disableWidgetsCheckBox.toggled.connect(self.bottomLeftTabWidget.setDisabled)
            disableWidgetsCheckBox.toggled.connect(self.bottomRightGroupBox.setDisabled)
    
            topLayout = QHBoxLayout()
            topLayout.addWidget(styleLabel)
            topLayout.addWidget(styleComboBox)
            topLayout.addStretch(1)
            topLayout.addWidget(self.useStylePaletteCheckBox)
            topLayout.addWidget(disableWidgetsCheckBox)
    
            mainLayout = QGridLayout()
            mainLayout.addLayout(topLayout, 0, 0, 1, 2)
            mainLayout.addWidget(self.topLeftGroupBox, 1, 0)
            mainLayout.addWidget(self.topRightGroupBox, 1, 1)
            mainLayout.addWidget(self.bottomLeftTabWidget, 2, 0)
            mainLayout.addWidget(self.bottomRightGroupBox, 2, 1)
            mainLayout.addWidget(self.progressBar, 3, 0, 1, 2)
            mainLayout.setRowStretch(1, 1)
            mainLayout.setRowStretch(2, 1)
            mainLayout.setColumnStretch(0, 1)
            mainLayout.setColumnStretch(1, 1)
            self.setLayout(mainLayout)
            self.setWindowTitle("Styles")
            self.changeStyle('Windows')
    
        def on_button_clicked(self):
            alert = QMessageBox()
            alert.setText('You clicked the button!')
                   
            self.button_state = self.radioButton1.isChecked()
            print("self.button_state ", self.button_state)
            
            alert.exec_()
            sleep(1)
    
            self.accept()
    
    #        self.done(0)
    #         self.close()
    #         generate_plots()
    
    
        def changeStyle(self, styleName):
            QApplication.setStyle(QStyleFactory.create(styleName))
            self.changePalette()
    
        def changePalette(self):
            if (self.useStylePaletteCheckBox.isChecked()):
                QApplication.setPalette(QApplication.style().standardPalette())
            else:
                QApplication.setPalette(self.originalPalette)
    
        def advanceProgressBar(self):
            curVal = self.progressBar.value()
            maxVal = self.progressBar.maximum()
            self.progressBar.setValue(curVal + (maxVal - curVal) / 100)
        def createTopLeftGroupBox(self):
            self.topLeftGroupBox = QGroupBox("Group 1")
            self.radioButton1 = QRadioButton("Radio button 1")
            radioButton2 = QRadioButton("Radio button 2")
            radioButton3 = QRadioButton("Radio button 3")
            self.radioButton1.setChecked(True)
            checkBox = QCheckBox("Tri-state check box")
            checkBox.setTristate(True)
            checkBox.setCheckState(Qt.PartiallyChecked)
            layout = QVBoxLayout()
            layout.addWidget(self.radioButton1)
            layout.addWidget(radioButton2)
            layout.addWidget(radioButton3)
            layout.addWidget(checkBox)
            layout.addStretch(1)
            self.topLeftGroupBox.setLayout(layout)    
    
        def createTopRightGroupBox(self):
            self.topRightGroupBox = QGroupBox("Group 2")
    
            defaultPushButton = QPushButton("Default Push Button")
            defaultPushButton.setDefault(True)
            togglePushButton = QPushButton("Toggle Push Button")
            togglePushButton.setCheckable(True)
            togglePushButton.setChecked(True)
            flatPushButton = QPushButton("Flat Push Button")
            flatPushButton.setFlat(True)
            button = QPushButton('Click This One')
            button.clicked.connect(self.on_button_clicked)
            layout = QVBoxLayout()
            layout.addWidget(button)
            layout.addWidget(defaultPushButton)
            layout.addWidget(togglePushButton)
            layout.addWidget(flatPushButton)
            layout.addStretch(1)
            self.topRightGroupBox.setLayout(layout)
    
        def createBottomLeftTabWidget(self):
            self.bottomLeftTabWidget = QTabWidget()
            self.bottomLeftTabWidget.setSizePolicy(QSizePolicy.Preferred,
                    QSizePolicy.Ignored)
    
            tab1 = QWidget()
            tableWidget = QTableWidget(10, 10)
            tab1hbox = QHBoxLayout()
            tab1hbox.setContentsMargins(5, 5, 5, 5)
            tab1hbox.addWidget(tableWidget)
            tab1.setLayout(tab1hbox)
            tab2 = QWidget()
            textEdit = QTextEdit()
            textEdit.setPlainText("Twinkle, twinkle, little star,\n"
                                  "How I wonder what you are.\n" 
                                  "Up above the world so high,\n"
                                  "Like a diamond in the sky.\n"
                                  "Twinkle, twinkle, little star,\n" 
                                  "How I wonder what you are!\n")
    
            tab2hbox = QHBoxLayout()
            tab2hbox.setContentsMargins(5, 5, 5, 5)
            tab2hbox.addWidget(textEdit)
            tab2.setLayout(tab2hbox)
    
            self.bottomLeftTabWidget.addTab(tab1, "&Table")
            self.bottomLeftTabWidget.addTab(tab2, "Text &Edit")
    
        def createBottomRightGroupBox(self):
            self.bottomRightGroupBox = QGroupBox("Group 3")
            self.bottomRightGroupBox.setCheckable(True)
            self.bottomRightGroupBox.setChecked(True)
    
            lineEdit = QLineEdit('s3cRe7')
            lineEdit.setEchoMode(QLineEdit.Password)
            spinBox = QSpinBox(self.bottomRightGroupBox)
            spinBox.setValue(50)
            dateTimeEdit = QDateTimeEdit(self.bottomRightGroupBox)
            dateTimeEdit.setDateTime(QDateTime.currentDateTime())
            slider = QSlider(Qt.Horizontal, self.bottomRightGroupBox)
            slider.setValue(40)
            scrollBar = QScrollBar(Qt.Horizontal, self.bottomRightGroupBox)
            scrollBar.setValue(60)
            dial = QDial(self.bottomRightGroupBox)
            dial.setValue(30)
            dial.setNotchesVisible(True)
    
            layout = QGridLayout()
            layout.addWidget(lineEdit, 0, 0, 1, 2)
            layout.addWidget(spinBox, 1, 0, 1, 2)
            layout.addWidget(dateTimeEdit, 2, 0, 1, 2)
            layout.addWidget(slider, 3, 0)
            layout.addWidget(scrollBar, 4, 0)
            layout.addWidget(dial, 3, 1, 2, 1)
            layout.setRowStretch(5, 1)
            self.bottomRightGroupBox.setLayout(layout)
    
        def createProgressBar(self):
            self.progressBar = QProgressBar()
            self.progressBar.setRange(0, 10000)
            self.progressBar.setValue(0)
    
            timer = QTimer(self)
            timer.timeout.connect(self.advanceProgressBar)
            timer.start(1000)
    
        
    def plot_data(df, title, fig_num):
        FIGURE_SIZE = (8, 6)
        df_len = len(df)
        x_series = np.arange(0, df_len)
     
        fig, axs = plt.subplots(nrows=2, num=fig_num, figsize=FIGURE_SIZE, 
                        dpi=72, facecolor='w', edgecolor='k', sharex=True, sharey=False, 
                            gridspec_kw={'hspace': 0.25}, tight_layout=False)
            
        plt.suptitle('Plot Some Data', fontsize=12, fontweight='bold')
        plt_axes = plt.gca()
        plt_axes.set_ylim(-10.0, 10.0)
    
        axs[0].plot(x_series, df['data1'], alpha=0.8, ms=1, color='b', label='Data 1')  
        axs[0].xaxis.set_major_locator(ticker.MultipleLocator(10.))
        axs[0].xaxis.set_minor_locator(ticker.MultipleLocator(10./5.))
        axs[0].set(title=title, ylabel="Amp") 
    
        axs[1].plot(x_series, df['data2'], alpha=0.8, ms=1, color='b', label='Data 2')  
        axs[1].xaxis.set_major_locator(ticker.MultipleLocator(10.))
        axs[1].xaxis.set_minor_locator(ticker.MultipleLocator(10./5.))
        axs[1].set(title=title, ylabel="Amp") 
    
    #     plt.savefig('data_plot.png', dpi=300)
       
        plt.show()  
        plt.close()
    
    
    def generate_plots():
    
        data_df = pd.DataFrame({
                'data1': {17384: 98125, 2680: 98107, 722: 98005, 18754: 98109, 14554: 98155}, 
                'data2': {17384: 1.5, 2680: 0.75, 722: 3.25, 18754: 1.0, 14554: 2.5}, 
                'data3': {17384: 1650, 2680: 3700, 722: 51836, 18754: 2640, 14554: 9603}, 
                'data4': {17384: 2, 2680: 2, 722: 4, 18754: 2, 14554: 4}, 
                'data4': {17384: 1430, 2680: 1440, 722: 4670, 18754: 1130, 14554: 3180}, 
                'data5': {17384: 3.0, 2680: 1.0, 722: 2.0, 18754: 1.0, 14554: 2.0}
                })
        print (data_df)
    
        plot_data(data_df, 'data plot', 30)
    
    
    def main(date_time_now):
     
        print("main() - date_time_now: ", date_time_now)
        
        app = QApplication(sys.argv)
        gallery = WidgetGallery()
        gallery.show()
    #     sys.exit(app.exec_()) 
        app.exec_()
        app.quit() 
    
        print("main(): gallery.button_state: ", gallery.button_state)
        generate_plots()
    
           
    
    
    if __name__ == '__main__':
    
        date_time_now = strftime('%Y-%m-%d-%H.%M.%S', gmtime())
        main(date_time_now)
    

    =================================

    alt text

    alt text

    alt text

    [edit: Added missing coding tags SGaist]


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    matplotlib has also a Qt based backend so these two might interfere with each other. What I would suggest is that you use directly the classes of that backend to integrate matplotlib with your Qt Application.

    Otherwise, if you only to get a dialog for some setup and the use matplotlib separately, use a function for the Qt part so you have all the setup and teardown done in the scope of the method and you should be good to go with the rest.



  • Hello,

    That's really interesting, I had no idea. I will check it out ASAP!

    Thanks for the suggestion, if I get it working I'll update the post with the correct answer.



  • That worked! Thank you so much! I only had to add a this to my script and it works great.

    import matplotlib
    matplotlib.use('Qt5Agg')
    
    

  • Lifetime Qt Champion

    Thanks for the feedback and happy hacking !


Log in to reply