def __init__(self,
                 parent,
                 dstack=None,
                 do=None,
                 xvals=None,
                 xlabel='',
                 ylabel=''):

        if (dstack is None and do is None):
            dstack = np.zeros((10, 10))

        if do is None:
            self.do = DisplayOpts(dstack)
            self.do.Optimise()
        else:
            self.do = do

        self.do.WantChangeNotification.append(self.draw)

        if xvals is None:
            xvals = np.arange(self.do.ds.shape[0])

        self.xvals = xvals
        self.xlabel = xlabel

        fastGraph.FastGraphPanel.__init__(self, parent, -1, self.xvals,
                                          self.do.ds[:, :])
示例#2
0
    def __init__(self,
                 parent,
                 dstack=None,
                 do=None,
                 xvals=None,
                 xlabel='',
                 ylabel=''):
        wx.Panel.__init__(self, parent)

        if (dstack is None and do is None):
            dstack = np.zeros((10, 10))

        if do is None:
            self.do = DisplayOpts(dstack)
            self.do.Optimise()
        else:
            self.do = do

        self.do.WantChangeNotification.append(self.draw)

        self.xvals = xvals
        self.xlabel = xlabel
        self.ylabel = ylabel

        sizer1 = wx.BoxSizer(wx.VERTICAL)

        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self, -1, self.figure)

        sizer1.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND)

        #self.toolbar = NavigationToolbar2WxAgg(self.canvas)
        #self.toolbar = MyNavigationToolbar(self.canvas, self)
        #self.toolbar.Realize()

        #        if wx.Platform == '__WXMAC__':
        #            # Mac platform (OSX 10.3, MacPython) does not seem to cope with
        #            # having a toolbar in a sizer. This work-around gets the buttons
        #            # back, but at the expense of having the toolbar at the top
        #            self.SetToolBar(self.toolbar)
        #        else:
        #            # On Windows platform, default window size is incorrect, so set
        #            # toolbar width to figure width.
        #            tw, th = self.toolbar.GetSizeTuple()
        #            fw, fh = self.canvas.GetSizeTuple()
        #            # By adding toolbar in sizer, we are able to put it at the bottom
        #            # of the frame - so appearance is closer to GTK version.
        #            # As noted above, doesn't work for Mac.
        #            self.toolbar.SetSize(wx.Size(fw, th))
        #
        #            sizer1.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)

        self.Bind(wx.EVT_SIZE, self._onSize)

        #self.toolbar.update()
        self.SetSizer(sizer1)
        self.draw()
示例#3
0
class GraphViewPanel(fastGraph.FastGraphPanel):
    def __init__(self, parent, dstack=None, do=None, xvals=None, xlabel=''):

        if (dstack == None and do == None):
            dstack = np.zeros((10, 10))

        if do == None:
            self.do = DisplayOpts(dstack)
            self.do.Optimise()
        else:
            self.do = do

        self.do.WantChangeNotification.append(self.draw)

        if xvals == None:
            xvals = np.arange(self.do.ds.shape[0])

        self.xvals = xvals
        self.xlabel = xlabel

        fastGraph.FastGraphPanel.__init__(self, parent, -1, self.xvals,
                                          self.do.ds[:, :])

        #self.draw()

    def draw(self, event=None):
        self.SetData(self.xvals, self.do.ds[:, :])
示例#4
0
class GraphViewPanel(wx.Panel):
    def __init__(self, parent, dstack=None, do=None, xvals=None, xlabel=''):
        wx.Panel.__init__(self, parent)

        if (dstack == None and do == None):
            dstack = scipy.zeros((10, 10))

        if do == None:
            self.do = DisplayOpts(dstack)
            self.do.Optimise()
        else:
            self.do = do

        self.do.WantChangeNotification.append(self.draw)

        self.xvals = xvals
        self.xlabel = xlabel

        sizer1 = wx.BoxSizer(wx.VERTICAL)

        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self, -1, self.figure)

        sizer1.Add(self.canvas, 1, wx.TOP | wx.LEFT | wx.EXPAND)

        #self.toolbar = NavigationToolbar2WxAgg(self.canvas)
        #self.toolbar = MyNavigationToolbar(self.canvas, self)
        #self.toolbar.Realize()

        #        if wx.Platform == '__WXMAC__':
        #            # Mac platform (OSX 10.3, MacPython) does not seem to cope with
        #            # having a toolbar in a sizer. This work-around gets the buttons
        #            # back, but at the expense of having the toolbar at the top
        #            self.SetToolBar(self.toolbar)
        #        else:
        #            # On Windows platform, default window size is incorrect, so set
        #            # toolbar width to figure width.
        #            tw, th = self.toolbar.GetSizeTuple()
        #            fw, fh = self.canvas.GetSizeTuple()
        #            # By adding toolbar in sizer, we are able to put it at the bottom
        #            # of the frame - so appearance is closer to GTK version.
        #            # As noted above, doesn't work for Mac.
        #            self.toolbar.SetSize(wx.Size(fw, th))
        #
        #            sizer1.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)

        self.Bind(wx.EVT_SIZE, self._onSize)

        #self.toolbar.update()
        self.SetSizer(sizer1)
        self.draw()

    def draw(self, event=None):
        self.axes.cla()

        if self.xvals == None:
            xvals = np.arange(self.do.ds.shape[0])
        else:
            xvals = self.xvals

        for i in range(self.do.ds.shape[3]):
            self.axes.plot(xvals,
                           self.do.ds[:, self.do.yp, self.do.zp, i].squeeze(),
                           label=self.do.names[i])

        if self.do.ds.shape[3] > 1:
            self.axes.legend()
        self.axes.set_xlabel(self.xlabel)

        self.canvas.draw()

    def _onSize(self, event):
        #self._resizeflag = True
        self._SetSize()

    def _SetSize(self):
        pixels = tuple(self.GetClientSize())
        self.SetSize(pixels)
        self.canvas.SetSize(pixels)
        self.figure.set_size_inches(
            float(pixels[0]) / self.figure.get_dpi(),
            float(pixels[1]) / self.figure.get_dpi())
示例#5
0
    def __init__(self, image,  parent=None, title='', mode='LM', 
                 size = (800,700), glCanvas=None):
        AUIFrame.__init__(self,parent, -1, title,size=size, pos=wx.DefaultPosition)

        self.mode = mode
        self.glCanvas = glCanvas
        
        self.updateHooks = []
        self.statusHooks = []
        self.installedModules = []
        
        # will store weakrefs to things that modules previously injected into our namespace
        #self._module_injections = weakref.WeakValueDictionary()
        
        self.dataChangeHooks = []

        self.updating = False

        if glCanvas:
            self.glCanvas.wantViewChangeNotification.add(self)

        

        self.timer = mytimer()
        self.timer.Start(10000)

        self.image = image
        #self.image = ImageStack(data = dstack, mdh = mdh, filename = filename, queueURI = queueURI, events = None)
        if not self.image.filename is None and title == '':
            self.SetTitle(self.image.filename)

        

        self.do = DisplayOpts(self.image.data)
        if self.image.data.shape[1] == 1:
            self.do.slice = self.do.SLICE_XZ
        self.do.Optimise()

        if self.image.mdh and 'ChannelNames' in self.image.mdh.getEntryNames():
            chan_names = self.image.mdh.getEntry('ChannelNames')
            if len(chan_names) == self.image.data.shape[3]:
                self.do.names = chan_names

        #self.vp = ArraySettingsAndViewPanel(self, self.image.data, wantUpdates=[self.update], mdh=self.image.mdh)
        #self.view = ArrayViewPanel(self, do=self.do)
        #self.AddPage(self.view, True, 'Data')
        #self._mgr.AddPane(self.vp, aui.AuiPaneInfo().
        #                  Name("Data").Caption("Data").Centre().CloseButton(False).CaptionVisible(False))

        

        self.mainFrame = weakref.ref(self)
        #self.do = self.vp.do
        
        
        tmp_menu = wx.Menu()
        tmp_menu.Append(wx.ID_OPEN, '&Open', "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVE, "&Save As", "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVEAS, "&Export Cropped", "", wx.ITEM_NORMAL)
        

        #a submenu for modules to hook and install saving functions into
        self.save_menu = wx.Menu()
        self._menus['Save'] = self.save_menu
        tmp_menu.AppendMenu(-1, 'Save &Results', self.save_menu)
        
        #tmp_menu.AppendSeparator()
        #tmp_menu.Append(wx.ID_CLOSE, "Close", "", wx.ITEM_NORMAL)
        self.menubar.Append(tmp_menu, "File")
        self._menus['File'] = tmp_menu

        self.view_menu = wx.Menu()
        self.menubar.Append(self.view_menu, "&View")
        self._menus['View'] = self.view_menu

        #'extras' menu for modules to install stuff into
        self.mProcessing = wx.Menu()
        self.menubar.Append(self.mProcessing, "&Processing")
        self._menus['Processing'] = self.mProcessing

        # Menu Bar end
        self.Bind(wx.EVT_MENU, self.OnOpen, id=wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self.OnSave, id=wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, self.OnExport, id=wx.ID_SAVEAS)
        #self.Bind(wx.EVT_MENU, lambda e: self.Close(), id=wx.ID_CLOSE)
        
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
		
        self.statusbar = self.CreateStatusBar(1, wx.STB_SIZEGRIP)

        self.panesToMinimise = []

        modules.loadMode(self.mode, self)
        self.CreateModuleMenu()

        self.add_common_menu_items()

        self.optionspanel = OptionsPanel(self, self.do, thresholdControls=True)
        self.optionspanel.SetSize(self.optionspanel.GetBestSize())
        pinfo = aui.AuiPaneInfo().Name("optionsPanel").Right().Caption('Display Settings').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
        self._mgr.AddPane(self.optionspanel, pinfo)

        self.panesToMinimise.append(pinfo)

        self._mgr.AddPane(self.optionspanel.CreateToolBar(self), aui.AuiPaneInfo().Name("ViewTools").Caption("View Tools").CloseButton(False).
                      ToolbarPane().Right().GripperTop())

        if self.do.ds.shape[2] > 1:
            from PYME.DSView.modules import playback
            self.playbackpanel = playback.PlayPanel(self, self)
            self.playbackpanel.SetSize(self.playbackpanel.GetBestSize())

            pinfo1 = aui.AuiPaneInfo().Name("playbackPanel").Bottom().Caption('Playback').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
            self._mgr.AddPane(self.playbackpanel, pinfo1)
            self.do.WantChangeNotification.append(self.playbackpanel.update)

        #self.mWindows =  wx.Menu()
        #self.menubar.append(self.mWindows, '&Composite With')
        self.do.WantChangeNotification.append(self.update)

        self.CreateFoldPanel()
       

        for pn in self.panesToMinimise:
            self._mgr.MinimizePane(pn)
        #self._mgr.MinimizePane(pinfo2)
        self.Layout()

        if 'view' in dir(self):
            sc = np.floor(np.log2(1.0*self.view.Size[0]/self.do.ds.shape[0]))
            #print self.view.Size[0], self.do.ds.shape[0], sc
            self.do.SetScale(sc)
            self.view.Refresh()
        self.update()
        
        self.drop = dt()        
        self.SetDropTarget(self.drop)
        
        self.AddMenuItem('Save', 'To Cluster', self.OnSaveToCluster)
        
        
        
        openViewers[self.image.filename] = self
