Why does my GUI go unresponsive even though I'm outsourcing to a worker thread?
===

I have a PyQt4 GUI in which I need to save a stack of Numpy arrays as *.tif images. This seems to take a significant amount of time and causes my GUI to go unresponsive for up to several minutes, depending on the number of images in the stack.

The bulk of the processing happens in this loop over the images:
    
    for i in range(0, np.shape(dataStack)[2]):

            print('Saving slice ' + str(i + 1))
            
            #Save tumor stack
            im1 = Image.fromarray(tumorStack[:,:,i]*255)
            im1.save(saveLocationStr + 'Slice' + str(i+1) + '.tif')
            
            #Set up correct number of subplots for review plot.
            if T0 is not None:
                plt.subplot(141)
            else:
                plt.subplot(131)
                
            #Plot current brain slice in 1st position
            plt.imshow(dataStack[:,:,i], cmap=mpl.cm.bone)
            plt.axis('off')
            
            plt.title(patient + '\n' + date + '\n' + 'Slice ' + str(i+1) + ' of ' + str(int(np.shape(dataStack)[2])))
            
            #Select correct next subplot
            if T0 is not None:
                plt.subplot(142)
            else:
                plt.subplot(132)
                
            #Get a masked copy of the tumorStack 
            tempTumorStack = copy.deepcopy(tumorStack[:,:,i])
            tempTumorStack = np.ma.masked_where(tempTumorStack == 0, tempTumorStack)
           
            #Plot masked tumor stack over brain data
            plt.imshow(dataStack[:,:,i], cmap=mpl.cm.bone)
            plt.imshow(tempTumorStack, cmap=mpl.cm.jet_r, interpolation='nearest')
            plt.axis('off')
            
            plt.title(modality + ' Region')
            
            #Get the auto-zoomed region and plot it
            (x, y) = tumorStack[:,:,i].nonzero()
            if( int(np.shape(x)[0]) == 0 or int(np.shape(y)[0]) == 0):
                if T0 is not None:
                    plt.subplot(143)
                    plt.imshow(T0[:,:,i], cmap=mpl.cm.bone)
                    plt.axis('off')
                    
                    plt.title('T0')
                    
                    #Plot autozoomed with perimiter over brain data
                    plt.subplot(144)
                    plt.imshow(np.zeros(np.shape(dataStack[:,:,i])), cmap=mpl.cm.bone)
                    
                    plt.title('Perimiter of \n' + modality + ' + T0 for SA')
                    
                    plt.axis('off')
                    
                else:
                    plt.subplot(133)
                    plt.imshow(np.zeros(np.shape(dataStack[:,:,i])), cmap=mpl.cm.bone)
                    
                    plt.title('Perimiter of \n' + modality + ' for SA')
                    
                    plt.axis('off')
                    
            else:
                minX = np.min(x)
                minY = np.min(y)
                maxX = np.max(x)
                maxY = np.max(y)
                
                zoomedXmin =  minX - (minX * .10)
                zoomedXmax = (maxX * .10) + maxX
                zoomedYmin =  minY - (minY * .10)
                zoomedYmax =  (maxY * .10) + maxY
                
                widthOf = zoomedXmax - zoomedXmin
                heigthOf = zoomedYmax - zoomedYmin

                #Get perimiter of tumor for autozoomed region
                #Can do n=8 if we want
                #tempTumorStack = bwperim(tempTumorStack,n=8)
                tempTumorStack = mahotas.labeled.borders(tempTumorStack)
                tempTumorStack = np.where(tempTumorStack == np.max(tempTumorStack), 1, np.nan)
                
                #Plot T0 then auto-zoomed if user wanted T0
                if T0 is not None:
                    plt.subplot(143)
                    plt.imshow(T0[:,:,i], cmap=mpl.cm.bone)
                    plt.axis('off')
                    
                    plt.title('T0')
                    
                    #Plot autozoomed with perimiter over brain data
                    plt.subplot(144)
                    plt.imshow(dataStack[int(zoomedXmin):int(zoomedXmax), int(zoomedYmin):int(zoomedYmax), i ], cmap=mpl.cm.bone)
                    plt.imshow(tempTumorStack[int(zoomedXmin):int(zoomedXmax), int(zoomedYmin):int(zoomedYmax) ], cmap=mpl.cm.jet_r)
                    #plt.xlim(minX, maxX-minX)
                    #plt.ylim(minY, maxY-minY)
                    
                    plt.title('Perimiter of \n' + modality + ' + T0 for SA')
                    
                    plt.axis('off')
                    
                #Just plot autozoomed
                else:
                    plt.subplot(133)
                    plt.imshow(dataStack[int(zoomedXmin):int(zoomedXmax), int(zoomedYmin):int(zoomedYmax), i ], cmap=mpl.cm.bone)
                    plt.imshow(tempTumorStack[int(zoomedXmin):int(zoomedXmax), int(zoomedYmin):int(zoomedYmax) ], cmap=mpl.cm.jet_r)
                    
                    plt.title('Perimiter of \n' + modality + ' for SA')
                    
                    plt.axis('off')
            
            #Finish setting up plot to specs, render, and save it
            plt.subplots_adjust(wspace=.5)
            plt.axis('off')
            plt.tick_params(bottom='off', top='off', left='off', right='off')
            plt.draw()
            plt.savefig(saveLocationStr + 'MRI_Comparison\\Slice' + str(i+1) + '.png', dpi=200)

I figured I would outsource the expensive work to a PyQt4 worker QThread, so following the example at <http://diotavelli.net/PyQtWiki/Threading,_Signals_and_Slots> I created a worker class that inherits from QtCore.QThread, called all the above code inside the run method of this class, and created and start()ed an instance of this class where the *.tif stack saving needs to occur in the main window.

The GUI still goes unresponsive as it did previously, but the thread seems to be successfully executing the code. I am concerned that perhaps some package used in the code above is not properly releasing the GIL (as referenced here <http://www.riverbankcomputing.com/pipermail/pyqt/2011-August/030470.html>). Is there a way to manually ensure this is working?

I have commented out and replaced the *.tif stack saving code with a time.sleep delay, and the GUI still goes unresponsive, so perhaps I am implementing QThread wrong?

Am I missing something else? Have I provided enough information?