It runs, but 0xc0000409 error occurs during operation - pyqt5

I'm practicing a program that reads and displays Excel files
Try raising the entire code.
I'm using Python 3.9, Pycharm
PyQt5 - 5.15.7
Help me TT
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, QHeaderView, QHBoxLayout, QVBoxLayout, QPushButton
from PyQt5.QtCore import Qt
import pandas as pd
from pympler import muppy
all_objects = muppy.get_objects()
class MyApp(QWidget):
def init(self):
super().init()
self.window_width, self.window_height = 700, 500
self.resize(self.window_width, self.window_height)
layout = QVBoxLayout()
self.setLayout(layout)
self.table = QTableWidget()
layout.addWidget(self.table)
self.button = QPushButton('&load Data')
self.button.clicked.connect(lambda _, xl_path=excel_file_patch, sheet_name=worksheet_name: self.loadExcelData(xl_path, sheet_name))
layout.addWidget(self.button)
def loadExcelData(self, excel_file_dir, worksheet_name):
df = pd.read_excel(excel_file_dir, worksheet_name)
if df.size == 0:
return super.loadExcelData(excel_file_dir, worksheet_name)
df.fillna('', inplace=True)
self.table.setRowCount(df.shape[0])
self.table.setColumnCount(df.shape[0])
self.table.setHorizontalHeaderLabels(df.columns)
if name == 'main':
excel_file_patch = 'data.xlsx'
worksheet_name = 'Sales'
app = QApplication(sys.argv)
myApp = MyApp()
myApp.show()
try:
sys.exit(app.exec())
except SystemExit:
print('closing Window...')

Related

PyQt - not showing instance of FigureCanvasQTAgg on QtWidget of TabPane