示例#6
0
class DSViewFrame(AUIFrame):
    def __init__(self, image,  parent=None, title='', mode='LM', 
                 size = (800,700), glCanvas=None):
        AUIFrame.__init__(self,parent, -1, title,size=size, pos=wx.DefaultPosition)

        self.mode = mode
        self.glCanvas = glCanvas
        
        self.updateHooks = []
        self.statusHooks = []
        self.installedModules = []
        
        # will store weakrefs to things that modules previously injected into our namespace
        #self._module_injections = weakref.WeakValueDictionary()
        
        self.dataChangeHooks = []

        self.updating = False

        if glCanvas:
            self.glCanvas.wantViewChangeNotification.add(self)

        

        self.timer = mytimer()
        self.timer.Start(10000)

        self.image = image
        #self.image = ImageStack(data = dstack, mdh = mdh, filename = filename, queueURI = queueURI, events = None)
        if not self.image.filename is None and title == '':
            self.SetTitle(self.image.filename)

        

        self.do = DisplayOpts(self.image.data)
        if self.image.data.shape[1] == 1:
            self.do.slice = self.do.SLICE_XZ
        self.do.Optimise()

        if self.image.mdh and 'ChannelNames' in self.image.mdh.getEntryNames():
            chan_names = self.image.mdh.getEntry('ChannelNames')
            if len(chan_names) == self.image.data.shape[3]:
                self.do.names = chan_names

        #self.vp = ArraySettingsAndViewPanel(self, self.image.data, wantUpdates=[self.update], mdh=self.image.mdh)
        #self.view = ArrayViewPanel(self, do=self.do)
        #self.AddPage(self.view, True, 'Data')
        #self._mgr.AddPane(self.vp, aui.AuiPaneInfo().
        #                  Name("Data").Caption("Data").Centre().CloseButton(False).CaptionVisible(False))

        

        self.mainFrame = weakref.ref(self)
        #self.do = self.vp.do
        
        
        tmp_menu = wx.Menu()
        tmp_menu.Append(wx.ID_OPEN, '&Open', "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVE, "&Save As", "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVEAS, "&Export Cropped", "", wx.ITEM_NORMAL)
        

        #a submenu for modules to hook and install saving functions into
        self.save_menu = wx.Menu()
        self._menus['Save'] = self.save_menu
        tmp_menu.AppendMenu(-1, 'Save &Results', self.save_menu)
        
        #tmp_menu.AppendSeparator()
        #tmp_menu.Append(wx.ID_CLOSE, "Close", "", wx.ITEM_NORMAL)
        self.menubar.Append(tmp_menu, "File")
        self._menus['File'] = tmp_menu

        self.view_menu = wx.Menu()
        self.menubar.Append(self.view_menu, "&View")
        self._menus['View'] = self.view_menu

        #'extras' menu for modules to install stuff into
        self.mProcessing = wx.Menu()
        self.menubar.Append(self.mProcessing, "&Processing")
        self._menus['Processing'] = self.mProcessing

        # Menu Bar end
        self.Bind(wx.EVT_MENU, self.OnOpen, id=wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self.OnSave, id=wx.ID_SAVE)
        self.Bind(wx.EVT_MENU, self.OnExport, id=wx.ID_SAVEAS)
        #self.Bind(wx.EVT_MENU, lambda e: self.Close(), id=wx.ID_CLOSE)
        
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
		
        self.statusbar = self.CreateStatusBar(1, wx.STB_SIZEGRIP)

        self.panesToMinimise = []

        modules.loadMode(self.mode, self)
        self.CreateModuleMenu()

        self.add_common_menu_items()

        self.optionspanel = OptionsPanel(self, self.do, thresholdControls=True)
        self.optionspanel.SetSize(self.optionspanel.GetBestSize())
        pinfo = aui.AuiPaneInfo().Name("optionsPanel").Right().Caption('Display Settings').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
        self._mgr.AddPane(self.optionspanel, pinfo)

        self.panesToMinimise.append(pinfo)

        self._mgr.AddPane(self.optionspanel.CreateToolBar(self), aui.AuiPaneInfo().Name("ViewTools").Caption("View Tools").CloseButton(False).
                      ToolbarPane().Right().GripperTop())

        if self.do.ds.shape[2] > 1:
            from PYME.DSView.modules import playback
            self.playbackpanel = playback.PlayPanel(self, self)
            self.playbackpanel.SetSize(self.playbackpanel.GetBestSize())

            pinfo1 = aui.AuiPaneInfo().Name("playbackPanel").Bottom().Caption('Playback').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
            self._mgr.AddPane(self.playbackpanel, pinfo1)
            self.do.WantChangeNotification.append(self.playbackpanel.update)

        #self.mWindows =  wx.Menu()
        #self.menubar.append(self.mWindows, '&Composite With')
        self.do.WantChangeNotification.append(self.update)

        self.CreateFoldPanel()
       

        for pn in self.panesToMinimise:
            self._mgr.MinimizePane(pn)
        #self._mgr.MinimizePane(pinfo2)
        self.Layout()

        if 'view' in dir(self):
            sc = np.floor(np.log2(1.0*self.view.Size[0]/self.do.ds.shape[0]))
            #print self.view.Size[0], self.do.ds.shape[0], sc
            self.do.SetScale(sc)
            self.view.Refresh()
        self.update()
        
        self.drop = dt()        
        self.SetDropTarget(self.drop)
        
        self.AddMenuItem('Save', 'To Cluster', self.OnSaveToCluster)
        
        
        
        openViewers[self.image.filename] = self
        
   

    def CreateModuleMenu(self):
        #self.modMenuIds = {}
        self.moduleNameByID = {}
        self.moduleMenuIDByName = {}
        self.mModules = wx.Menu()
        for mn in modules.allmodules():
            id = wx.NewId()
            self.mModules.AppendCheckItem(id, mn)
            self.moduleNameByID[id] = mn
            self.moduleMenuIDByName[mn] = id
            if mn in self.installedModules:
                self.mModules.Check(id, True)
                self.mModules.Enable(id, False)

            self.Bind(wx.EVT_MENU, self.OnToggleModule, id=id)

        self.menubar.Append(self.mModules, "&Modules")
        self._menus["&Modules"] = self.mModules
        

    def OnToggleModule(self, event):
        id = event.GetId()
        mn = self.moduleNameByID[id]
        #if self.mModules.IsChecked(id):
        
        self.LoadModule(mn)
         
        
    def LoadModule(self, moduleName):
        """Load a module with the given name and update GUI
        """
        
        modules.loadModule(moduleName, self)

        if moduleName in self.installedModules:
            id = self.moduleMenuIDByName[moduleName]
            self.mModules.Check(id, True)
            self.mModules.Enable(id, False)

        self.CreateFoldPanel()
        self._mgr.Update()
        

    def GetSelectedPage(self):
        nbs = self._mgr.GetNotebooks()
        currPage = nbs[0].GetCurrentPage()

        return currPage

    
    def create_overlay_panel(self):
        from PYME.DSView.OverlaysPanel import OverlayPanel
        if not 'overlaypanel' in dir(self):
            self.overlaypanel = OverlayPanel(self, self.view, self.image.mdh)
            self.overlaypanel.SetSize(self.overlaypanel.GetBestSize())
            pinfo2 = aui.AuiPaneInfo().Name("overlayPanel").Right().Caption('Overlays').CloseButton(
                False).MinimizeButton(True).MinimizeMode(
                aui.AUI_MINIMIZE_CAPT_SMART | aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
            self._mgr.AddPane(self.overlaypanel, pinfo2)
        
            self.panesToMinimise.append(pinfo2)
    


    def update(self):
        if not self.updating:
            self.updating = True
            #if 'view' in dir(self):
            #    self.view.Refresh()
            statusText = 'Slice No: (%d/%d)    x: %d    y: %d' % (self.do.zp, self.do.ds.shape[2], self.do.xp, self.do.yp)
            #grab status from modules which supply it
            for sCallback in self.statusHooks:
                statusText += '\t' + sCallback() #'Frames Analysed: %d    Events detected: %d' % (self.vp.do.zp, self.vp.do.ds.shape[2], self.vp.do.xp, self.vp.do.yp, self.LMAnalyser.numAnalysed, self.LMAnalyser.numEvents)
            self.statusbar.SetStatusText(statusText)

            #if 'playbackpanel' in dir(self):
            #    self.playbackpanel.update()

            #update any modules which require it
            for uCallback in self.updateHooks:
                #print uCallback
                uCallback(self)

            self.updating = False
            
    #def Redraw(self):
    #    self.v
            
    def DataChanged(self):
        for uCallback in self.dataChangeHooks:
            uCallback(self)

    def OnOpen(self, event=None):
        ViewIm3D(ImageStack())
        

    def OnSave(self, event=None):
        self.image.Save()
        self.SetTitle(self.image.filename)
        
    def OnSaveToCluster(self, event=None):
        from PYME.IO import clusterExport
        
        seriesName = clusterExport.suggest_cluster_filename(self.image)

        ted = wx.TextEntryDialog(None, 'Cluster filename:', 'Save file to cluster', seriesName)

        if ted.ShowModal() == wx.ID_OK:
            #pd = wx.ProgressDialog()
            clusterExport.ExportImageToCluster(self.image, ted.GetValue())

        ted.Destroy()

    def OnExport(self, event=None):
        bx = min(self.do.selection_begin_x, self.do.selection_end_x)
        ex = max(self.do.selection_begin_x, self.do.selection_end_x)
        by = min(self.do.selection_begin_y, self.do.selection_end_y)
        ey = max(self.do.selection_begin_y, self.do.selection_end_y)
        
        roi = [[bx, ex + 1],[by, ey + 1], [0, self.image.data.shape[2]]]
        
        self.image.Save(crop = True, roi=roi)

    def OnCrop(self):
        pass
        #View3D(self.image.data[])

    def OnCloseWindow(self, event):
        plt.close('all')
        if (not self.image.saved):
            dialog = wx.MessageDialog(self, "Save data stack?", "PYME", wx.YES_NO|wx.CANCEL)
            ans = dialog.ShowModal()
            if(ans == wx.ID_YES):
                self.OnSave()
                self._cleanup()
            elif (ans == wx.ID_NO):
                self._cleanup()
            else: #wxID_CANCEL:   
                if (not event.CanVeto()):
                    self._cleanup()
                else:
                    event.Veto()
        else:
            self._cleanup()

    def _cleanup(self):
        self.timer.Stop()
        del(self.image)
        
        AUIFrame._cleanup(self)

    def dsRefresh(self):
        #zp = self.vp.do.zp #save z -position
        self.do.SetDataStack(self.image.dataSource)
        #self.vp.do.zp = zp #restore z position
        self.elv.SetEventSource(self.image.dataSource.getEvents())
        self.elv.SetRange([0, self.image.dataSource.getNumSlices()])
        
        if b'ProtocolFocus' in self.elv.evKeyNames:
            self.zm = piecewiseMapping.GeneratePMFromEventList(self.elv.eventSource, self.mdh.getEntry('Camera.CycleTime'), self.mdh.getEntry('StartTime'), self.mdh.getEntry('Protocol.PiezoStartPos'))
            self.elv.SetCharts([('Focus [um]', self.zm, b'ProtocolFocus'),])

        self.update()
示例#7
0
    def __init__(self,
                 parent,
                 dstack=None,
                 aspect=1,
                 do=None,
                 voxelsize=[1, 1, 1]):

        if (dstack is None and do is None):
            dstack = scipy.zeros((10, 10))

        if do is None:
            self.do = DisplayOpts(dstack, aspect=aspect)
            self.do.Optimise()
        else:
            self.do = do

        self.voxelsize = voxelsize

        scrolledImagePanel.ScrolledImagePanel.__init__(self,
                                                       parent,
                                                       self.DoPaint,
                                                       style=wx.SUNKEN_BORDER
                                                       | wx.TAB_TRAVERSAL)

        self.do.WantChangeNotification.append(self.GetOpts)
        #self.do.WantChangeNotification.append(self.Refresh)

        self.SetVirtualSize(wx.Size(self.do.ds.shape[0], self.do.ds.shape[1]))
        #self.imagepanel.SetSize(wx.Size(self.do.ds.shape[0],self.do.ds.shape[1]))

        self.points = []
        self.pointsR = []
        self.showPoints = True
        self.showTracks = True
        self.showContours = True
        self.showScaleBar = True
        self.scaleBarLength = 2000
        self.pointMode = 'confoc'
        self.pointTolNFoc = {
            'confoc': (5, 5, 5),
            'lm': (2, 5, 5),
            'splitter': (2, 5, 5)
        }
        self.showAdjacentPoints = False
        self.pointSize = 11
        self.layerMode = 'Add'

        self.psfROIs = []
        self.psfROISize = [30, 30, 30]

        self.lastUpdateTime = 0
        self.lastFrameTime = 2e-3

        #self.do.scale = 0
        self.crosshairs = True
        #self.showSelection = True
        self.selecting = False

        self.aspect = 1.

        self._slice = None
        self._sc = None

        self.overlays = []

        self._oldIm = None
        self._oldImSig = None

        self.CenteringHandlers = []

        self.selectHandlers = []

        self.labelPens = [
            wx.Pen(
                wx.Colour(*[
                    int(c) for c in matplotlib.cm.hsv(v, alpha=.5, bytes=True)
                ]), 2) for v in numpy.linspace(0, 1, 16)
        ]

        #        if not aspect is None:
        #            if scipy.isscalar(aspect):
        #                self.do.aspects[2] = aspect
        #            elif len(aspect) == 3:
        #                self.do.aspects = aspect

        #self.SetOpts()
        #self.optionspanel.RefreshHists()
        self.updating = 0
        self.showOptsPanel = 1

        self.refrTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnRefrTimer)

        self.imagepanel.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
        self.imagepanel.Bind(wx.EVT_KEY_DOWN, self.OnKeyPress)
        #wx.EVT_KEY_DOWN(self.Parent(), self.OnKeyPress)
        self.imagepanel.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.imagepanel.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)

        self.imagepanel.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
        self.imagepanel.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)

        self.imagepanel.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.imagepanel.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)

        self.imagepanel.Bind(wx.EVT_MIDDLE_DCLICK, self.OnMiddleDClick)

        self.imagepanel.Bind(wx.EVT_MOTION, self.OnMotion)

        #
        self.imagepanel.Bind(wx.EVT_ERASE_BACKGROUND, self.DoNix)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.DoNix)
示例#8
0
class ArrayViewPanel(scrolledImagePanel.ScrolledImagePanel):
    def __init__(self,
                 parent,
                 dstack=None,
                 aspect=1,
                 do=None,
                 voxelsize=[1, 1, 1]):

        if (dstack is None and do is None):
            dstack = scipy.zeros((10, 10))

        if do is None:
            self.do = DisplayOpts(dstack, aspect=aspect)
            self.do.Optimise()
        else:
            self.do = do

        self.voxelsize = voxelsize

        scrolledImagePanel.ScrolledImagePanel.__init__(self,
                                                       parent,
                                                       self.DoPaint,
                                                       style=wx.SUNKEN_BORDER
                                                       | wx.TAB_TRAVERSAL)

        self.do.WantChangeNotification.append(self.GetOpts)
        #self.do.WantChangeNotification.append(self.Refresh)

        self.SetVirtualSize(wx.Size(self.do.ds.shape[0], self.do.ds.shape[1]))
        #self.imagepanel.SetSize(wx.Size(self.do.ds.shape[0],self.do.ds.shape[1]))

        self.points = []
        self.pointsR = []
        self.showPoints = True
        self.showTracks = True
        self.showContours = True
        self.showScaleBar = True
        self.scaleBarLength = 2000
        self.pointMode = 'confoc'
        self.pointTolNFoc = {
            'confoc': (5, 5, 5),
            'lm': (2, 5, 5),
            'splitter': (2, 5, 5)
        }
        self.showAdjacentPoints = False
        self.pointSize = 11
        self.layerMode = 'Add'

        self.psfROIs = []
        self.psfROISize = [30, 30, 30]

        self.lastUpdateTime = 0
        self.lastFrameTime = 2e-3

        #self.do.scale = 0
        self.crosshairs = True
        #self.showSelection = True
        self.selecting = False

        self.aspect = 1.

        self._slice = None
        self._sc = None

        self.overlays = []

        self._oldIm = None
        self._oldImSig = None

        self.CenteringHandlers = []

        self.selectHandlers = []

        self.labelPens = [
            wx.Pen(
                wx.Colour(*[
                    int(c) for c in matplotlib.cm.hsv(v, alpha=.5, bytes=True)
                ]), 2) for v in numpy.linspace(0, 1, 16)
        ]

        #        if not aspect is None:
        #            if scipy.isscalar(aspect):
        #                self.do.aspects[2] = aspect
        #            elif len(aspect) == 3:
        #                self.do.aspects = aspect

        #self.SetOpts()
        #self.optionspanel.RefreshHists()
        self.updating = 0
        self.showOptsPanel = 1

        self.refrTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnRefrTimer)

        self.imagepanel.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
        self.imagepanel.Bind(wx.EVT_KEY_DOWN, self.OnKeyPress)
        #wx.EVT_KEY_DOWN(self.Parent(), self.OnKeyPress)
        self.imagepanel.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
        self.imagepanel.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)

        self.imagepanel.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
        self.imagepanel.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)

        self.imagepanel.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
        self.imagepanel.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)

        self.imagepanel.Bind(wx.EVT_MIDDLE_DCLICK, self.OnMiddleDClick)

        self.imagepanel.Bind(wx.EVT_MOTION, self.OnMotion)

        #
        self.imagepanel.Bind(wx.EVT_ERASE_BACKGROUND, self.DoNix)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.DoNix)

    def OnRefrTimer(self, event):
        self.Refresh()
        self.Update()

    def SetDataStack(self, ds):
        self.do.SetDataStack(ds)
        self.SetVirtualSize(wx.Size(self.do.ds.shape[0], self.do.ds.shape[1]))

        self.do.xp = 0
        self.do.yp = 0
        self.do.zp = 0
        self.do.Optimise()

        self.do.ResetSelection()

        self.Layout()
