Brief description on what I'm trying to achieve:
I'm working on a analytics software built using Python, wxPython, and matplotlib. I'm trying to implement a function where the program can plot the results after performing some analytical calculations. At the moment, the program freezes when the it's performing the calculations (and the calculation time takes up to 10 seconds depending on the amount of data) so I'm trying to use threading to create a non-blocking program to improve user experience.
Problem I'm getting
I keep getting this error : (PyAssertionError: C++ assertion "hdcDst && hdcSrc" failed at ...... \\src\\msw\\dc.cpp(2559) in AlphaBlt():AlphaBlt():invalid HDC)
and googling hasn't really help with identifying the cause.
I'll post the full traceback at the bottom of the post.
Here's my code:
import wx
import time
import matplotlib.pyplot as plt
from wx.lib.pubsub import Publisher as pub
from threading import Thread
def plotgraph(x,y,sleeptime):
plt.plot(x,y)
#Simulate long process using time.sleep
time.sleep(sleep time)
#Send out a message once process is completed
pub.sendMessage('PLOT','empty')
class listener():
def __init__(self,name):
self.name = name
#Listens to message
pub.subscribe(self.Plot,'PLOT')
pass
def Plot(self,message):
print self.name
plt.show()
print 'printed'
waiting = listener('Bob')
t1 = Thread(target=plotgraph,args=([1,2,3],[1,2,3],5))
t1.start()
t2 = Thread(target=plotgraph,args=([1,2,3],[1,2,3],3))
t2.start()
Basically, the user will be clicking an icon on the GUI and that will trigger a function to perform some analytical calculation simulated by 'plotgraph()' here. At the moment, without using threads, plotgraph() will block my entire program, so I'm trying to use threads to perform the calculations to free up my GUI.
However when I tried to plot my GUI within the thread, ie have plt.show() in plotgraph(), the plot appears then disappears again. When I click the button on the GUI to spawn the thread a second time, I get the same error.
So I've tried to work around it by sending a message after the thread's ended so that the plt.show() will happen outside the thread but I'm still getting the same error.
I can't seem to be able to find a similar error online, except for one thread posted in 2008. If anyone could help that would be awesome!
In a nutshell I need a way to implement sort of a callback function that allows me to perform the analytic calculation in a thread, then plot the graph once the calculations are completed to free up my GUI. It'd be great if someone could explain to me what's wrong here, or could suggest an alternative method to do it. Thanks very much!!
Here's the full traceback:
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\App\appdata\canopy-1.
.5.3123.win-x86\lib\threading.py", line 810, in __bootstrap_inner
self.run()
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\App\appdata\canopy-1.
.5.3123.win-x86\lib\threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "<ipython-input-5-0cb01f87e97a>", line 13, in plotgraph
pub.sendMessage('PLOT','empty')
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\wx\lib\pubsub.py", line 811, in sendMessage
self.__topicTree.sendMessage(aTopic, message, onTopicNeverCreated)
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\wx\lib\pubsub.py", line 498, in sendMessage
deliveryCount += node.sendMessage(message)
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\wx\lib\pubsub.py", line 336, in sendMessage
listener(message)
File "<ipython-input-5-0cb01f87e97a>", line 24, in Plot
plt.show()
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\matplotlib\pyplot.py", line 155, in show
return _show(*args, **kw)
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\matplotlib\backend_bases.py", line 154, in __call__
manager.show()
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\matplotlib\backends\backend_wx.py", line 1414, in show
self.canvas.draw()
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\matplotlib\backends\backend_wxagg.py", line 50, in draw
self.gui_repaint(drawDC=drawDC)
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\matplotlib\backends\backend_wx.py", line 911, in gui_repaint
drawDC.DrawBitmap(self.bitmap, 0, 0)
File "C:\Users\chaishen\AppData\Local\Enthought\Canopy32\User\lib\site-package
\wx\_gdi.py", line 3460, in DrawBitmap
return _gdi_.DC_DrawBitmap(*args, **kwargs)
yAssertionError: C++ assertion "hdcDst && hdcSrc" failed at ..\..\src\msw\dc.cp
(2559) in AlphaBlt(): AlphaBlt(): invalid HDC
I think what you need is the wx.PyEventBinder. It works like this:
anEVT_CALCULATED = wx.NewEventType()
EVT_CALCULATED = wx.PyEventBinder(anEVT_CALCULATED, 1)
def onCalculate(self, event): # this is your click
calc_thread = CalculatorThread(self, params)
calc_thread.start()
return
def onConnected(self, event):
''' this is where your thread comes back '''
self.doSomeThingLikePlotting(event.resultdata)
class CalcEvent(wx.PyCommandEvent):
''' Event to signal that the thread has calculated'''
def __init__(self, etype, eid, resultdata):
wx.PyCommandEvent.__init__(self, etype, eid)
self.resultdata = resultdata
class CalculatorThread(threading.Thread):
''' This is the thread doing your calculation and handing it back'''
def __init__(self, listener, params):
threading.Thread.__init__(self)
self.listener = listener
self.params = params
def run(self):
resultdata = calculate(params) # this is your calculation
event = CalcEvent(anEVT_CALCULATED, -1, resultdata=resultdata)
wx.PostEvent(self.listener, event)
return
And of course you need to add one line to your __init__
self.Bind(EVT_CONNECTED, self.onCalculated)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.