pythonmultithreadingpysidetraitschaco

Starting a new event loop for chaco-traits popup window from pyside?


I am trying to make a numpy image slider using chaco which is launched from PySide. Ive tried using matplotlib but it lacked the speed for updating so Ive been trying chaco instead. The script below starts by initializing a Pyside dialog, from here I am trying to open a chaco/traits window which is used to display different views of numpy arrays using a slider to scroll through the arrays like a movie. The script works but I get a warning message:

QCoreApplication::exec: The event loop is already running 

I think I probably need to start the chaco window using its own thread or something but am not sure how to go about it. Any help much would be appreciated, the script is below:

import numpy as np
import sys
from PySide.QtCore import *
from PySide.QtGui import *

app = QApplication(sys.argv)

from traits.api import *
from traitsui.api import *
from enable.api import *
from enable.component_editor import *
from chaco.api import *
from chaco.tools.api import *
from chaco import *


class chacoWindow(HasTraits):
    #Chaco popup window with slider
    plot = Instance(HPlotContainer)
    #Slider max value is set using Frame
    Frame = Int
    high = 100

    traits_view = View(Group(
                    Item('plot', 
                             editor=ComponentEditor(), 
                             show_label=False),
                    Item( 'Frame', 
                             editor = RangeEditor( 
                             high_name   = 'high',
                             format      = '%d',
                             is_float    = False))),
                   width=1000, height=600, resizable=True, title="Track viewer")

    def __init__(self, dataDict, arg1):

        self.high = arg1 - 1
        self.dataDict = dataDict

        self.data1 = self.dataDict['Movie1']
        self.data2 = self.dataDict['Movie2']

        #Left plot
        self.plotdata1 = ArrayPlotData(image1 = self.data1['0'])
        plotLeft = Plot(self.plotdata1)
        plotLeft.img_plot("image1")               
        #Right plot  
        self.plotdata2 = ArrayPlotData(image2 = self.data2['0'])
        plotRight = Plot(self.plotdata2)
        plotRight.img_plot("image2")

        #Add some zoom/pan tools
        plotLeft.tools.append(PanTool(plotLeft))
        plotLeft.tools.append(BetterZoom(plotLeft, zoom_factor=0.8, zoom_to_mouse = True))
        plotLeft.tools.append(DragZoom(plotLeft, drag_button="right"))   
        plotRight.tools.append(PanTool(plotRight))
        plotRight.tools.append(BetterZoom(plotRight))
        plotRight.tools.append(DragZoom(plotRight, drag_button="right"))
        #Axes shared          
        plotLeft.range2d = plotRight.range2d
        container = HPlotContainer(plotLeft, plotRight)
        self.plot = container

    def _Frame_changed(self):
        #Change frame when slider changes
        self.plotdata1.set_data("image1", self.data1[str(self.Frame)])
        self.plotdata2.set_data("image2", self.data2[str(self.Frame)])


class Form(QDialog):
    #Basic form dialog using Pyside
    def __init__(self, dataDict, parent=None):
        super(Form, self).__init__(parent)
        self.dataDict = dataDict 
        self.totalFrames = len(dataDict['Movie1'])
        formatButton1 = QPushButton("Format 1")        
        buttonLayout = QHBoxLayout()
        buttonLayout.addStretch()
        buttonLayout.addWidget(formatButton1)
        #Add VBox space for extra widgets
        layout = QVBoxLayout()        
        layout.addLayout(buttonLayout)
        self.setLayout(layout)
        self.connect(formatButton1, SIGNAL("clicked()"), self.setChaco)                     
        self.setWindowTitle('Master form')

    def setChaco(self):
        #Create chaco window instance
        scatter = chacoWindow(dataDict, self.totalFrames)
        scatter.configure_traits(self) 


if __name__ == "__main__":       
    #make some demo data
    ar0 = np.zeros((25,25))
    ar0[10][10] = 1
    ar1 = np.zeros((25,25))
    ar1[12][12] = 1    
    #Dictionary of images
    dataDict = {'Movie1': {'0': ar0, '1':ar1, '2':ar0}, 
                'Movie2': {'0': ar1, '1':ar0, '2':ar1}}
    form = Form(dataDict)
    form.show()
    app.exec_()

Solution

  • I managed to find the solution. Changing this function solves the problem:

    def setChaco(self):
        #Create chaco window instance
        scatter = chacoWindow(dataDict, self.totalFrames)
        #Change this line: scatter.configure_traits(self)
        scatter.edit_traits() 
    

    This appears to let the PySide event loop handle everything.