#        self.Refresh()

    def ResetDataStack(self, ds):
        self.do.SetDataStack(ds)

    def _ScreenToAbsCoordinates(self, x, y):
        xp, yp = self.CalcUnscrolledPosition(x, y)
        #xp = self.centreX + self.glCanvas.pixelsize*(x - self.Size[0]/2)
        #yp = self.centreY - self.glCanvas.pixelsize*(y - self.Size[1]/2)
        if self.do.orientation == self.do.UPRIGHT:
            return xp, yp
        else:
            return yp, xp

    def _ScreenToPixelCoordinates(self, x, y):
        #sc = pow(2.0,(self.do.scale-2))
        xp, yp = self._ScreenToAbsCoordinates(x, y)

        return xp / self.scale, yp / (self.scale * self.aspect)

    def _AbsToScreenCoordinates(self, x, y):
        x0, y0 = self.CalcUnscrolledPosition(0, 0)

        if self.do.orientation == self.do.UPRIGHT:
            return x - x0, y - y0
        else:
            return y - x0, x - y0

    def _PixelToScreenCoordinates(self, x, y):
        #sc = pow(2.0,(self.do.scale-2))
        #print self.scale, self.aspect
        return self._AbsToScreenCoordinates(x * self.scale,
                                            y * self.scale * self.aspect)

    def _PixelToScreenCoordinates3D(self, x, y, z):
        #sc = pow(2.0,(self.do.scale-2))
        if (self.do.slice == self.do.SLICE_XY):
            xs, ys = self._PixelToScreenCoordinates(x, y)
        elif (self.do.slice == self.do.SLICE_XZ):
            xs, ys = self._PixelToScreenCoordinates(x, z)
        elif (self.do.slice == self.do.SLICE_YZ):
            xs, ys = self._PixelToScreenCoordinates(y, z)

        return xs, ys

    def _drawBoxPixelCoords(self, dc, x, y, z, w, h, d):
        """Draws a box in screen space given 3D co-ordinates"""
        if (self.do.slice == self.do.SLICE_XY):
            xs, ys = self._PixelToScreenCoordinates(x, y)
            ws, hs = (w * self.scale, h * self.scale * self.aspect)
        elif (self.do.slice == self.do.SLICE_XZ):
            xs, ys = self._PixelToScreenCoordinates(x, z)
            ws, hs = (w * self.scale, d * self.scale * self.aspect)
        elif (self.do.slice == self.do.SLICE_YZ):
            xs, ys = self._PixelToScreenCoordinates(y, z)
            ws, hs = (h * self.scale, d * self.scale * self.aspect)

        dc.DrawRectangle(xs - 0.5 * ws, ys - 0.5 * hs, ws, hs)

    @property
    def scale(self):
        return pow(2.0, (self.do.scale))

    def DrawCrosshairs(self, view, dc):
        if self.crosshairs:
            sX, sY = view.imagepanel.Size

            dc.SetPen(wx.Pen(wx.CYAN, 1))
            if (view.do.slice == view.do.SLICE_XY):
                lx = view.do.xp
                ly = view.do.yp
            elif (view.do.slice == view.do.SLICE_XZ):
                lx = view.do.xp
                ly = view.do.zp
            elif (view.do.slice == view.do.SLICE_YZ):
                lx = view.do.yp
                ly = view.do.zp

            xc, yc = view._PixelToScreenCoordinates(lx, ly)
            dc.DrawLine(0, yc, sX, yc)
            dc.DrawLine(xc, 0, xc, sY)

            dc.SetPen(wx.NullPen)

    def DrawSelection(self, view, dc):
        if self.do.showSelection:
            col = wx.TheColourDatabase.FindColour('YELLOW')
            #col.Set(col.red, col.green, col.blue, 125)
            dc.SetPen(wx.Pen(col, 1))
            dc.SetBrush(wx.TRANSPARENT_BRUSH)

            lx, ly, hx, hy = self.do.GetSliceSelection()
            lx, ly = self._PixelToScreenCoordinates(lx, ly)
            hx, hy = self._PixelToScreenCoordinates(hx, hy)

            if self.do.selectionMode == DisplayOpts.SELECTION_RECTANGLE:
                dc.DrawRectangle(lx, ly, (hx - lx), (hy - ly))

            elif self.do.selectionMode == DisplayOpts.SELECTION_SQUIGGLE:
                if len(self.do.selection_trace) > 2:
                    x, y = numpy.array(self.do.selection_trace).T
                    pts = numpy.vstack(self._PixelToScreenCoordinates(x, y)).T
                    dc.DrawSpline(pts)
            elif self.do.selectionWidth == 1:
                dc.DrawLine(lx, ly, hx, hy)
            else:
                lx, ly, hx, hy = self.do.GetSliceSelection()
                dx = hx - lx
                dy = hy - ly

                if dx == 0 and dy == 0:  #special case - profile is orthogonal to current plane
                    d_x = 0.5 * self.do.selectionWidth
                    d_y = 0.5 * self.do.selectionWidth
                else:
                    d_x = 0.5 * self.do.selectionWidth * dy / numpy.sqrt(
                        (dx**2 + dy**2))
                    d_y = 0.5 * self.do.selectionWidth * dx / numpy.sqrt(
                        (dx**2 + dy**2))

                x_0, y_0 = self._PixelToScreenCoordinates(lx + d_x, ly - d_y)
                x_1, y_1 = self._PixelToScreenCoordinates(lx - d_x, ly + d_y)
                x_2, y_2 = self._PixelToScreenCoordinates(hx - d_x, hy + d_y)
                x_3, y_3 = self._PixelToScreenCoordinates(hx + d_x, hy - d_y)

                lx, ly = self._PixelToScreenCoordinates(lx, ly)
                hx, hy = self._PixelToScreenCoordinates(hx, hy)

                dc.DrawLine(lx, ly, hx, hy)
                dc.DrawPolygon([(x_0, y_0), (x_1, y_1), (x_2, y_2),
                                (x_3, y_3)])

            dc.SetPen(wx.NullPen)
            dc.SetBrush(wx.NullBrush)

    def DrawTracks(self, view, dc):
        if self.showTracks and 'filter' in dir(
                self) and 'clumpIndex' in self.filter.keys():
            t = self.filter['t']  #prob safe as int
            x = self.filter['x'] / self.voxelsize[0]
            y = self.filter['y'] / self.voxelsize[1]

            xb, yb, zb = self._calcVisibleBounds()

            IFoc = (x >= xb[0]) * (y >= yb[0]) * (t >= zb[0]) * (x < xb[1]) * (
                y < yb[1]) * (t < zb[1])

            tFoc = list(set(self.filter['clumpIndex'][IFoc]))

            dc.SetBrush(wx.TRANSPARENT_BRUSH)

            for tN in tFoc:
                IFoc = (self.filter['clumpIndex'] == tN)
                if IFoc.sum() < 2:
                    return
                pFoc = numpy.vstack(
                    self._PixelToScreenCoordinates3D(x[IFoc], y[IFoc],
                                                     t[IFoc])).T

                #print pFoc.shape
                dc.SetPen(self.labelPens[tN % 16])
                dc.DrawLines(pFoc)

    def DrawScaleBar(self, view, dc):
        if self.showScaleBar:
            pGreen = wx.Pen(wx.TheColourDatabase.FindColour('WHITE'), 10)
            pGreen.SetCap(wx.CAP_BUTT)
            dc.SetPen(pGreen)
            sX, sY = view.imagepanel.Size

            sbLen = self.scaleBarLength * view.scale / view.voxelsize[0]

            y1 = 20
            x1 = 20 + sbLen
            x0 = x1 - sbLen
            dc.DrawLine(x0, y1, x1, y1)

            dc.SetTextForeground(wx.TheColourDatabase.FindColour('WHITE'))
            if self.scaleBarLength > 1000:
                s = u'%1.1f \u00B5m' % (self.scaleBarLength / 1000.)
            else:
                s = u'%d nm' % int(self.scaleBarLength)
            w, h = dc.GetTextExtent(s)
            dc.DrawText(s, x0 + (sbLen - w) / 2, y1 + 7)

    def DrawContours(self, view, dc):
        if self.showContours and 'filter' in dir(
                self) and 'contour' in self.filter.keys(
                ) and self.do.slice == self.do.SLICE_XY:
            t = self.filter['t']  # prob safe as int
            x = self.filter['x'] / self.voxelsize[0]
            y = self.filter['y'] / self.voxelsize[1]

            xb, yb, zb = self._calcVisibleBounds()

            IFoc = (x >= xb[0]) * (y >= yb[0]) * (t >= zb[0]) * (x < xb[1]) * (
                y < yb[1]) * (t < zb[1])

            dc.SetBrush(wx.TRANSPARENT_BRUSH)

            pGreen = wx.Pen(wx.TheColourDatabase.FindColour('RED'), 1)
            #pRed = wx.Pen(wx.TheColourDatabase.FindColour('RED'),1)
            dc.SetPen(pGreen)

            contours = self.filter['contour'][IFoc]
            if 'clumpIndex' in self.filter.keys():
                colInds = self.filter['clumpIndex'][IFoc] % len(self.labelPens)
            else:
                colInds = numpy.zeros(len(contours),
                                      'i')  #%len(self.labelPens)
            for c, colI in zip(contours, colInds):
                xc, yc = c.T
                dc.SetPen(self.labelPens[int(colI)])
                dc.DrawSpline(
                    numpy.vstack(self._PixelToScreenCoordinates(xc, yc)).T)

    def DrawPoints(self, view, dc):
        dx = 0
        dy = 0

        aN = SLICE_AXIS_LUT[self.do.slice]
        tolN = TOL_AXIS_LUT[self.do.slice]
        pos = [self.do.xp, self.do.yp, self.do.zp]

        if self.showPoints and ('filter' in dir(self) or len(self.points) > 0):
            if 'filter' in dir(self):
                t = self.filter['t']  #prob safe as int
                x = self.filter['x'] / self.voxelsize[0]
                y = self.filter['y'] / self.voxelsize[1]

                xb, yb, zb = self._calcVisibleBounds()

                IFoc = (x >= xb[0]) * (y >= yb[0]) * (t >= zb[0]) * (
                    x < xb[1]) * (y < yb[1]) * (t < zb[1])

                pFoc = numpy.vstack((x[IFoc], y[IFoc], t[IFoc])).T
                if self.pointMode == 'splitter':
                    pCol = self.filter['gFrac'][IFoc] > .5
                pNFoc = []

            #intrinsic points
            elif len(self.points) > 0:
                pointTol = self.pointTolNFoc[self.pointMode]

                IFoc = abs(self.points[:, aN] - pos[aN]) < 1
                INFoc = abs(self.points[:, aN] - pos[aN]) < pointTol[tolN]

                pFoc = self.points[IFoc]
                pNFoc = self.points[INFoc]

                if self.pointMode == 'splitter':
                    pCol = self.pointColours[IFoc]

            if self.pointMode == 'splitter':
                if 'chroma' in dir(self):
                    dx = self.chroma.dx.ev(
                        pFoc[:, 0] * 1e3 * self.voxelsize[0], pFoc[:, 1] *
                        1e3 * self.voxelsize[1]) / (1e3 * self.voxelsize[0])
                    dy = self.chroma.dy.ev(
                        pFoc[:, 0] * 1e3 * self.voxelsize[0], pFoc[:, 1] *
                        1e3 * self.voxelsize[1]) / (1e3 * self.voxelsize[1])
                else:
                    dx = 0 * pFoc[:, 0]
                    dy = 0 * pFoc[:, 0]

                if 'chroma' in dir(self):
                    dxn = self.chroma.dx.ev(
                        pNFoc[:, 0] * 1e3 * self.voxelsize[0], pNFoc[:, 1] *
                        1e3 * self.voxelsize[1]) / (1e3 * self.voxelsize[0])
                    dyn = self.chroma.dy.ev(
                        pNFoc[:, 0] * 1e3 * self.voxelsize[0], pNFoc[:, 1] *
                        1e3 * self.voxelsize[1]) / (1e3 * self.voxelsize[1])
                else:
                    dxn = 0 * pNFoc[:, 0]
                    dyn = 0 * pNFoc[:, 0]

            dc.SetBrush(wx.TRANSPARENT_BRUSH)
            ps = self.pointSize

            if self.showAdjacentPoints:
                dc.SetPen(wx.Pen(wx.TheColourDatabase.FindColour('BLUE'), 1))

                if self.pointMode == 'splitter':
                    for p, dxi, dyi in zip(pNFoc, dxn, dyn):
                        self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps,
                                                 ps)
                        self._drawBoxPixelCoords(
                            dc, p[0] - dxi,
                            0.5 * self.do.ds.shape[1] + p[1] - dyi, p[2], ps,
                            ps, ps)

                else:
                    for p in pNFoc:
                        self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps,
                                                 ps)

            pGreen = wx.Pen(wx.TheColourDatabase.FindColour('GREEN'), 1)
            pRed = wx.Pen(wx.TheColourDatabase.FindColour('RED'), 1)
            dc.SetPen(pGreen)

            if self.pointMode == 'splitter':
                for p, c, dxi, dyi in zip(pFoc, pCol, dx, dy):
                    if c:
                        dc.SetPen(pGreen)
                    else:
                        dc.SetPen(pRed)

                    self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps, ps)
                    self._drawBoxPixelCoords(
                        dc, p[0] - dxi, 0.5 * self.do.ds.shape[1] + p[1] - dyi,
                        p[2], ps, ps, ps)

            else:
                for p in pFoc:
                    self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps, ps)

            dc.SetPen(wx.NullPen)
            dc.SetBrush(wx.NullBrush)

    def _calcVisibleBounds(self):
        sc = pow(2.0, (self.do.scale))
        x0, y0 = self.CalcUnscrolledPosition(0, 0)
        sX, sY = self.imagepanel.Size

        if self.do.slice == self.do.SLICE_XY:
            bnds = [(x0 / sc, (x0 + sX) / sc), (y0 / sc, (y0 + sY) / sc),
                    (self.do.zp - .5, self.do.zp + .5)]
        elif self.do.slice == self.do.SLICE_XZ:
            bnds = [(x0 / sc, (x0 + sX) / sc),
                    (self.do.yp - .5, self.do.yp + .5),
                    (y0 / sc, (y0 + sY) / sc)]
        elif self.do.slice == self.do.SLICE_YZ:
            bnds = [(self.do.xp - .5, self.do.xp + .5),
                    (x0 / sc, (x0 + sX) / sc), (y0 / sc, (y0 + sY) / sc)]

        return bnds

    def DoPaint(self, dc, fullImage=False):
        #print 'p'

        dc.Clear()

        im = self.Render(fullImage)

        sc = pow(2.0, (self.do.scale))
        sc2 = sc

        if sc >= 1:
            step = 1
        else:
            step = 2**(-numpy.ceil(numpy.log2(sc)))
            sc2 = sc * step

        im2 = wx.BitmapFromImage(im)
        dc.DrawBitmap(im2, -sc2 / 2, -sc2 / 2)

        #sX, sY = im.GetWidth(), im.GetHeight()

        self.DrawCrosshairs(self, dc)
        self.DrawSelection(self, dc)
        self.DrawScaleBar(self, dc)

        #self.DrawTracks(self, dc)
        self.DrawPoints(self, dc)
        self.DrawContours(self, dc)

        dc.SetPen(wx.NullPen)
        dc.SetBrush(wx.NullBrush)

        for ovl in self.do.overlays:
            ovl(self, dc)

    def GrabImage(self, fullImage=True):
        #TODO - get suitable image dependent viewport

        xs, ys = self._unscrolled_view_size()
        if fullImage:
            if (xs > 2e3 or ys > 2e3) and wx.MessageBox(
                    'Captured image will be very large, continue?',
                    'Warning',
                    style=wx.OK | wx.CANCEL) != wx.OK:
                return
        else:
            s = self.GetClientSize()
            xs = min(s.GetWidth(), xs)
            ys = min(s.GetHeight(), ys)

        MemBitmap = wx.EmptyBitmap(xs, ys)
        MemDC = wx.MemoryDC()
        OldBitmap = MemDC.SelectObject(MemBitmap)

        self.DoPaint(MemDC, fullImage)

        return MemBitmap

    def GrabPNG(self, filename, fullImage=True):
        MemBitmap = self.GrabImage(fullImage)
        img = MemBitmap.ConvertToImage()
        img.SaveFile(filename, wx.BITMAP_TYPE_PNG)

    def GrabPNGToBuffer(self, fullImage=True):
        '''Get PNG data in a buffer (rather than writing directly to file)'''
        from io import BytesIO

        img = self.GrabImage(fullImage)
        out = BytesIO()
        # NB - using wx functionality rather than pillow here as wxImage.GetData() returns a BytesArray object rather
        # than a buffer on py3. This underlying problem may need to be revisited.
        img.ConvertToImage().SaveFile(out, wx.BITMAP_TYPE_PNG)
        return out.getvalue()

    def CopyImage(self, fullImage=True):
        """ Copies the currently displayed image to the clipboard"""
        bmp = self.GrabImage(fullImage)
        try:
            wx.TheClipboard.Open()
            bmpDataObject = wx.BitmapDataObject(bmp)
            wx.TheClipboard.SetData(bmpDataObject)
        finally:
            wx.TheClipboard.Close()

    def OnWheel(self, event):
        rot = event.GetWheelRotation()
        if rot < 0:
            if event.RightIsDown():
                self.do.yp = max(self.do.yp - 1, 0)
            elif event.MiddleIsDown():
                self.do.xp = max(self.do.xp - 1, 0)
            elif event.ShiftDown():
                self.do.SetScale(self.do.scale - 1)
            else:
                self.do.zp = max(self.do.zp - 1, 0)
        if rot > 0:
            if event.RightIsDown():
                self.do.yp = min(self.do.yp + 1, self.do.ds.shape[1] - 1)
            elif event.MiddleIsDown():
                self.do.xp = min(self.do.xp + 1, self.do.ds.shape[0] - 1)
            elif event.ShiftDown():
                self.do.SetScale(self.do.scale + 1)
            else:
                self.do.zp = min(self.do.zp + 1, self.do.ds.shape[2] - 1)

        if ('update' in dir(self.GetParent())):
            self.GetParent().update()
        else:
            self.imagepanel.Refresh()
        #self.update()

    def OnKeyPress(self, event):
        if event.GetKeyCode() == wx.WXK_PAGEUP:
            self.do.zp = max(0, self.do.zp - 1)
            #self.optionspanel.RefreshHists()
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                #if not self.painting:
                self.imagepanel.Refresh()
                #else:
                #    if not self.refrTimer.IsRunning():
                #        self.refrTimer.Start(.2, True)

        elif event.GetKeyCode() == wx.WXK_PAGEDOWN:
            self.do.zp = min(self.do.zp + 1, self.do.ds.shape[2] - 1)
            #self.optionspanel.RefreshHists()
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
                #print 'upd'
            else:
                #if not self.painting:
                self.imagepanel.Refresh()
                #else:
                #    if not self.refrTimer.IsRunning():
                #print 'upt'
                #        self.refrTimer.Start(.2, True)

        elif event.GetKeyCode() == 74:  #J
            self.do.xp = (self.do.xp - 1)
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 76:  #L
            self.do.xp += 1
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 73:  #I
            self.do.yp -= 1
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 75:  #K
            self.do.yp += 1
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 77:  #M
            #print 'o'
            self.do.Optimise()
        elif event.GetKeyCode() == ord('C'):
            if event.GetModifiers() == wx.MOD_CMD:
                self.CopyImage()
            elif event.GetModifiers() == wx.MOD_CMD | wx.MOD_SHIFT:
                self.CopyImage(False)
            else:
                event.Skip()
        else:
            event.Skip()

    def GetOpts(self, event=None):
        if (self.updating == 0):

            sc = pow(2.0, (self.do.scale))
            s = self.CalcImSize()
            self.SetVirtualSize(wx.Size(s[0] * sc, s[1] * sc))

            if (self._slice != self.do.slice) or (self._sc != sc):
                #print('recentering')
                #if the slice has changed, change our aspect and do some
                self._slice = self.do.slice
                self._sc = sc
                #if not event is None and event.GetId() in [self.cbSlice.GetId(), self.cbScale.GetId()]:
                #recenter the view
                if (self.do.slice == self.do.SLICE_XY):
                    lx = self.do.xp
                    ly = self.do.yp
                    self.aspect = self.do.aspect[1] / self.do.aspect[0]
                elif (self.do.slice == self.do.SLICE_XZ):
                    lx = self.do.xp
                    ly = self.do.zp
                    self.aspect = self.do.aspect[2] / self.do.aspect[0]
                elif (self.do.slice == self.do.SLICE_YZ):
                    lx = self.do.yp
                    ly = self.do.zp
                    self.aspect = self.do.aspect[2] / self.do.aspect[1]

                sx, sy = self.imagepanel.GetClientSize()

                ppux, ppuy = self.GetScrollPixelsPerUnit()
                self.Scroll(
                    max(0, lx * sc - sx / 2) / ppux,
                    max(0, ly * sc * self.aspect - sy / 2) / ppuy)

            #self.imagepanel.Refresh()
            self.Refresh()
            self.Update()

    def Optim(self, event=None):
        self.do.Optimise(self.do.ds, int(self.do.zp))
        self.updating = 1
        #self.SetOpts()
        #self.optionspanel.RefreshHists()
        self.Refresh()
        self.Update()
        self.updating = 0

    def CalcImSize(self):
        if (self.do.slice == self.do.SLICE_XY):
            if (self.do.orientation == self.do.UPRIGHT):
                return (self.do.ds.shape[0], self.do.ds.shape[1])
            else:
                return (self.do.ds.shape[1], self.do.ds.shape[0])
        elif (self.do.slice == self.do.SLICE_XZ):
            return (self.do.ds.shape[0], self.do.ds.shape[2])
        else:
            return (self.do.ds.shape[1], self.do.ds.shape[2])

    def DoNix(self, event):
        pass

    def OnLeftDown(self, event):
        if self.do.leftButtonAction == self.do.ACTION_SELECTION:
            self.StartSelection(event)

        event.Skip()

    def OnLeftUp(self, event):
        if self.do.leftButtonAction == self.do.ACTION_SELECTION:
            self.ProgressSelection(event)
            self.EndSelection()
        else:
            self.OnSetPosition(event)

        event.Skip()

    def OnMiddleDown(self, event):
        dc = wx.ClientDC(self.imagepanel)
        #        self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        self.middleDownPos = self.CalcUnscrolledPosition(*pos)
        event.Skip()

    def OnMiddleUp(self, event):
        dc = wx.ClientDC(self.imagepanel)
        #        self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)

        dx = pos[0] - self.middleDownPos[0]
        dy = pos[1] - self.middleDownPos[1]

        sc = pow(2.0, (self.do.scale))

        if (abs(dx) > 5) or (abs(dy) > 5):
            for h in self.CenteringHandlers:
                h(-dx / sc, -dy / sc)

        event.Skip()

    def OnMiddleDClick(self, event):
        dc = wx.ClientDC(self.imagepanel)
        #        self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)
        #print pos
        sc = pow(2.0, (self.do.scale))
        if (self.do.slice == self.do.SLICE_XY):
            x = (pos[0] / sc) - 0.5 * self.do.ds.shape[0]
            y = (pos[1] / (sc * self.aspect)) - 0.5 * self.do.ds.shape[1]

            for h in self.CenteringHandlers:
                h(x, y)

        event.Skip()

    def _unscrolled_view_size(self):
        sc = pow(2.0, (self.do.scale))
        shp = self.do.ds.shape

        if (self.do.slice == self.do.SLICE_XY):
            xs = int(shp[0] * sc)
            ys = int(shp[1] * sc * self.aspect)
        elif (self.do.slice == self.do.SLICE_XZ):
            xs = int(shp[0] * sc)
            ys = int(shp[2] * sc * self.aspect)
        elif (self.do.slice == self.do.SLICE_YZ):
            xs = int(shp[1] * sc)
            ys = int(shp[2] * sc * self.aspect)

        return xs, ys

    def OnSetPosition(self, event):
        dc = wx.ClientDC(self.imagepanel)
        #self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)

        #print(pos)
        self.do.inOnChange = True
        try:
            sc = pow(2.0, (self.do.scale))
            #print(sc)
            if (self.do.slice == self.do.SLICE_XY):
                self.do.xp = int(pos[0] / sc)
                self.do.yp = int(pos[1] / (sc * self.aspect))
            elif (self.do.slice == self.do.SLICE_XZ):
                self.do.xp = int(pos[0] / sc)
                self.do.zp = int(pos[1] / (sc * self.aspect))
            elif (self.do.slice == self.do.SLICE_YZ):
                self.do.yp = int(pos[0] / sc)
                self.do.zp = int(pos[1] / (sc * self.aspect))
        finally:
            self.do.inOnChange = False

        self.do.OnChange()

        for cb in self.selectHandlers:
            cb(self)
        #if ('update' in dir(self.GetParent())):
        #     self.GetParent().update()
        #else:
        #    self.imagepanel.Refresh()

    def PointsHitTest(self):
        if len(self.points) > 0:
            iCand = numpy.where((abs(self.points[:, 2] - self.do.zp) < 1) *
                                (abs(self.points[:, 0] - self.do.xp) < 3) *
                                (abs(self.points[:, 1] - self.do.yp) < 3))[0]

            if len(iCand) == 0:
                return None
            elif len(iCand) == 1:
                return iCand[0]
            else:
                pCand = self.points[iCand, :]

                iNearest = numpy.argmin((pCand[:, 0] - self.do.xp)**2 +
                                        (pCand[:, 1] - self.do.yp)**2)

                return iCand[iNearest]
        else:
            return None

    def OnRightDown(self, event):
        self.StartSelection(event)

    def StartSelection(self, event):
        self.selecting = True

        dc = wx.ClientDC(self.imagepanel)
        #self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)
        #print pos
        sc = pow(2.0, (self.do.scale))
        if (self.do.slice == self.do.SLICE_XY):
            self.do.selection_begin_x = int(pos[0] / sc)
            self.do.selection_begin_y = int(pos[1] / (sc * self.aspect))
        elif (self.do.slice == self.do.SLICE_XZ):
            self.do.selection_begin_x = int(pos[0] / sc)
            self.do.selection_begin_z = int(pos[1] / (sc * self.aspect))
        elif (self.do.slice == self.do.SLICE_YZ):
            self.do.selection_begin_y = int(pos[0] / sc)
            self.do.selection_begin_z = int(pos[1] / (sc * self.aspect))

        self.do.selection_trace = []
        self.do.selection_trace.append(
            ((pos[0] / sc), (pos[1] / (sc * self.aspect))))

    def OnRightUp(self, event):
        self.ProgressSelection(event)
        self.EndSelection()

    def OnMotion(self, event):
        if event.Dragging() and self.selecting:
            self.ProgressSelection(event)

    def ProgressSelection(self, event):
        dc = wx.ClientDC(self.imagepanel)
        #self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)
        #print pos

        sc = pow(2.0, (self.do.scale))

        if not event.ShiftDown():
            if (self.do.slice == self.do.SLICE_XY):
                self.do.selection_end_x = int(pos[0] / sc)
                self.do.selection_end_y = int(pos[1] / (sc * self.aspect))
            elif (self.do.slice == self.do.SLICE_XZ):
                self.do.selection_end_x = int(pos[0] / sc)
                self.do.selection_end_z = int(pos[1] / (sc * self.aspect))
            elif (self.do.slice == self.do.SLICE_YZ):
                self.do.selection_end_y = int(pos[0] / sc)
                self.do.selection_end_z = int(pos[1] / (sc * self.aspect))
        else:  #lock
            if (self.do.slice == self.do.SLICE_XY):
                self.do.selection_end_x = int(pos[0] / sc)
                self.do.selection_end_y = int(pos[1] / (sc * self.aspect))

                dx = abs(self.do.selection_end_x - self.do.selection_begin_x)
                dy = abs(self.do.selection_end_y - self.do.selection_begin_y)

                if dx > 1.5 * dy:  #horizontal
                    self.do.selection_end_y = self.do.selection_begin_y
                elif dy > 1.5 * dx:  #vertical
                    self.do.selection_end_x = self.do.selection_begin_x
                else:  #diagonal
                    self.do.selection_end_y = self.do.selection_begin_y + dx * numpy.sign(
                        self.do.selection_end_y - self.do.selection_begin_y)

            elif (self.do.slice == self.do.SLICE_XZ):
                self.do.selection_end_x = int(pos[0] / sc)
                self.do.selection_end_z = int(pos[1] / (sc * self.aspect))
            elif (self.do.slice == self.do.SLICE_YZ):
                self.do.selection_end_y = int(pos[0] / sc)
                self.do.selection_end_z = int(pos[1] / (sc * self.aspect))

        self.do.selection_trace.append(
            ((pos[0] / sc), (pos[1] / (sc * self.aspect))))

        self.Refresh()
        self.Update()

    def EndSelection(self):
        self.selecting = False
        self.do.EndSelection()

    def _gensig(self, x0, y0, sX, sY, do):
        sig = [
            x0, y0, sX, sY, do.scale, do.slice,
            do.GetActiveChans(), do.ds.shape
        ]
        if do.slice == DisplayOpts.SLICE_XY:
            sig += [do.zp, do.maximumProjection]
        if do.slice == DisplayOpts.SLICE_XZ:
            sig += [do.yp]
        if do.slice == DisplayOpts.SLICE_YZ:
            sig += [do.xp]

        return sig

    def Redraw(self, sender=None, **kwargs):
        self._oldImSig = None
        self.Refresh()
        self.Update()

    def _map_colour(self, seg, gain, offset, cmap, ima):
        lut = getLUT(cmap)

        if cmap == labeled:
            # special case for labelled colourmap - use slow matplotlib lookup and rely on matplotlib roll-around to
            # cycle colour map TODO - check if recent matplotlibs actually roll around or not.
            ima[:] = numpy.minimum(
                ima[:] + (255 * cmap(gain * (seg - offset))[:, :, :3])[:], 255)

        elif numpy.iscomplexobj(seg):
            if self.do.colourMax or (self.do.complexMode == 'imag coloured'):
                applyLUT(numpy.imag(seg),
                         self.do.cmax_scale / self.do.ds.shape[2],
                         self.do.cmax_offset, lut, ima)
                ima[:] = (ima * numpy.clip((numpy.real(seg) - offset) * gain,
                                           0, 1)[:, :, None]).astype('uint8')
            elif self.do.complexMode == 'real':
                applyLUT(seg.real, gain, offset, lut, ima)
            elif self.do.complexMode == 'imag':
                applyLUT(seg.imag, gain, offset, lut, ima)
            elif self.do.complexMode == 'abs':
                applyLUT(numpy.abs(seg), gain, offset, lut, ima)
            elif self.do.complexMode == 'angle':
                applyLUT(numpy.angle(seg), gain, offset, lut, ima)
            else:
                applyLUT(numpy.angle(seg),
                         self.do.cmax_scale / self.do.ds.shape[2],
                         self.do.cmax_offset, lut, ima)
                ima[:] = (ima * numpy.clip((numpy.abs(seg) - offset) * gain, 0,
                                           1)[:, :, None]).astype('uint8')
        else:
            #print seg.shape
            applyLUT(seg, gain, offset, lut, ima)

    def Render(self, fullImage=False):
        #print 'rend'
        if fullImage:
            x0, y0 = 0, 0
            sX, sY = self._unscrolled_view_size()
        else:
            x0, y0 = self.CalcUnscrolledPosition(0, 0)
            sX, sY = self.imagepanel.Size

        sig = self._gensig(x0, y0, sX, sY, self.do)
        if sig == self._oldImSig:  # and not self._oldIm is None:
            #if nothing has changed, don't re-render
            return self._oldIm

        sc = pow(2.0, self.do.scale)
        sc2 = sc

        if sc >= 1:
            step = 1
        else:
            step = 2**(-numpy.ceil(numpy.log2(sc)))
            sc2 = sc * step

        sX_ = int(sX / (sc))
        sY_ = int(sY / (sc * self.aspect))
        x0_ = int(x0 / sc)
        y0_ = int(y0 / (sc * self.aspect))

        fstep = float(step)
        step = int(step)

        if (step > 1) and hasattr(self.do.ds, 'levels'):
            # we have a pyramidal data source

            level = -self.do.scale

            #if (level > len(self.do.ds.levels)):
            level = int(min(level, len(self.do.ds.levels)))
            step = int(2**(-numpy.ceil(numpy.log2(sc)) - level))

            _s = 1.0 / (2**level)

            x0_, y0_, sX_, sY_ = [
                int(numpy.ceil(v * _s)) for v in [x0_, y0_, sX_, sY_]
            ]

            # x0_ = int(numpy.ceil(x0_*_s))
            # y0_ = int(y0_*_s)
            # sX_ = int(sX_*_s)
            # sY_ = int(sY_*_s)

            ds = self.do.ds.levels[level]
        else:
            ds = self.do.ds
            _s = 1

        #XY
        if self.do.slice == DisplayOpts.SLICE_XY:
            dmy, dmx = self.do.ds.shape[1], self.do.ds.shape[0]
            slice_key = (slice(x0_, (x0_ + sX_),
                               step), slice(y0_, (y0_ + sY_), step),
                         int(self.do.zp * _s), int(self.do.tp * _s))

            proj_axis = 2

        #XZ
        elif self.do.slice == DisplayOpts.SLICE_XZ:
            dmy, dmx = self.do.ds.shape[2], self.do.ds.shape[0]
            slice_key = (slice(x0_, (x0_ + sX_), step), int(self.do.yp * _s),
                         slice(y0_, (y0_ + sY_), step), int(self.do.tp * _s))

            proj_axis = 1
        #YZ
        elif self.do.slice == DisplayOpts.SLICE_YZ:
            dmy, dmx = self.do.ds.shape[2], self.do.ds.shape[1]
            slice_key = (int(self.do.xp * _s), slice(x0_, (x0_ + sX_), step),
                         slice(y0_, (y0_ + sY_), step), int(self.do.tp * _s))

            proj_axis = 0

        if ds.ndim < 5:
            # for old-style data, drop the time dimension
            slice_key = slice_key[:3]

        #ima = numpy.zeros((int(numpy.ceil(min(sY_/_s, dmy)/fstep)), int(numpy.ceil(min(sX_/_s, dmx)/fstep)), 3), 'uint8')

        segs = []
        for chan, offset, gain, cmap in self.do.GetActiveChans():
            if self.do.maximumProjection and (self.do.slice
                                              == DisplayOpts.SLICE_XY):
                # special case for max projection - fixme - remove after we get colour coded projections in the projection module
                seg = self.do.ds[slice_key[:2] +
                                 (slice(None), chan)].max(2).squeeze().T
                if self.do.colourMax:
                    seg = seg + 1j * self.do.ds[slice_key[:2] +
                                                (slice(None),
                                                 chan)].argmax(2).squeeze().T
            else:
                seg = ds[slice_key + (chan, )].squeeze().T

            segs.append((seg, chan, offset, gain, cmap))

        if len(segs) > 0:
            ima = numpy.zeros(segs[0][0].shape[:2] + (3, ), 'uint8')
        else:
            ima = numpy.zeros((int(numpy.ceil(min(sY_ / _s, dmy) / fstep)),
                               int(numpy.ceil(min(sX_ / _s, dmx) / fstep)), 3),
                              'uint8')

        for seg, chan, offset, gain, cmap in segs:
            #'slice_key:', slice_key)
            #print('seg.shape, ima.shape:', seg.shape, ima.shape)
            self._map_colour(seg, gain, offset, cmap, ima)