I'm continuing project described more in that question: PyQt - can't read Excel file
Basically my code looks like this right now:
# This is a sample Python script.
# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
import csv
import sys
import numpy as np
from PyQt6 import QtWidgets
from PyQt6.QtWidgets import QDialog, QApplication, QFileDialog, QTableWidget, QTableWidgetItem, QTabWidget, QWidget
from PySide6.QtCore import Slot, SIGNAL
from PyQt6.uic import loadUi
import pandas as pd
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=12, height=5, dpi=100):
fig = Figure(figsize=(width, height), dpi=100)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
class MainWindow(QDialog):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.initUI()
def initUI(self):
loadUi('gui.ui', self)
self.btnShow.setEnabled(False)
self.btnLoad.setEnabled(False)
self.btnBrowse.clicked.connect(self.browseFiles)
self.btnLoad.clicked.connect(self.loadExcelData)
self.btnClean.clicked.connect(self.cleanData)
self.btnShow.clicked.connect(self.showGraphs)
#Slot()
def browseFiles(self):
fname = QFileDialog.getOpenFileName(self, 'Open a file', 'C:\\', "Excel (*.xls *.xlsx)")
self.filename.setText(fname[0])
self.btnLoad.setEnabled(True)
#Slot()
def loadExcelData(self):
column_names = ["Action", "TimeOfFailure", "ReverseRankR", "S(i)", "Cdf", "Ppf", "LogTime"]
df = pd.read_excel(self.filename.text(), "Sheet1", names=column_names)
if df.size == 0:
return
self.tableExcelData.setRowCount(df.shape[0])
self.tableExcelData.setColumnCount(df.shape[1])
self.tableExcelData.setHorizontalHeaderLabels(df.columns)
for row in df.iterrows():
values = row[1]
for col_index, value in enumerate(values):
tableItem = QTableWidgetItem(str(value))
self.tableExcelData.setItem(row[0], col_index, tableItem)
self.btnLoad.setEnabled(False)
self.btnShow.setEnabled(True)
#Slot()
def cleanData(self):
self.btnLoad.setEnabled(True)
self.btnShow.setEnabled(False)
self.tableExcelData.setRowCount(0)
self.tableExcelData.setColumnCount(0)
#Slot()
def showGraphs(self):
timeOfDays = []
cdf = []
ppf = []
logTime = []
for row in range(self.tableExcelData.rowCount()):
isFailure = False
for column in range(self.tableExcelData.columnCount()):
value = self.tableExcelData.item(row, column)
if(column == 0 and str(value.text()) == 'F'):
isFailure = True
if isFailure == True:
if(column == 1): #TimeOfDays
value = int(value.text())
timeOfDays.append(value)
elif(column == 4): #CDF
value = float(value.text())
cdf.append(value)
elif(column == 5):
value = float(value.text())
ppf.append(value)
elif(column == 6):
value = float(value.text())
logTime.append(value)
print(timeOfDays)
print(cdf)
print(ppf)
print(logTime)
#fig = Figure(figsize=(12,5), dpi=100)
#firstSubplot = fig.add_subplot(111)
#firstSubplot.scatter(timeOfDays, ppf, '*')
#firstSubplot.plot(timeOfDays, ppf)
#fig.show()
#plt.plot(timeOfDays, ppf)
#plt.show()
try:
canvasFig = MplCanvas()
canvasFig.axes.scatter(timeOfDays, ppf, s=5, color='red')
canvasFig.axes.plot(timeOfDays, ppf)
canvasFig.draw()
self.tabFirstGraph.setCentralWidget(canvasFig)
except Exception as e:
print('Error: ' + str(e))
#canvas = FigureCanvasTkAgg(fig, master=self)
#canvas.get_tk_widget().pack()
#canvas.draw()
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWidget = QtWidgets.QStackedWidget()
mainWidget.addWidget(mainWindow)
mainWidget.show()
sys.exit(app.exec())
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
I'm trying to generate two graphs (now it's code for only creation of one):
try:
canvasFig = MplCanvas()
canvasFig.axes.scatter(timeOfDays, ppf, s=5, color='red')
canvasFig.axes.plot(timeOfDays, ppf)
canvasFig.draw()
self.tabFirstGraph.setCentralWidget(canvasFig) #
except Exception as e:
print('Error: ' + str(e))
I tried to create another TabPane ("tabFirstGraph" as name of this object) and set canvas figure object to fill this QWidget instance. But I'm getting constantly this error:
Error: 'QWidget' object has no attribute 'setCentralWidget'
I assumed already that problem is with line above (QWidget, QTableWidget don't have this method). But how can I show my canvas figure graph on "First Graph" Tab Pane?
Thanks in advance for your all answers. :)

cannot plot lines on matplotlib embedded in pyqt5

Following is the codes. It plots a line via pressing a button. However, when I pressed the button, it just printed
matplotlib.lines.Line2D object at 0x11371fcc0 ......
but could not show the line on the canvas. How do you fix it?
import matplotlib
matplotlib.use("Qt5Agg")
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import mywidgets
# mywidgets.MplCanvas is a wrapper of FigureCanvas in order to make the drawing convenient.
class ApplicationWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setWindowTitle("Hello")
self.main_widget = QWidget(self)
l = QVBoxLayout(self.main_widget)
fig1 = Figure(figsize=(5, 4))
self.sc = mywidgets.MplCanvas(self.main_widget, fig1)
l.addWidget(self.sc)
bdraw = QPushButton('Draw')
bdraw.pressed.connect(self.draw)
l.addWidget(bdraw)
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
def draw(self):
# it does not report any error, but on lines are drawn.
line = self.sc.axes.plot([1,2,3], 'r')
print(line)
if __name__ == '__main__':
app = QApplication([])
aw = ApplicationWindow()
aw.show()
#sys.exit(qApp.exec_())
app.exec_()
You forgot to update the canvas after plotting to it.
def draw(self):
line = self.sc.axes.plot([1,2,3], 'r')
self.sc.draw_idle()

How save a Matplotlib figure with Pickle in a Pyqt5 environment?

