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)
=================================
[edit: Added missing coding tags SGaist]
-
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')
-
Thanks for the feedback and happy hacking !