#
        img = wx.ImageFromData(ima.shape[1], ima.shape[0], ima.ravel())
        img.Rescale(img.GetWidth() * sc2, img.GetHeight() * sc2 * self.aspect)
        self._oldIm = img
        self._oldImSig = sig
        return img
示例#9
0
class ArrayViewPanel(scrolledImagePanel.ScrolledImagePanel):
    def __init__(self, parent, dstack = None, aspect=1, do = None, voxelsize=[1,1,1]):
        
        if (dstack == None and do == None):
            dstack = scipy.zeros((10,10))

        if do == None:
            self.do = DisplayOpts(dstack, aspect=aspect)
            self.do.Optimise()
        else:
            self.do = do
            
        self.voxelsize = voxelsize

        scrolledImagePanel.ScrolledImagePanel.__init__(self, parent, self.DoPaint, style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL)

        self.do.WantChangeNotification.append(self.GetOpts)
        #self.do.WantChangeNotification.append(self.Refresh)

        self.SetVirtualSize(wx.Size(self.do.ds.shape[0],self.do.ds.shape[1]))
        #self.imagepanel.SetSize(wx.Size(self.do.ds.shape[0],self.do.ds.shape[1]))
        

        self.points =[]
        self.pointsR = []
        self.showPoints = True
        self.showTracks = True
        self.showContours = True
        self.showScaleBar = True
        self.scaleBarLength = 2000
        self.pointMode = 'confoc'
        self.pointTolNFoc = {'confoc' : (5,5,5), 'lm' : (2, 5, 5), 'splitter' : (2,5,5)}
        self.showAdjacentPoints = False
        self.pointSize = 11
        self.layerMode = 'Add'

        self.psfROIs = []
        self.psfROISize=[30,30,30]

        self.lastUpdateTime = 0
        self.lastFrameTime = 2e-3

        #self.do.scale = 0
        self.crosshairs = True
        #self.showSelection = True
        self.selecting = False

        self.aspect = 1.

        self.slice = None 
        
        self.overlays = []
        
        self._oldIm = None
        self._oldImSig = None
        
        self.CenteringHandlers = []
        
        self.labelPens = [wx.Pen(wx.Colour(*pylab.cm.hsv(v, bytes=True)), 2) for v in numpy.linspace(0, 1, 16)]