I'm facing an issue and I cannot get rid of it.
I'm trying to use the Pickle package in order to save a matplotlib figure to replot it if i want to.
So far I have the below code which open a Qt window and plot some curves in it if the 'if' condition in lfpViewer.__Init__() is 1 (I put 0 only to check the pickle load function).
So I added, to the toolbar, two buttons where I can save a .pickle of the current figure or load a .pickle from a previous figure.
import pickle
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import os
import matplotlib
import numpy as np
matplotlib.use('Qt5Agg')
import matplotlib.patches as patches
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.centralWidget = QWidget()
self.color = self.centralWidget.palette().color(QPalette.Background)
self.setCentralWidget(self.centralWidget)
self.plotview = QGroupBox(" ")
self.layout_plotview = QVBoxLayout()
self.mascenelfp = lfpViewer(self)
self.layout_plotview.addWidget(self.mascenelfp)
self.centralWidget.setLayout(self.layout_plotview)
class lfpViewer(QGraphicsView):
def __init__(self, parent=None):
super(lfpViewer, self).__init__(parent)
self.parent=parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.setBackgroundBrush(QBrush(self.parent.color))# self.setBackgroundBrush(QBrush(QColor(200, 200, 200)))
self.figure = plt.figure(facecolor=[self.parent.color.red()/255,self.parent.color.green()/255,self.parent.color.blue()/255]) #Figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
self.save_button = QPushButton()
self.save_button.setIcon(QIcon(os.path.join('icons','SaveData.png')))
self.save_button.setToolTip("Save Figure Data")
self.toolbar.addWidget(self.save_button)
self.save_button.clicked.connect(self.saveFigData)
self.load_button = QPushButton()
self.load_button.setIcon(QIcon(os.path.join('icons','LoadData.png')))
self.load_button.setToolTip("Load Figure Data")
self.toolbar.addWidget(self.load_button)
self.load_button.clicked.connect(self.loaddatapickle)
if 0:
t=np.arange(1000)
self.axes_l=self.figure.add_subplot(311)
self.axes_l.plot(t, np.sin(2*3.14*100*t))
self.axes_Y=self.figure.add_subplot(312)
self.axes_Y.plot(t, np.cos(2*3.14*100*t))
self.axes_Yi=self.figure.add_subplot(313)
self.axes_Yi.plot(t, np.tan(2*3.14*100*t))
self.canvas.setGeometry(0, 0, 1600, 500 )
layout = QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
self.setLayout(layout)
def loaddatapickle(self):
fileName = QFileDialog.getOpenFileName(self,'Load Data', '', 'pickle (*.pickle)')
if (fileName[0] == '') :
return
fileName = str(fileName[0])
filehandler = open(fileName , 'rb')
self.figure = pickle.load(filehandler)
filehandler.close()
self.canvas.draw()
self.parent.parent.processEvents()
return
def saveFigData(self):
fileName = QFileDialog.getSaveFileName(self,'Save Figure Data', '', 'pickle (*.pickle)')
if (fileName[0] == '') :
return
fileName = str(fileName[0])
file_pi = open(fileName, 'wb')
pickle.dump(self.figure, file_pi, -1)
file_pi.close()
return
def main():
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.showMaximized()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The save seems works (well, at least, I have a file), but the load button do absolutly nothing !
Even If I have a .pickle file, I don't know if pickle save the correct binary of the figure because when I load the pickle file in debug mode, I get lot of red stuff.
Look for the below image :
If I do the code without PyQt5, it works fine, for instance, with the below code:
import pickle
import matplotlib
import numpy as np
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
def loaddatapickle():
filehandler = open('test.pickle' , 'rb')
figure = pickle.load(filehandler )
filehandler.close()
return figure
def saveFigData(figure):
file_pi = open('test.pickle', 'wb')
pickle.dump(figure , file_pi, 1)
file_pi.close()
return
figure = plt.figure( ) #Figure()
Save= 0
if Save==1:
t=np.arange(1000)
axes_l=figure.add_subplot(311)
axes_l.plot(t, np.sin(2*3.14*100*t))
axes_Y=figure.add_subplot(312)
axes_Y.plot(t, np.cos(2*3.14*100*t))
axes_Yi=figure.add_subplot(313)
axes_Yi.plot(t, np.tan(2*3.14*100*t))
saveFigData(figure)
else:
figure=loaddatapickle()
plt.show()
If somebody have an idea of what is going on here, please tell me !
Have a nice day.
I can't be sure if this solves the problem you are facing, but let's give it a try. I need to mention, I don't have QT5 available and I'm working with python 2.7 and matplotlib 2.0.0. But the solution here might be valid for general cases.
When adapting the program to pyqt4 and running it, I found out that the pickling works fine. Also the unpickling did not throw any error, so I suspected that there might be a problem of displaying the unpickled figure.
What turns out to allow loading the figure is to not only load the figure into self.figure but to recreate the canvas with this unpickled figure and newly add it to the layout:
def loaddatapickle(self):
#needed to change some stuff here, since in Qt4 the dialog directly returns a string
fileName = QFileDialog.getOpenFileName(self,'Load Data', '' )
if (fileName == '') :
return
fileName = str(fileName)
filehandler = open(fileName , 'rb')
self.figure = pickle.load(filehandler)
filehandler.close()
# remove the old canvas
self.layout().removeWidget(self.canvas)
# create a new canvas
self.canvas = FigureCanvas(self.figure)
# add the new canvas at the position of the old one
self.layout().addWidget(self.canvas, 1)
self.canvas.draw()
self.parent.parent.processEvents()
return
Of course it would be better to directly update the canvas with the new figure, but I haven't found any way to do that.