#        if not aspect == None:
#            if scipy.isscalar(aspect):
#                self.do.aspects[2] = aspect
#            elif len(aspect) == 3:
#                self.do.aspects = aspect

        
        #self.SetOpts()
        #self.optionspanel.RefreshHists()
        self.updating = 0
        self.showOptsPanel = 1

        self.refrTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnRefrTimer)

        wx.EVT_MOUSEWHEEL(self.imagepanel, self.OnWheel)
        wx.EVT_KEY_DOWN(self.imagepanel, self.OnKeyPress)
        #wx.EVT_KEY_DOWN(self.Parent(), self.OnKeyPress)
        wx.EVT_LEFT_DOWN(self.imagepanel, self.OnLeftDown)
        wx.EVT_LEFT_UP(self.imagepanel, self.OnLeftUp)
        
        wx.EVT_MIDDLE_DOWN(self.imagepanel, self.OnMiddleDown)
        wx.EVT_MIDDLE_UP(self.imagepanel, self.OnMiddleUp)
        
        wx.EVT_RIGHT_DOWN(self.imagepanel, self.OnRightDown)
        wx.EVT_RIGHT_UP(self.imagepanel, self.OnRightUp)
        
        wx.EVT_MIDDLE_DCLICK(self.imagepanel, self.OnMiddleDClick)

        wx.EVT_MOTION(self.imagepanel, self.OnMotion)

        #
        wx.EVT_ERASE_BACKGROUND(self.imagepanel, self.DoNix)
        wx.EVT_ERASE_BACKGROUND(self, self.DoNix)

    def OnRefrTimer(self, event):
        self.Refresh()
        self.Update()
        
    def SetDataStack(self, ds):
        self.do.SetDataStack(ds)
        self.SetVirtualSize(wx.Size(self.do.ds.shape[0],self.do.ds.shape[1]))
                
        self.do.xp=0
        self.do.yp=0
        self.do.zp=0
        self.do.Optimise()
            
        self.do.ResetSelection()
        
        self.Layout()
#        self.Refresh()

    def ResetDataStack(self, ds):
        self.do.SetDataStack(ds)

    def _ScreenToAbsCoordinates(self, x, y):
        xp,yp = self.CalcUnscrolledPosition(x,y)
        #xp = self.centreX + self.glCanvas.pixelsize*(x - self.Size[0]/2)
        #yp = self.centreY - self.glCanvas.pixelsize*(y - self.Size[1]/2)
        if self.do.orientation == self.do.UPRIGHT:
            return xp, yp
        else:
            return yp, xp

    def _ScreenToPixelCoordinates(self, x, y):
        #sc = pow(2.0,(self.do.scale-2))
        xp, yp = self._ScreenToAbsCoordinates(x, y)
        
        return xp/self.scale, yp/(self.scale*self.aspect)
        

    def _AbsToScreenCoordinates(self, x, y):
        x0,y0 = self.CalcUnscrolledPosition(0,0)

        if self.do.orientation == self.do.UPRIGHT:        
            return x - x0, y - y0
        else:
            return y - x0, x - y0

    def _PixelToScreenCoordinates(self, x, y):
        #sc = pow(2.0,(self.do.scale-2))
        return self._AbsToScreenCoordinates(x*self.scale, y*self.scale*self.aspect)
        
    def _PixelToScreenCoordinates3D(self, x, y, z):
        #sc = pow(2.0,(self.do.scale-2))
        if (self.do.slice == self.do.SLICE_XY):
            xs, ys = self._PixelToScreenCoordinates(x,y)
        elif (self.do.slice == self.do.SLICE_XZ):
            xs, ys = self._PixelToScreenCoordinates(x,z)
        elif (self.do.slice == self.do.SLICE_YZ):
            xs, ys = self._PixelToScreenCoordinates(y,z)
            
        return xs, ys
        
    def _drawBoxPixelCoords(self, dc, x, y, z, w, h, d):
        '''Draws a box in screen space given 3D co-ordinates'''        
        if (self.do.slice == self.do.SLICE_XY):
            xs, ys = self._PixelToScreenCoordinates(x,y)
            ws, hs = (w*self.scale, h*self.scale*self.aspect)
        elif (self.do.slice == self.do.SLICE_XZ):
            xs, ys = self._PixelToScreenCoordinates(x,z)
            ws, hs = (w*self.scale, d*self.scale*self.aspect)
        elif (self.do.slice == self.do.SLICE_YZ):
            xs, ys = self._PixelToScreenCoordinates(y,z)
            ws, hs = (h*self.scale, d*self.scale*self.aspect)
            
        dc.DrawRectangle(xs - 0.5*ws, ys - 0.5*hs, ws,hs)
        
        
    @property
    def scale(self):
        return pow(2.0,(self.do.scale))
        
    
    def DrawCrosshairs(self, view, dc):
        if self.crosshairs:
            sX, sY = view.imagepanel.Size
            
            dc.SetPen(wx.Pen(wx.CYAN,1))
            if(view.do.slice == view.do.SLICE_XY):
                lx = view.do.xp
                ly = view.do.yp
            elif(view.do.slice == view.do.SLICE_XZ):
                lx = view.do.xp
                ly = view.do.zp
            elif(view.do.slice == view.do.SLICE_YZ):
                lx = view.do.yp
                ly = view.do.zp
        
            
            xc, yc = view._PixelToScreenCoordinates(lx, ly)            
            dc.DrawLine(0, yc, sX, yc)
            dc.DrawLine(xc, 0, xc, sY)
            
            dc.SetPen(wx.NullPen)
            
    def DrawSelection(self, view, dc):
        if self.do.showSelection:
            col = wx.TheColourDatabase.FindColour('YELLOW')
            #col.Set(col.red, col.green, col.blue, 125)
            dc.SetPen(wx.Pen(col,1))
            dc.SetBrush(wx.TRANSPARENT_BRUSH)

            lx, ly, hx, hy = self.do.GetSliceSelection()
            lx, ly = self._PixelToScreenCoordinates(lx, ly)
            hx, hy = self._PixelToScreenCoordinates(hx, hy)
            
            if self.do.selectionMode == DisplayOpts.SELECTION_RECTANGLE:
                dc.DrawRectangle(lx,ly, (hx-lx),(hy-ly))
                
            elif self.do.selectionMode == DisplayOpts.SELECTION_SQUIGLE:
                if len(self.do.selection_trace) > 2:
                    x, y = numpy.array(self.do.selection_trace).T
                    pts = numpy.vstack(self._PixelToScreenCoordinates(x, y)).T
                    dc.DrawSpline(pts)
            elif self.do.selectionWidth == 1:
                dc.DrawLine(lx,ly, hx,hy)
            else:
                lx, ly, hx, hy = self.do.GetSliceSelection()
                dx = hx - lx
                dy = hy - ly

                if dx == 0 and dy == 0: #special case - profile is orthogonal to current plane
                    d_x = 0.5*self.do.selectionWidth
                    d_y = 0.5*self.do.selectionWidth
                else:
                    d_x = 0.5*self.do.selectionWidth*dy/numpy.sqrt((dx**2 + dy**2))
                    d_y = 0.5*self.do.selectionWidth*dx/numpy.sqrt((dx**2 + dy**2))
                    
                x_0, y_0 = self._PixelToScreenCoordinates(lx + d_x, ly - d_y)
                x_1, y_1 = self._PixelToScreenCoordinates(lx - d_x, ly + d_y)
                x_2, y_2 = self._PixelToScreenCoordinates(hx - d_x, hy + d_y)
                x_3, y_3 = self._PixelToScreenCoordinates(hx + d_x, hy - d_y)
                
                lx, ly = self._PixelToScreenCoordinates(lx, ly)
                hx, hy = self._PixelToScreenCoordinates(hx, hy)
               

                dc.DrawLine(lx, ly, hx, hy)
                dc.DrawPolygon([(x_0, y_0), (x_1, y_1), (x_2, y_2), (x_3, y_3)])
                    
            dc.SetPen(wx.NullPen)
            dc.SetBrush(wx.NullBrush)
            
    def DrawTracks(self, view, dc):
        if self.showTracks and 'filter' in dir(self) and 'clumpIndex' in self.filter.keys():
            t = self.filter['t']
            x = self.filter['x']/self.voxelsize[0]
            y = self.filter['y']/self.voxelsize[1]
            
            xb, yb, zb = self._calcVisibleBounds()
            
            IFoc = (x >= xb[0])*(y >= yb[0])*(t >= zb[0])*(x < xb[1])*(y < yb[1])*(t < zb[1])
            
            tFoc = list(set(self.filter['clumpIndex'][IFoc]))

            dc.SetBrush(wx.TRANSPARENT_BRUSH)

            #pGreen = wx.Pen(wx.TheColourDatabase.FindColour('RED'),1)
            #pRed = wx.Pen(wx.TheColourDatabase.FindColour('RED'),1)
            #dc.SetPen(pGreen)
            

            for tN in tFoc:
                IFoc = (self.filter['clumpIndex'] == tN)
                if IFoc.sum() < 2:
                    return
                pFoc = numpy.vstack(self._PixelToScreenCoordinates3D(x[IFoc], y[IFoc], t[IFoc])).T
                
                #print pFoc.shape
                dc.SetPen(self.labelPens[tN%16])
                dc.DrawLines(pFoc)
                
    def DrawScaleBar(self, view, dc):
        if self.showScaleBar:
            pGreen = wx.Pen(wx.TheColourDatabase.FindColour('WHITE'),10)
            pGreen.SetCap(wx.CAP_BUTT)
            dc.SetPen(pGreen)
            sX, sY = view.imagepanel.Size
            
            sbLen = self.scaleBarLength*view.scale/view.voxelsize[0]
            
            y1 = 20
            x1 = 20 + sbLen
            x0 = x1 - sbLen
            dc.DrawLine(x0, y1, x1, y1)
            
            dc.SetTextForeground(wx.TheColourDatabase.FindColour('WHITE'))
            if self.scaleBarLength > 1000:
                s = u'%1.1f \u03BCm' % (self.scaleBarLength/1000.)
            else:
                s = u'%d mm' % int(self.scaleBarLength)
            w, h = dc.GetTextExtent(s)
            dc.DrawText(s, x0 + (sbLen - w)/2, y1 + 7)
                
    def DrawContours(self, view, dc):
        if self.showContours and 'filter' in dir(self) and 'contour' in self.filter.keys() and self.do.slice ==self.do.SLICE_XY:
            t = self.filter['t']
            x = self.filter['x']/self.voxelsize[0]
            y = self.filter['y']/self.voxelsize[1]
            
            xb, yb, zb = self._calcVisibleBounds()
            
            IFoc = (x >= xb[0])*(y >= yb[0])*(t >= zb[0])*(x < xb[1])*(y < yb[1])*(t < zb[1])

            dc.SetBrush(wx.TRANSPARENT_BRUSH)

            pGreen = wx.Pen(wx.TheColourDatabase.FindColour('RED'),1)
            #pRed = wx.Pen(wx.TheColourDatabase.FindColour('RED'),1)
            dc.SetPen(pGreen)
            
            contours = self.filter['contour'][IFoc]
            if 'clumpIndex' in self.filter.keys():
                colInds = self.filter['clumpIndex'][IFoc] %len(self.labelPens)
            else:
                colInds = numpy.zeros(len(contours), 'i')
            for c, colI in zip(contours, colInds):
                xc, yc = c.T
                dc.SetPen(self.labelPens[int(colI)])
                dc.DrawSpline(numpy.vstack(self._PixelToScreenCoordinates(xc, yc)).T)
                
    
       
    def DrawPoints(self, view, dc):
        dx = 0
        dy = 0
        
        aN = SLICE_AXIS_LUT[self.do.slice]
        tolN = TOL_AXIS_LUT[self.do.slice]
        pos = [self.do.xp, self.do.yp, self.do.zp]

        if self.showPoints and ('filter' in dir(self) or len(self.points) > 0):
            if 'filter' in dir(self):
                t = self.filter['t']
                x = self.filter['x']/self.voxelsize[0]
                y = self.filter['y']/self.voxelsize[1]
                
                xb, yb, zb = self._calcVisibleBounds()
                
                IFoc = (x >= xb[0])*(y >= yb[0])*(t >= zb[0])*(x < xb[1])*(y < yb[1])*(t < zb[1])
                    
                pFoc = numpy.vstack((x[IFoc], y[IFoc], t[IFoc])).T
                if self.pointMode == 'splitter':
                    pCol = self.filter['gFrac'][IFoc] > .5                
                pNFoc = []

            #intrinsic points            
            elif len(self.points) > 0:
                pointTol = self.pointTolNFoc[self.pointMode]
                
                IFoc = abs(self.points[:,aN] - pos[aN]) < 1
                INFoc = abs(self.points[:,aN] - pos[aN]) < pointTol[tolN]
                    
                pFoc = self.points[IFoc]
                pNFoc = self.points[INFoc]
                
                if self.pointMode == 'splitter':
                    pCol = self.pointColours[IFoc]
                    
            if self.pointMode == 'splitter':
                if 'chroma' in dir(self):
                    dx = self.chroma.dx.ev(pFoc[:,0]*1e3*self.voxelsize[0], pFoc[:,1]*1e3*self.voxelsize[1])/(1e3*self.voxelsize[0])
                    dy = self.chroma.dy.ev(pFoc[:,0]*1e3*self.voxelsize[0], pFoc[:,1]*1e3*self.voxelsize[1])/(1e3*self.voxelsize[1])
                else:
                    dx = 0*pFoc[:,0]
                    dy = 0*pFoc[:,0]

                if 'chroma' in dir(self):
                    dxn = self.chroma.dx.ev(pNFoc[:,0]*1e3*self.voxelsize[0], pNFoc[:,1]*1e3*self.voxelsize[1])/(1e3*self.voxelsize[0])
                    dyn = self.chroma.dy.ev(pNFoc[:,0]*1e3*self.voxelsize[0], pNFoc[:,1]*1e3*self.voxelsize[1])/(1e3*self.voxelsize[1])
                else:
                    dxn = 0*pFoc[:,0]
                    dyn = 0*pFoc[:,0]

            dc.SetBrush(wx.TRANSPARENT_BRUSH)
            ps = self.pointSize

            if self.showAdjacentPoints:
                dc.SetPen(wx.Pen(wx.TheColourDatabase.FindColour('BLUE'),1))
                
                if self.pointMode == 'splitter':
                    for p, dxi, dyi in zip(pNFoc, dxn, dyn):
                        self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps, ps)
                        self._drawBoxPixelCoords(dc, p[0]-dxi, 0.5*self.do.ds.shape[1] + p[1]-dyi, p[2], ps, ps, ps)

                else:
                    for p in pNFoc:
                        self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps, ps)


            pGreen = wx.Pen(wx.TheColourDatabase.FindColour('GREEN'),1)
            pRed = wx.Pen(wx.TheColourDatabase.FindColour('RED'),1)
            dc.SetPen(pGreen)
            
            if self.pointMode == 'splitter':
                for p, c, dxi, dyi in zip(pFoc, pCol, dx, dy):
                    if c:
                        dc.SetPen(pGreen)
                    else:
                        dc.SetPen(pRed)
                        
                    self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps, ps)
                    self._drawBoxPixelCoords(dc, p[0]-dxi, 0.5*self.do.ds.shape[1] + p[1]-dyi, p[2], ps, ps, ps)
                    
            else:
                for p in pFoc:
                    self._drawBoxPixelCoords(dc, p[0], p[1], p[2], ps, ps, ps)
            
            dc.SetPen(wx.NullPen)
            dc.SetBrush(wx.NullBrush)

    def _calcVisibleBounds(self):
        sc = pow(2.0,(self.do.scale)) 
        x0,y0 = self.CalcUnscrolledPosition(0,0)
        sX, sY = self.imagepanel.Size
        
        if self.do.slice == self.do.SLICE_XY:
            bnds = [(x0/sc, (x0+sX)/sc), (y0/sc, (y0+sY)/sc), (self.do.zp-.5, self.do.zp+.5)]
        elif self.do.slice == self.do.SLICE_XZ:
            bnds = [(x0/sc, (x0+sX)/sc), (self.do.yp-.5, self.do.yp+.5), (y0/sc, (y0+sY)/sc)]
        elif self.do.slice == self.do.SLICE_YZ:
            bnds = [(self.do.xp-.5, self.do.xp+.5),(x0/sc, (x0+sX)/sc), (y0/sc, (y0+sY)/sc)]

        return bnds
        
    
    
    def DoPaint(self, dc):
        #print 'p'
        
        dc.Clear()
                                     
        im = self.Render()

        sc = pow(2.0,(self.do.scale))
        sc2 = sc
        
        if sc >= 1:
            step = 1
        else:
            step = 2**(-numpy.ceil(numpy.log2(sc)))
            sc2 = sc*step
            
        #sX, sY = view.imagepanel.Size
            
        #im.Rescale(im.GetWidth()*sc2,im.GetHeight()*sc2*self.aspect)

        
        im2 = wx.BitmapFromImage(im)
        dc.DrawBitmap(im2,-sc2/2,-sc2/2)
        
        #sX, sY = im.GetWidth(), im.GetHeight()

        self.DrawCrosshairs(self, dc)
        self.DrawSelection(self, dc) 
        self.DrawScaleBar(self, dc)

        #self.DrawTracks(self, dc)
        self.DrawPoints(self, dc)
        self.DrawContours(self, dc)

        dc.SetPen(wx.NullPen)
        dc.SetBrush(wx.NullBrush)
            
        for ovl in self.do.overlays:
            ovl(self, dc)
            
#    def OnPaint(self,event):
#        self.painting = True
#        DC = wx.PaintDC(self.imagepanel)
#        if not time.time() > (self.lastUpdateTime + 2*self.lastFrameTime): #avoid paint floods
#            if not self.refrTimer.IsRunning():
#                self.refrTimer.Start(.2, True) #make sure we do get a refresh after disposing of flood
#            return
#
#        frameStartTime = time.time()
#        self.imagepanel.impanel.PrepareDC(DC)
#
#        x0,y0 = self.imagepanel.CalcUnscrolledPosition(0,0)
#
#        #s = self.imagepanel.GetVirtualSize()
#        s = self.imagepanel.impanel.GetClientSize()
#        MemBitmap = wx.EmptyBitmap(s.GetWidth(), s.GetHeight())
#        #del DC
#        MemDC = wx.MemoryDC()
#        OldBitmap = MemDC.SelectObject(MemBitmap)
#        try:
#            DC.BeginDrawing()
#            #DC.Clear()
#            #Perform(WM_ERASEBKGND, MemDC, MemDC);
#            #Message.DC := MemDC;
#            self.DoPaint(MemDC);
#            #Message.DC := 0;
#            #DC.BlitXY(0, 0, s.GetWidth(), s.GetHeight(), MemDC, 0, 0)
#            DC.Blit(x0, y0, s.GetWidth(), s.GetHeight(), MemDC, 0, 0)
#            DC.EndDrawing()
#        finally:
#            #MemDC.SelectObject(OldBitmap)
#            del MemDC
#            del MemBitmap
#
#        self.lastUpdateTime = time.time()
#        self.lastFrameTime = self.lastUpdateTime - frameStartTime
#
#        self.painting = False
#        #print self.lastFrameTime
            

    def OnWheel(self, event):
        rot = event.GetWheelRotation()
        if rot < 0:
            if event.RightIsDown():
                self.do.yp = max(self.do.yp - 1, 0)
            elif event.MiddleIsDown(): 
                self.do.xp = max(self.do.xp - 1, 0)
            elif event.ShiftDown():
                self.do.SetScale(self.do.scale - 1)
            else:
                self.do.zp = max(self.do.zp - 1, 0)
        if rot > 0:
            if event.RightIsDown():
                self.do.yp = min(self.do.yp + 1, self.do.ds.shape[1] -1)
            elif event.MiddleIsDown(): 
                self.do.xp = min(self.do.xp + 1, self.do.ds.shape[0] -1)
            elif event.ShiftDown():
                self.do.SetScale(self.do.scale + 1)
            else:
                self.do.zp = min(self.do.zp + 1, self.do.ds.shape[2] -1)
                
        if ('update' in dir(self.GetParent())):
             self.GetParent().update()
        else:
            self.imagepanel.Refresh()
        #self.update()
    
    def OnKeyPress(self, event):
        if event.GetKeyCode() == wx.WXK_PRIOR:
            self.do.zp = max(0, self.do.zp - 1)
            #self.optionspanel.RefreshHists()
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                #if not self.painting:
                self.imagepanel.Refresh()
                #else:
                #    if not self.refrTimer.IsRunning():
                #        self.refrTimer.Start(.2, True)

        elif event.GetKeyCode() == wx.WXK_NEXT:
            self.do.zp = min(self.do.zp + 1, self.do.ds.shape[2] - 1)
            #self.optionspanel.RefreshHists()
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
                #print 'upd'
            else:
                #if not self.painting:
                self.imagepanel.Refresh()
                #else:
                #    if not self.refrTimer.IsRunning():
                        #print 'upt'
                #        self.refrTimer.Start(.2, True)
                
        elif event.GetKeyCode() == 74: #J
            self.do.xp = (self.do.xp - 1)
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 76: #L
            self.do.xp +=1
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 73: #I
            self.do.yp += 1
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 75: #L
            self.do.yp -= 1
            if ('update' in dir(self.GetParent())):
                self.GetParent().update()
            else:
                self.imagepanel.Refresh()
        elif event.GetKeyCode() == 77: #M
            #print 'o'
            self.do.Optimise()
        else:
            event.Skip()
        

        
    def GetOpts(self,event=None):
        if (self.updating == 0):

            sc = pow(2.0,(self.do.scale))
            s = self.CalcImSize()
            self.SetVirtualSize(wx.Size(s[0]*sc,s[1]*sc))

            if not self.slice == self.do.slice:
                #if the slice has changed, change our aspect and do some
                self.slice = self.do.slice
                #if not event == None and event.GetId() in [self.cbSlice.GetId(), self.cbScale.GetId()]:
                #recenter the view
                if(self.do.slice == self.do.SLICE_XY):
                    lx = self.do.xp
                    ly = self.do.yp
                    self.aspect = self.do.aspect[1]/self.do.aspect[0]
                elif(self.do.slice == self.do.SLICE_XZ):
                    lx = self.do.xp
                    ly = self.do.zp
                    self.aspect = self.do.aspect[2]/self.do.aspect[0]
                elif(self.do.slice == self.do.SLICE_YZ):
                    lx = self.do.yp
                    ly = self.do.zp
                    self.aspect = self.do.aspect[2]/self.do.aspect[1]

                sx,sy =self.imagepanel.GetClientSize()

                #self.imagepanel.SetScrollbars(20,20,s[0]*sc/20,s[1]*sc/20,min(0, lx*sc - sx/2)/20, min(0,ly*sc - sy/2)/20)
                ppux, ppuy = self.GetScrollPixelsPerUnit()
                #self.imagepanel.SetScrollPos(wx.HORIZONTAL, max(0, lx*sc - sx/2)/ppux)
                #self.imagepanel.SetScrollPos(wx.VERTICAL, max(0, ly*sc - sy/2)/ppuy)
                self.Scroll(max(0, lx*sc - sx/2)/ppux, max(0, ly*sc*self.aspect - sy/2)/ppuy)

            #self.imagepanel.Refresh()
            self.Refresh()
            self.Update()
            
    def Optim(self, event = None):
        self.do.Optimise(self.do.ds, int(self.do.zp))
        self.updating=1
        #self.SetOpts()
        #self.optionspanel.RefreshHists()
        self.Refresh()
        self.Update()
        self.updating=0
        
    def CalcImSize(self):
        if (self.do.slice == self.do.SLICE_XY):
            if (self.do.orientation == self.do.UPRIGHT):
                return (self.do.ds.shape[0],self.do.ds.shape[1])
            else:
                return (self.do.ds.shape[1],self.do.ds.shape[0])
        elif (self.do.slice == self.do.SLICE_XZ):
            return (self.do.ds.shape[0],self.do.ds.shape[2])
        else:
            return(self.do.ds.shape[1],self.do.ds.shape[2] )
        
    def DoNix(self, event):
        pass

    def OnLeftDown(self,event):
        if self.do.leftButtonAction == self.do.ACTION_SELECTION:
            self.StartSelection(event)
            
        event.Skip()
    
    def OnLeftUp(self,event):
        if self.do.leftButtonAction == self.do.ACTION_SELECTION:
            self.ProgressSelection(event)
            self.EndSelection()
        else:
            self.OnSetPosition(event)
            
        event.Skip()
        
    def OnMiddleDown(self,event):
        dc = wx.ClientDC(self.imagepanel)
        self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        self.middleDownPos = self.CalcUnscrolledPosition(*pos)
        event.Skip()
    
    def OnMiddleUp(self,event):
        dc = wx.ClientDC(self.imagepanel)
        self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)

        dx = pos[0] - self.middleDownPos[0]
        dy = pos[1] - self.middleDownPos[1]
        
        sc = pow(2.0,(self.do.scale))

        if (abs(dx) > 5) or (abs(dy) > 5):
            for h in self.CenteringHandlers:
                h(-dx/sc,-dy/sc)
        
        event.Skip()
        
    def OnMiddleDClick(self,event):
        dc = wx.ClientDC(self.imagepanel)
        self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)
        #print pos
        sc = pow(2.0,(self.do.scale))
        if (self.do.slice == self.do.SLICE_XY):
            x = (pos[0]/sc) - 0.5*self.do.ds.shape[0]
            y = (pos[1]/(sc*self.aspect)) - 0.5*self.do.ds.shape[1]
            
            for h in self.CenteringHandlers:
                h(x,y)
            
        event.Skip()
    
            
    def OnSetPosition(self,event):
        dc = wx.ClientDC(self.imagepanel)
        #self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)

        print(pos)
        self.do.inOnChange = True
        sc = pow(2.0,(self.do.scale))
        print(sc)
        if (self.do.slice == self.do.SLICE_XY):
            self.do.xp =int(pos[0]/sc)
            self.do.yp = int(pos[1]/(sc*self.aspect))
        elif (self.do.slice == self.do.SLICE_XZ):
            self.do.xp =int(pos[0]/sc)
            self.do.zp =int(pos[1]/(sc*self.aspect))
        elif (self.do.slice == self.do.SLICE_YZ):
            self.do.yp =int(pos[0]/sc)
            self.do.zp =int(pos[1]/(sc*self.aspect))
            
        self.do.inOnChange = False
        self.do.OnChange()
        #if ('update' in dir(self.GetParent())):
        #     self.GetParent().update()
        #else:
        #    self.imagepanel.Refresh()

    def PointsHitTest(self):
        if len(self.points) > 0:
            iCand = numpy.where((abs(self.points[:,2] - self.do.zp) < 1)*(abs(self.points[:,0] - self.do.xp) < 3)*(abs(self.points[:,1] - self.do.yp) < 3))[0]

            if len(iCand) == 0:
                return None
            elif len(iCand) == 1:
                return iCand[0]
            else:
                pCand = self.points[iCand, :]

                iNearest = numpy.argmin((pCand[:,0] - self.do.xp)**2 + (pCand[:,1] - self.do.yp)**2)

                return iCand[iNearest]
        else:
            return None


    def OnRightDown(self, event):
        self.StartSelection(event)
            
    def StartSelection(self,event):
        self.selecting = True
        
        dc = wx.ClientDC(self.imagepanel)
        #self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)
        #print pos
        sc = pow(2.0,(self.do.scale))
        if (self.do.slice == self.do.SLICE_XY):
            self.do.selection_begin_x = int(pos[0]/sc)
            self.do.selection_begin_y = int(pos[1]/(sc*self.aspect))
        elif (self.do.slice == self.do.SLICE_XZ):
            self.do.selection_begin_x = int(pos[0]/sc)
            self.do.selection_begin_z = int(pos[1]/(sc*self.aspect))
        elif (self.do.slice == self.do.SLICE_YZ):
            self.do.selection_begin_y = int(pos[0]/sc)
            self.do.selection_begin_z = int(pos[1]/(sc*self.aspect))
            
        self.do.selection_trace = []
        self.do.selection_trace.append(((pos[0]/sc), (pos[1]/(sc*self.aspect))))

    def OnRightUp(self,event):
        self.ProgressSelection(event)
        self.EndSelection()

    def OnMotion(self, event):
        if event.Dragging() and self.selecting:
            self.ProgressSelection(event)
            
    def ProgressSelection(self,event):
        dc = wx.ClientDC(self.imagepanel)
        #self.imagepanel.PrepareDC(dc)
        pos = event.GetLogicalPosition(dc)
        pos = self.CalcUnscrolledPosition(*pos)
        #print pos
        
        sc = pow(2.0,(self.do.scale))

        if not event.ShiftDown():
            if (self.do.slice == self.do.SLICE_XY):
                self.do.selection_end_x = int(pos[0]/sc)
                self.do.selection_end_y = int(pos[1]/(sc*self.aspect))
            elif (self.do.slice == self.do.SLICE_XZ):
                self.do.selection_end_x = int(pos[0]/sc)
                self.do.selection_end_z = int(pos[1]/(sc*self.aspect))
            elif (self.do.slice == self.do.SLICE_YZ):
                self.do.selection_end_y = int(pos[0]/sc)
                self.do.selection_end_z = int(pos[1]/(sc*self.aspect))
        else: #lock
            if (self.do.slice == self.do.SLICE_XY):
                self.do.selection_end_x = int(pos[0]/sc)
                self.do.selection_end_y = int(pos[1]/(sc*self.aspect))

                dx = abs(self.do.selection_end_x - self.do.selection_begin_x)
                dy = abs(self.do.selection_end_y - self.do.selection_begin_y)

                if dx > 1.5*dy: #horizontal
                    self.do.selection_end_y = self.do.selection_begin_y
                elif dy > 1.5*dx: #vertical
                    self.do.selection_end_x = self.do.selection_begin_x
                else: #diagonal
                    self.do.selection_end_y = self.do.selection_begin_y + dx*numpy.sign(self.do.selection_end_y - self.do.selection_begin_y)

            elif (self.do.slice == self.do.SLICE_XZ):
                self.do.selection_end_x = int(pos[0]/sc)
                self.do.selection_end_z = int(pos[1]/(sc*self.aspect))
            elif (self.do.slice == self.do.SLICE_YZ):
                self.do.selection_end_y = int(pos[0]/sc)
                self.do.selection_end_z = int(pos[1]/(sc*self.aspect))
                
        self.do.selection_trace.append(((pos[0]/sc), (pos[1]/(sc*self.aspect))))

        #if ('update' in dir(self.GetParent())):
        #     self.GetParent().update()
        #self.update()
        #else:
        self.Refresh()
        self.Update()

    def EndSelection(self):
        self.selecting = False
            
        
    def _gensig(self, x0, y0, sX,sY, do):
        sig = [x0, y0, sX, sY, do.scale, do.slice, do.GetActiveChans(), do.ds.shape]
        if do.slice == DisplayOpts.SLICE_XY:
            sig += [do.zp, do.maximumProjection]
        if do.slice == DisplayOpts.SLICE_XZ:
            sig += [do.yp]
        if do.slice == DisplayOpts.SLICE_YZ:
            sig += [do.xp]
            
        return sig
    
    def Redraw(self, caller=None):
        self._oldImSig = None
        self.Refresh()
        self.Update()