pyqt5 videowidget not showing in layout

I am writing a program with pyqt5 where pressing a button first cycles through some pictures then cycles through some videos.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
import argparse
import sys
class MainWindow(QMainWindow):
def __init__(self,args):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = CentralWidget(args)
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
QCoreApplication.instance().quit()
self.centralwidget.startvid()
class CentralWidget(QWidget):
def __init__(self,args):
super(CentralWidget, self).__init__()
self.layout = QVBoxLayout()
self.layout.setAlignment(Qt.AlignCenter)
self.setLayout(self.layout)
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.vw = QVideoWidget()
self.player.setVideoOutput(self.vw)
def startvid(self):
self.layout.addWidget(self.vw)
url= QUrl.fromLocalFile(glob.glob("videos/*")[0])
content= QMediaContent(url)
self.player.setMedia(content)
self.player.setVideoOutput(self.vw)
self.player.play()
if __name__== "__main__":
parser = argparse.ArgumentParser()
#~ parser.add_argument("-nb","--nobox",action="store_true", help="do not wait for the box connection")
args = parser.parse_args()
app = QApplication(sys.argv)
mainwindow = MainWindow(args)
#~ mainwindow.showFullScreen()
mainwindow.show()
sys.exit(app.exec_())
I tried to paste the minimal code. The thing is, I press the button nothing shows, although I used examples like this one PyQt5 - Can't play video using QVideoWidget to test if playing the video is ok, and these work. It's as if it is not adding the widget to the layout or something. Any idea what might be wrong?
I had to use QGraphicsView to achieve what I wanted, here is a fix:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = VideoPlayer()
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
self.centralwidget.phaseQuit(2)
self.centralwidget.play()
class VideoPlayer(QWidget):
def __init__(self, parent=None):
super(VideoPlayer, self).__init__(parent)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.videoItem = QGraphicsVideoItem()
self.videoItem.setSize(QSizeF(640, 480))
scene = QGraphicsScene(self)
graphicsView = QGraphicsView(scene)
scene.addItem(self.videoItem)
layout = QVBoxLayout()
layout.addWidget(graphicsView)
self.setLayout(layout)
self.mediaPlayer.setVideoOutput(self.videoItem)
self.counter = 0
def play(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
pass
else:
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(glob.glob("videos/*")[self.counter])))
self.mediaPlayer.play()
self.counter += 1
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
player = MainWindow()
player.show()
sys.exit(app.exec_())