#################################################################
    def Render(self):
        #print 'rend'
        x0,y0 = self.CalcUnscrolledPosition(0,0)
        sX, sY = self.imagepanel.Size
        
        sig = self._gensig(x0, y0, sX, sY, self.do)
        if sig == self._oldImSig:# and not self._oldIm == None:
            #if nothing has changed, don't re-render
            return self._oldIm

        aspect = {}

        sc = pow(2.0,self.do.scale)
        sc2 = sc
        
        if sc >= 1:
            step = 1
        else:
            step = 2**(-numpy.ceil(numpy.log2(sc)))
            sc2 = sc*step
        
        sX_ = int(sX/(sc))
        sY_ = int(sY/(sc*self.aspect))
        x0_ = int(x0/sc)
        y0_ = int(y0/(sc*self.aspect))
        
        #sc = pow(2.0,(self.do.scale-2))
        
        #print sX, sX_, self.do.ds.shape[0], step, x0_, y0_
        
        
            #sc = sc*step
            
        fstep = float(step)

        #XY
        if self.do.slice == DisplayOpts.SLICE_XY:
            ima = numpy.zeros(
                (numpy.ceil(min(sY_, self.do.ds.shape[1])/fstep), 
                 numpy.ceil(min(sX_, self.do.ds.shape[0])/fstep), 3), 
                 'uint8'
                )
            #print ima.shape
            for chan, offset, gain, cmap in self.do.GetActiveChans():#zip(self.do.Chans, self.do.Offs, self.do.Gains, self.do.cmaps, self.do.show):
                #ima[:] = numpy.minimum(ima[:] + (255*cmap(gain*(self.do.ds[x0_:(x0_+sX_),y0_:(y0_+sY_),int(self.do.zp), chan].squeeze().T - offset))[:,:,:3])[:], 255)
                #cmap =
                
                #print lut.shape
                #if show:
                if not cmap == labeled:
                    #seg = self.do.ds[x0_:(x0_+sX_),y0_:(y0_+sY_),int(self.do.zp), chan].squeeze().T
                    #seg = seg.astype('f4')
                    #g = numpy.float32(255.*gain)
                    #o = numpy.float32(offset)
                    #seg = (g*(seg - o))
                    #print seg.dtype
                    #seg = seg.astype('uint8')
                    #seg = (g*(self.do.ds[x0_:(x0_+sX_),y0_:(y0_+sY_),int(self.do.zp), chan].squeeze().T - o)).astype('uint8')
                    #seg = lut[seg]
                    #print seg.shape
                    #ima[:] = seg
                    #ima[:,:,0] = seg
                    #ima[:,:,1] = seg
                    #ima[:,:,2] = seg
                    lut = getLUT(cmap)
                    
                    if self.do.maximumProjection:
                        seg = self.do.ds[x0_:(x0_+sX_):step,y0_:(y0_+sY_):step,:, chan].max(2).squeeze().T
                        if self.do.colourMax:
                            aseg = self.do.ds[x0_:(x0_+sX_):step,y0_:(y0_+sY_):step,:, chan].argmax(2).squeeze().T
                            applyLUT(aseg, self.do.cmax_scale/self.do.ds.shape[2], self.do.cmax_offset, lut, ima)
                            ima[:] = (ima*numpy.clip((seg - offset)*gain, 0,1)[:,:,None]).astype('uint8')
                        else:
                            applyLUT(seg, gain, offset, lut, ima)
                    else:
                        seg = self.do.ds[x0_:(x0_+sX_):step,y0_:(y0_+sY_):step,int(self.do.zp), chan].squeeze().T
                        
                        if numpy.iscomplexobj(seg):
                            if self.do.complexMode == 'real':
                                applyLUT(seg.real, gain, offset, lut, ima)
                            elif self.do.complexMode == 'imag':
                                applyLUT(seg.imag, gain, offset, lut, ima)
                            elif self.do.complexMode == 'abs':
                                applyLUT(numpy.abs(seg), gain, offset, lut, ima)
                            elif self.do.complexMode == 'angle':
                                applyLUT(numpy.angle(seg), gain, offset, lut, ima)
                            else:
                                applyLUT(numpy.angle(seg), self.do.cmax_scale/self.do.ds.shape[2], self.do.cmax_offset, lut, ima)
                                ima[:] = (ima*numpy.clip((numpy.abs(seg) - offset)*gain, 0,1)[:,:,None]).astype('uint8')
                        else:
                            #print seg.shape
                            applyLUT(seg, gain, offset, lut, ima)

                else:
                    if self.layerMode == 'mult':
                        ima[:] = numpy.minimum(ima[:]*(cmap(gain*(self.do.ds[x0_:(x0_+sX_):step,y0_:(y0_+sY_):step,int(self.do.zp), chan].squeeze().T - offset))[:,:,:3])[:], 255)
                    else:
                        ima[:] = numpy.minimum(ima[:] + (255*cmap(gain*(self.do.ds[x0_:(x0_+sX_):step,y0_:(y0_+sY_):step,int(self.do.zp), chan].squeeze().T - offset))[:,:,:3])[:], 255)
        #XZ
        elif self.do.slice == DisplayOpts.SLICE_XZ:
            ima = numpy.zeros((numpy.ceil(min(sY_, self.do.ds.shape[2])/fstep), numpy.ceil(min(sX_, self.do.ds.shape[0])/fstep), 3), 'uint8')

            for chan, offset, gain, cmap in self.do.GetActiveChans():#in zip(self.do.Chans, self.do.Offs, self.do.Gains, self.do.cmaps):
                if not cmap == labeled:
                    lut = getLUT(cmap)
                    seg = self.do.ds[x0_:(x0_+sX_):step,int(self.do.yp),y0_:(y0_+sY_):step, chan].squeeze().T
                    applyLUT(seg, gain, offset, lut, ima)
                else:
                    ima[:] = ima[:] + 255*cmap(gain*(self.do.ds[x0_:(x0_+sX_):step,int(self.do.yp),y0_:(y0_+sY_):step, chan].squeeze().T - offset))[:,:,:3][:]

        #YZ
        elif self.do.slice == DisplayOpts.SLICE_YZ:
            ima = numpy.zeros((numpy.ceil(min(sY_, self.do.ds.shape[2])/fstep), numpy.ceil(min(sX_, self.do.ds.shape[1])/fstep), 3), 'uint8')

            for chan, offset, gain, cmap in self.do.GetActiveChans():#zip(self.do.Chans, self.do.Offs, self.do.Gains, self.do.cmaps):
                if not cmap == labeled:
                    lut = getLUT(cmap)
                    seg = self.do.ds[int(self.do.xp),x0_:(x0_+sX_):step,y0_:(y0_+sY_):step, chan].squeeze().T
                    applyLUT(seg, gain, offset, lut, ima)
                else:
                    ima[:] = ima[:] + 255*cmap(gain*(self.do.ds[int(self.do.xp),x0_:(x0_+sX_):step,y0_:(y0_+sY_):step, chan].squeeze().T - offset))[:,:,:3][:]
#        

        ######################################

        #import matplotlib.pyplot as plt
        #print '> ready to show'
        #plt.imshow(ima)
        #plt.show()

        ######################################


        img = wx.ImageFromData(ima.shape[1], ima.shape[0], ima.ravel())
        img.Rescale(img.GetWidth()*sc2,img.GetHeight()*sc2*self.aspect)
        self._oldIm = img
        self._oldImSig = sig
        return img
示例#10
0
    def __init__(self, image,  parent=None, title='', mode='LM', 
                 size = (800,700), glCanvas=None):
        wx.Frame.__init__(self,parent, -1, title,size=size, pos=(1100, 300))
        
        self.SetAutoLayout(True)

        self.mode = mode
        self.glCanvas = glCanvas
        self.paneHooks = []
        self.updateHooks = []
        self.statusHooks = []
        self.installedModules = []
        
        self.dataChangeHooks = []

        self.updating = False

        if glCanvas:
            self.glCanvas.wantViewChangeNotification.add(self)

        self.pane0 = None

        self.timer = mytimer()
        self.timer.Start(10000)

        self.image = image
        #self.image = ImageStack(data = dstack, mdh = mdh, filename = filename, queueURI = queueURI, events = None)
        if not self.image.filename == None and title == '':
            self.SetTitle(self.image.filename)

        self._mgr = aui.AuiManager(agwFlags = aui.AUI_MGR_DEFAULT | aui.AUI_MGR_AUTONB_NO_CAPTION)
        atabstyle = self._mgr.GetAutoNotebookStyle()
        self._mgr.SetAutoNotebookStyle((atabstyle ^ aui.AUI_NB_BOTTOM) | aui.AUI_NB_TOP)
        # tell AuiManager to manage this frame
        self._mgr.SetManagedWindow(self)

        self.do = DisplayOpts(self.image.data)
        if self.image.data.shape[1] == 1:
            self.do.slice = self.do.SLICE_XZ
        self.do.Optimise()

        if self.image.mdh and 'ChannelNames' in self.image.mdh.getEntryNames():
            self.do.names = self.image.mdh.getEntry('ChannelNames')

        #self.vp = ArraySettingsAndViewPanel(self, self.image.data, wantUpdates=[self.update], mdh=self.image.mdh)
        #self.view = ArrayViewPanel(self, do=self.do)
        #self.AddPage(self.view, True, 'Data')
        #self._mgr.AddPane(self.vp, aui.AuiPaneInfo().
        #                  Name("Data").Caption("Data").Centre().CloseButton(False).CaptionVisible(False))

        

        self.mainFrame = weakref.ref(self)
        #self.do = self.vp.do
        
        self._menus = {}
        # Menu Bar
        self.menubar = wx.MenuBar()
        self.SetMenuBar(self.menubar)
        tmp_menu = wx.Menu()
        tmp_menu.Append(wx.ID_OPEN, '&Open', "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVE, "&Save As", "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVEAS, "&Export Cropped", "", wx.ITEM_NORMAL)

        #a submenu for modules to hook and install saving functions into
        self.save_menu = wx.Menu()
        self._menus['Save'] = self.save_menu
        tmp_menu.AppendMenu(-1, 'Save &Results', self.save_menu)
        
        tmp_menu.AppendSeparator()
        tmp_menu.Append(wx.ID_CLOSE, "Close", "", wx.ITEM_NORMAL)
        self.menubar.Append(tmp_menu, "File")

        self.view_menu = wx.Menu()
        self.menubar.Append(self.view_menu, "&View")
        self._menus['View'] = self.view_menu

        #'extras' menu for modules to install stuff into
        self.mProcessing = wx.Menu()
        self.menubar.Append(self.mProcessing, "&Processing")
        self._menus['Processing'] = self.mProcessing

        # Menu Bar end
        wx.EVT_MENU(self, wx.ID_OPEN, self.OnOpen)
        wx.EVT_MENU(self, wx.ID_SAVE, self.OnSave)
        wx.EVT_MENU(self, wx.ID_SAVEAS, self.OnExport)
        wx.EVT_CLOSE(self, self.OnCloseWindow)
        wx.EVT_SIZE(self, self.OnSize)

		
        self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)

        self.panesToMinimise = []

        modules.loadMode(self.mode, self)
        self.CreateModuleMenu()

        

        self.optionspanel = OptionsPanel(self, self.do, thresholdControls=True)
        self.optionspanel.SetSize(self.optionspanel.GetBestSize())
        pinfo = aui.AuiPaneInfo().Name("optionsPanel").Right().Caption('Display Settings').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
        self._mgr.AddPane(self.optionspanel, pinfo)

        self.panesToMinimise.append(pinfo)

        self._mgr.AddPane(self.optionspanel.CreateToolBar(self), aui.AuiPaneInfo().Name("ViewTools").Caption("View Tools").CloseButton(False).
                      ToolbarPane().Right().GripperTop())

        if self.do.ds.shape[2] > 1:
            from PYME.DSView.modules import playback
            self.playbackpanel = playback.PlayPanel(self, self)
            self.playbackpanel.SetSize(self.playbackpanel.GetBestSize())

            pinfo1 = aui.AuiPaneInfo().Name("playbackPanel").Bottom().Caption('Playback').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
            self._mgr.AddPane(self.playbackpanel, pinfo1)
            self.do.WantChangeNotification.append(self.playbackpanel.update)

        #self.mWindows =  wx.Menu()
        #self.menubar.append(self.mWindows, '&Composite With')
        self.do.WantChangeNotification.append(self.update)

        self.CreateFoldPanel()
        self._mgr.Update()

        for pn in self.panesToMinimise:
            self._mgr.MinimizePane(pn)
        #self._mgr.MinimizePane(pinfo2)
        self.Layout()

        if 'view' in dir(self):
            sc = pylab.floor(pylab.log2(1.0*self.view.Size[0]/self.do.ds.shape[0]))
            #print self.view.Size[0], self.do.ds.shape[0], sc
            self.do.SetScale(sc)
            self.view.Refresh()
        self.update()
        
        self.drop = dt()        
        self.SetDropTarget(self.drop)
        
        
        
        openViewers[self.image.filename] = self
示例#11
0
class DSViewFrame(wx.Frame):
    def __init__(self, image,  parent=None, title='', mode='LM', 
                 size = (800,700), glCanvas=None):
        wx.Frame.__init__(self,parent, -1, title,size=size, pos=(1100, 300))
        
        self.SetAutoLayout(True)

        self.mode = mode
        self.glCanvas = glCanvas
        self.paneHooks = []
        self.updateHooks = []
        self.statusHooks = []
        self.installedModules = []
        
        self.dataChangeHooks = []

        self.updating = False

        if glCanvas:
            self.glCanvas.wantViewChangeNotification.add(self)

        self.pane0 = None

        self.timer = mytimer()
        self.timer.Start(10000)

        self.image = image
        #self.image = ImageStack(data = dstack, mdh = mdh, filename = filename, queueURI = queueURI, events = None)
        if not self.image.filename == None and title == '':
            self.SetTitle(self.image.filename)

        self._mgr = aui.AuiManager(agwFlags = aui.AUI_MGR_DEFAULT | aui.AUI_MGR_AUTONB_NO_CAPTION)
        atabstyle = self._mgr.GetAutoNotebookStyle()
        self._mgr.SetAutoNotebookStyle((atabstyle ^ aui.AUI_NB_BOTTOM) | aui.AUI_NB_TOP)
        # tell AuiManager to manage this frame
        self._mgr.SetManagedWindow(self)

        self.do = DisplayOpts(self.image.data)
        if self.image.data.shape[1] == 1:
            self.do.slice = self.do.SLICE_XZ
        self.do.Optimise()

        if self.image.mdh and 'ChannelNames' in self.image.mdh.getEntryNames():
            self.do.names = self.image.mdh.getEntry('ChannelNames')

        #self.vp = ArraySettingsAndViewPanel(self, self.image.data, wantUpdates=[self.update], mdh=self.image.mdh)
        #self.view = ArrayViewPanel(self, do=self.do)
        #self.AddPage(self.view, True, 'Data')
        #self._mgr.AddPane(self.vp, aui.AuiPaneInfo().
        #                  Name("Data").Caption("Data").Centre().CloseButton(False).CaptionVisible(False))

        

        self.mainFrame = weakref.ref(self)
        #self.do = self.vp.do
        
        self._menus = {}
        # Menu Bar
        self.menubar = wx.MenuBar()
        self.SetMenuBar(self.menubar)
        tmp_menu = wx.Menu()
        tmp_menu.Append(wx.ID_OPEN, '&Open', "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVE, "&Save As", "", wx.ITEM_NORMAL)
        tmp_menu.Append(wx.ID_SAVEAS, "&Export Cropped", "", wx.ITEM_NORMAL)

        #a submenu for modules to hook and install saving functions into
        self.save_menu = wx.Menu()
        self._menus['Save'] = self.save_menu
        tmp_menu.AppendMenu(-1, 'Save &Results', self.save_menu)
        
        tmp_menu.AppendSeparator()
        tmp_menu.Append(wx.ID_CLOSE, "Close", "", wx.ITEM_NORMAL)
        self.menubar.Append(tmp_menu, "File")

        self.view_menu = wx.Menu()
        self.menubar.Append(self.view_menu, "&View")
        self._menus['View'] = self.view_menu

        #'extras' menu for modules to install stuff into
        self.mProcessing = wx.Menu()
        self.menubar.Append(self.mProcessing, "&Processing")
        self._menus['Processing'] = self.mProcessing

        # Menu Bar end
        wx.EVT_MENU(self, wx.ID_OPEN, self.OnOpen)
        wx.EVT_MENU(self, wx.ID_SAVE, self.OnSave)
        wx.EVT_MENU(self, wx.ID_SAVEAS, self.OnExport)
        wx.EVT_CLOSE(self, self.OnCloseWindow)
        wx.EVT_SIZE(self, self.OnSize)

		
        self.statusbar = self.CreateStatusBar(1, wx.ST_SIZEGRIP)

        self.panesToMinimise = []

        modules.loadMode(self.mode, self)
        self.CreateModuleMenu()

        

        self.optionspanel = OptionsPanel(self, self.do, thresholdControls=True)
        self.optionspanel.SetSize(self.optionspanel.GetBestSize())
        pinfo = aui.AuiPaneInfo().Name("optionsPanel").Right().Caption('Display Settings').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
        self._mgr.AddPane(self.optionspanel, pinfo)

        self.panesToMinimise.append(pinfo)

        self._mgr.AddPane(self.optionspanel.CreateToolBar(self), aui.AuiPaneInfo().Name("ViewTools").Caption("View Tools").CloseButton(False).
                      ToolbarPane().Right().GripperTop())

        if self.do.ds.shape[2] > 1:
            from PYME.DSView.modules import playback
            self.playbackpanel = playback.PlayPanel(self, self)
            self.playbackpanel.SetSize(self.playbackpanel.GetBestSize())

            pinfo1 = aui.AuiPaneInfo().Name("playbackPanel").Bottom().Caption('Playback').CloseButton(False).MinimizeButton(True).MinimizeMode(aui.AUI_MINIMIZE_CAPT_SMART|aui.AUI_MINIMIZE_POS_RIGHT)#.CaptionVisible(False)
            self._mgr.AddPane(self.playbackpanel, pinfo1)
            self.do.WantChangeNotification.append(self.playbackpanel.update)

        #self.mWindows =  wx.Menu()
        #self.menubar.append(self.mWindows, '&Composite With')
        self.do.WantChangeNotification.append(self.update)

        self.CreateFoldPanel()
        self._mgr.Update()

        for pn in self.panesToMinimise:
            self._mgr.MinimizePane(pn)
        #self._mgr.MinimizePane(pinfo2)
        self.Layout()

        if 'view' in dir(self):
            sc = pylab.floor(pylab.log2(1.0*self.view.Size[0]/self.do.ds.shape[0]))
            #print self.view.Size[0], self.do.ds.shape[0], sc
            self.do.SetScale(sc)
            self.view.Refresh()
        self.update()
        
        self.drop = dt()        
        self.SetDropTarget(self.drop)
        
        
        
        openViewers[self.image.filename] = self
        
    def OnSize(self, event):
        #self.Layout()
        self._mgr.Update()
        #self.Refresh()
        #self.Update()

    def AddPage(self, page=None, select=True,caption='Dummy'):
        if self.pane0 == None:
            name = caption.replace(' ', '')
            self._mgr.AddPane(page, aui.AuiPaneInfo().
                          Name(name).Caption(caption).Centre().CloseButton(False).CaptionVisible(False))
            self.pane0 = name
        else:
            self._mgr.Update()
            pn = self._mgr.GetPaneByName(self.pane0)
            if pn.IsNotebookPage():
                print((pn.notebook_id))
                nbs = self._mgr.GetNotebooks()
                if len(nbs) > pn.notebook_id:
                    currPage = nbs[pn.notebook_id].GetSelection()
                self._mgr.AddPane(page, aui.AuiPaneInfo().
                              Name(caption.replace(' ', '')).Caption(caption).CloseButton(False).NotebookPage(pn.notebook_id))
                if (not select) and len(nbs) > pn.notebook_id:
                    self._mgr.Update()
                    nbs[pn.notebook_id].SetSelection(currPage)
            else:
                self._mgr.AddPane(page, aui.AuiPaneInfo().
                              Name(caption.replace(' ', '')).Caption(caption).CloseButton(False), target=pn)
                
                
                if not select:
                    self._mgr.Update()
                    nb = self._mgr.GetNotebooks()[0]
                    nb.SetSelection(0)

               
        wx.CallAfter(self._mgr.Update)
        #self.Layout() 
        #self.OnSize(None)
        #self.OnSize(None)
        

    def CreateModuleMenu(self):
        self.modMenuIds = {}
        self.mModules = wx.Menu()
        for mn in modules.allmodules():
            id = wx.NewId()
            self.mModules.AppendCheckItem(id, mn)
            self.modMenuIds[id] = mn
            if mn in self.installedModules:
                self.mModules.Check(id, True)

            wx.EVT_MENU(self, id, self.OnToggleModule)
            
        self.menubar.Append(self.mModules, "&Modules")
        
    def AddMenuItem(self, menuName, itemName='', itemCallback = None, itemType='normal', helpText = ''):   
        mItem = None
        if not menuName in self._menus.keys():
            menu = wx.Menu()
            self.menubar.Insert(self.menubar.GetMenuCount()-1, menu, menuName)
            self._menus[menuName] = menu
        else:
            menu = self._menus[menuName]
        
        if itemType == 'normal':        
            mItem = menu.Append(wx.ID_ANY, itemName, helpText, wx.ITEM_NORMAL)
            self.Bind(wx.EVT_MENU, itemCallback, mItem)
        elif itemType == 'separator':
            menu.AppendSeparator()
            
        return mItem

    def OnToggleModule(self, event):
        id = event.GetId()
        mn = self.modMenuIds[id]
        if self.mModules.IsChecked(id):
            modules.loadModule(mn, self)

        if mn in self.installedModules:
            self.mModules.Check(id, True)

        self.CreateFoldPanel()
        self._mgr.Update()

    def GetSelectedPage(self):
        nbs = self._mgr.GetNotebooks()
        currPage = nbs[0].GetCurrentPage()

        return currPage

    



    def CreateFoldPanel(self):
        pinfo = self._mgr.GetPaneByName('sidePanel')
        if pinfo.IsOk(): #we already have a sidepanel, clear
            self.sidePanel.Clear()
        else:
            self.sidePanel = afp.foldPanel(self, -1, wx.DefaultPosition,size = wx.Size(180, 1000))
            pinfo = aui.AuiPaneInfo().Name("sidePanel").Left().CloseButton(False).CaptionVisible(False)

            self._mgr.AddPane(self.sidePanel, pinfo)
            
        if len(self.paneHooks) > 0:
            pinfo.Show()

            for genFcn in self.paneHooks:
                genFcn(self.sidePanel)
        else:
            pinfo.Hide()
            

        self._mgr.Update()
        self.Refresh()
        self.Update()


    def update(self):
        if not self.updating:
            self.updating = True
            #if 'view' in dir(self):
            #    self.view.Refresh()
            statusText = 'Slice No: (%d/%d)    x: %d    y: %d' % (self.do.zp, self.do.ds.shape[2], self.do.xp, self.do.yp)
            #grab status from modules which supply it
            for sCallback in self.statusHooks:
                statusText += '\t' + sCallback() #'Frames Analysed: %d    Events detected: %d' % (self.vp.do.zp, self.vp.do.ds.shape[2], self.vp.do.xp, self.vp.do.yp, self.LMAnalyser.numAnalysed, self.LMAnalyser.numEvents)
            self.statusbar.SetStatusText(statusText)

            #if 'playbackpanel' in dir(self):
            #    self.playbackpanel.update()

            #update any modules which require it
            for uCallback in self.updateHooks:
                #print uCallback
                uCallback(self)

            self.updating = False
            
    #def Redraw(self):
    #    self.v
            
    def DataChanged(self):
        for uCallback in self.dataChangeHooks:
            uCallback(self)

    def OnOpen(self, event=None):
        ViewIm3D(ImageStack())
        

    def OnSave(self, event=None):
        self.image.Save()
        self.SetTitle(self.image.filename)

    def OnExport(self, event=None):
        self.image.Save(crop = True, view = self.view)

    def OnCrop(self):
        pass
        #View3D(self.image.data[])

    def OnCloseWindow(self, event):
        pylab.close('all')
        if (not self.image.saved):
            dialog = wx.MessageDialog(self, "Save data stack?", "PYME", wx.YES_NO|wx.CANCEL)
            ans = dialog.ShowModal()
            if(ans == wx.ID_YES):
                self.OnSave()
                self._cleanup()
            elif (ans == wx.ID_NO):
                self._cleanup()
            else: #wxID_CANCEL:   
                if (not event.CanVeto()):
                    self._cleanup()
                else:
                    event.Veto()
        else:
            self._cleanup()

    def _cleanup(self):
        self.timer.Stop()
        #for some reason AUI doesn't clean itself up properly and stops the
        #window from being garbage collected - fix this here
        self._mgr.UnInit()
        self._mgr._frame = None
        #if self.glCanvas:
        #    self.glCanvas.wantViewChangeNotification.remove(self)
        self.Destroy()

    def dsRefresh(self):
        #zp = self.vp.do.zp #save z -position
        self.do.SetDataStack(self.image.dataSource)
        #self.vp.do.zp = zp #restore z position
        self.elv.SetEventSource(self.image.dataSource.getEvents())
        self.elv.SetRange([0, self.image.dataSource.getNumSlices()])
        
        if 'ProtocolFocus' in self.elv.evKeyNames:
            self.zm = piecewiseMapping.GeneratePMFromEventList(self.elv.eventSource, self.mdh.getEntry('Camera.CycleTime'), self.mdh.getEntry('StartTime'), self.mdh.getEntry('Protocol.PiezoStartPos'))
            self.elv.SetCharts([('Focus [um]', self.zm, 'ProtocolFocus'),])

        self.update()