How to implement QThread correctly with matplotlib and pyplot

I understand that there have been one or two other questions posted that are related but not exactly what I need. I'm building this gui that activates a module by clicking a button. This python module that gets activated by pushing the button generates heatmaps from multiple pandas dataframes and saves those images, which in turn is then saved into an xlsx using pandas ExcelWriter.
I've tried to implement QThread, as other stackoverflow examples tried to explain similar problems but I continue getting this error: "It is not safe to use pixmaps outside the GUI thread". I understand that technically I'm not creating the heatmap inside the MAIN gui thread but I thought with QThread that I am still inside "a" gui thread. These dataframes that the heatmaps are based off of can be of a large size at times and I am somewhat grasping the concept of sending a signal to the main gui thread when a heatmap is to be created and have the heatmap function inside the main gui class...but I fear that will be troublesome later in passing so much data around..this is more like pipelining than threading. I just want this working thread to create these images and save them and then take those saved files and save them into an xlsx without interrupting the main gui..
(NOTE: This is a simplified version, in the real program there will be several of these threads created almost simultaneously and inside each thread several heatmaps will be created)
---main.py---
import sys
from MAIN_GUI import *
from PyQt4 import QtGui, QtCore
from excel_dummy import *
if __name__=="__main__":
app = QtGui.QApplication(sys.argv)
class MAIN_GUI(QtGui.QMainWindow):
def __init__(self):
super(MAIN_GUI, self).__init__()
self.uiM = Ui_MainWindow()
self.uiM.setupUi(self)
self.connect(self.uiM.updateALL_Button,QtCore.SIGNAL('clicked()'),self.newThread)
def newThread(self):
Excelify = excelify()
Excelify.start()
self.connect(Excelify,QtCore.SIGNAL('donethread(QString)'),(self.done))
def done(self):
print('done')
main_gui = MAIN_GUI()
main_gui.show()
main_gui.raise_()
sys.exit(app.exec_())
---excel_dummy.py---
import os, pandas as pd
from pandas import ExcelWriter
import numpy as np
import seaborn.matrix as sm
from PyQt4 import QtCore
from PyQt4.QtCore import QThread
from matplotlib.backends.backend_agg import FigureCanvas
from matplotlib.figure import Figure
import time
class excelify(QThread):
def __init__(self):
QThread.__init__(self)
def run(self):
path = 'home/desktop/produced_files'
with ExcelWriter(path + '/final.xlsx', engine='xlsxwriter') as writer:
workbook = writer.book
worksheet = workbook.add_worksheet()
heatit = self.heatmap()
worksheet.insert_image('C3',path + '/' + 'heat.jpg')
worksheet.write(2, 2, 'just write something')
writer.save()
print('file size: %s "%s"' % (os.stat(path).st_size, path))
time.slee(0.3)
self.emit(QtCore.SIGNAL('donethread(QString)'),'')
def heatmap(self):
df = pd.DataFrame(np.array([[1,22222,33333],[2,44444,55555],[3,44444,22222],[4,55555,33333]]),columns=['hour','in','out'])
dfu = pd.DataFrame(df.groupby([df.in,df.hour]).size())
dfu.reset_index(inplace=True)
dfu.rename(columns={'0':'Count'})
dfu.columns=['in','hour','Count']
dfu_2 = dfu.copy()
mask=0
fig = Figure()
ax = fig.add_subplot(1,1,1)
canvas = FigureCanvas(fig)
df_heatmap = dfu_2.pivot('in','hour','Count').fillna(0)
sm.heatmap(df_heatmap,ax=ax,square=True,annot=False,mask=mask)
fig.savefig(path + '/' + heat.jpg')
---MAIN_GUI.py---
from PyQt4 import QtCore,QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.unicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(320,201)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.updateALL_Button = QtGui.QPushButton(self.centralwidget)
self.updateALL_Button.setGeometry(QtCore.QRect(40,110,161,27))
self.updateALL_Button.setFocusPolicy(QtCore.Qt.NoFocus)
self.updateALL_Button.setObjectName(_fromUtf8("Options_updateALL_Button"))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 320, 24))
self.menubar.setObjectName(_fromUtf8("menubar"))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self,MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.updateALL_Button.setText(_translate("MainWindow", "updateALL", None))
Even though you are explicitely using the Agg backend to generate your figure, it looks like Seaborn is still using the default backend on your system, which is most likely Qt4Agg, an interactive backend. We want Seaborn to use a non-interactive backend instead to avoid any error (see matplotlib documentation for more details about backends). To do so, tell Matplotlib in your imports to use the Agg backend and import Seaborn after Matplotlib.
You will also need to save your figure as a png, since jpg is not supported by the Agg backend. Unless you have some specific reasons for using jpg, png is usually a better format for graphs.
Finally, you could use a memory buffer instead of saving your images to a temporary file before saving them in an Excel Workbook. I haven't tested it, but it will probably be faster if you are working with large files.
Below is a MWE I've written which includes the aformentioned points and which does not give any error on my system in Python3.4:
import pandas as pd
import time
from pandas import ExcelWriter
import numpy as np
from PyQt4 import QtCore, QtGui
import matplotlib as mpl
mpl.use('Agg')
from matplotlib.backends.backend_agg import FigureCanvas
import seaborn.matrix as sm
try: # Python 2 (not tested)
from cStringIO import StringIO as BytesIO
except ImportError: # Python 3
from io import BytesIO
class MAIN_GUI(QtGui.QWidget):
def __init__(self):
super(MAIN_GUI, self).__init__()
self.worker = Excelify()
btn = QtGui.QPushButton('Run')
disp = QtGui.QLabel()
self.setLayout(QtGui.QGridLayout())
self.layout().addWidget(btn, 0, 0)
self.layout().addWidget(disp, 2, 0)
self.layout().setRowStretch(1, 100)
btn.clicked.connect(self.worker.start)
self.worker.figSaved.connect(disp.setText)
class Excelify(QtCore.QThread):
figSaved = QtCore.pyqtSignal(str)
def run(self):
self.figSaved.emit('Saving figure to Workbook.')
t1 = time.clock()
image_data = self.heatmap()
with ExcelWriter('final.xlsx', engine='xlsxwriter') as writer:
wb = writer.book
ws = wb.add_worksheet()
ws.insert_image('C3', 'heat.png', {'image_data': image_data})
writer.save()
t2 = time.clock()
self.figSaved.emit('Done in %f sec.' % (t2-t1))
def heatmap(self):
df = pd.DataFrame(np.array([[1, 22222, 33333], [2, 44444, 55555],
[3, 44444, 22222], [4, 55555, 33333]]),
columns=['hour', 'in', 'out'])
dfu = pd.DataFrame(df.groupby([df.out, df.hour]).size())
dfu.reset_index(inplace=True)
dfu.rename(columns={'0': 'Count'})
dfu.columns = ['in', 'hour', 'Count']
fig = mpl.figure.Figure()
fig.set_canvas(FigureCanvas(fig))
ax = fig.add_subplot(111)
df_heatmap = dfu.pivot('in', 'hour', 'Count').fillna(0)
sm.heatmap(df_heatmap, ax=ax, square=True, annot=False, mask=0)
buf= BytesIO()
fig.savefig(buf, format='png')
return(buf)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MAIN_GUI()
w.show()
w.setFixedSize(200, 100)
sys.exit(app.exec_())