Example #1
1
class ImagePanel(tk.Frame):
    """ This is a wrapper class for matplotlib figure canvas.
    It implements the mediator pattern for communication with collegues.
    """

    def __init__(self, parent, name, figsize=(2,2), dpi=100, title='', wl=False, info=False, toolbar=False, cb=False):
        self.name = name
        tk.Frame.__init__(self, parent)
        self.parent = parent
        self.img_is_set = False
        self.figsize = figsize
        self.dpi = dpi
        self.title = title
        self.toolbar = toolbar
        self.wl = wl
        self.make_canvas()
        if info: self.make_info()
        self.images = None
        self.original_img = None
        self.nZoom = 0
        self.indexOfImg = 0
        self.level_is_set = False
        self.window_is_set = False
        self.initial_level = None
        self.initial_window = None
        self.img = None
        self.cb = cb
        self.cbar = None
        self.metadata = {}
        self.collegues = []

    def register(self, collegue):
        self.collegues.append(collegue)

    def inform(self, event):
        for collegue in self.collegues:
            collegue.update_(self.name, event)

    def doubleclick(self, event):
        if event.dblclick:
            self.inform('<Double-Button-1>')
            print('DoubleClick')

    def make_canvas(self):
        self.canvas_frame = tk.Frame(self, padx=5, pady=5, cursor='crosshair')
        self.canvas_frame.pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        if self.toolbar:
            self.toolbar_frame = self.make_toolbar()
            self.toolbar_frame.pack(side=tk.TOP, fill=tk.X, expand=0)

        self.f = Figure(figsize=self.figsize, dpi=self.dpi)
        self.subplot = self.f.add_subplot(111)
        self.subplot.set_title(self.title, fontsize=10)
        plt.setp(self.subplot.get_xticklabels(), fontsize=4)
        plt.setp(self.subplot.get_yticklabels(), fontsize=4)
        self.canvas = FigureCanvasTkAgg(self.f, master=self.canvas_frame)
        self.img = self.canvas.show()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        self.canvas.mpl_connect('scroll_event', self.mouseWheel)
        self.canvas.mpl_connect('button_press_event', self.doubleclick)

        if self.wl:
            self.wl_scale = self.make_wl()
            self.wl_scale.pack(side=tk.TOP, fill=tk.X, expand=0)

    def make_wl(self):
        f = font.Font(size=6)
        wl_frame = tk.Frame(self.canvas_frame)
        self.levelScale = tk.Scale(wl_frame, orient=tk.HORIZONTAL, from_=0.0, to=256.0, width=8, font=f, command=self.set_level)
        self.levelScale.pack(side=tk.TOP, fill=tk.X, expand=0)
        self.windowScale = tk.Scale(wl_frame, orient=tk.HORIZONTAL, from_=0.0, to=256.0, width=8, font=f, command=self.set_window)
        self.windowScale.pack(side=tk.TOP, fill=tk.X, expand=0)

        return wl_frame

    def make_info(self):
        self.info = tk.LabelFrame(self.parent, text='Image Info', padx=5, pady=5, width=400)
        self.info.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0)

    def make_toolbar(self):
        toolbar_frame = tk.Frame(self.canvas_frame)

        set = ('DrawRectangle$icons/Rectangle$tk.FLAT$self.drawRectangle$tk.LEFT',
               'Delete$icons/Delete$tk.FLAT$self.deleteRectangle$tk.LEFT',
               'ZoomIn$icons/ZoomIn$tk.FLAT$self.zoomIn$tk.LEFT',
               'ZoomOut$icons/ZoomOut$tk.FLAT$self.zoomOut$tk.LEFT',
               'Reset$icons/ResetZoom$tk.FLAT$self.resetZoom$tk.LEFT',
               'Move$icons/Move$tk.FLAT$self.move$tk.LEFT',
               'Ruler$icons/Ruler$tk.FLAT$self.ruler$tk.LEFT',
               'Histogram$icons/Histogram$tk.FLAT$self.histogram$tk.LEFT',
               'Info$icons/Info$tk.FLAT$self.info$tk.LEFT',
               'Save$icons/Save18$tk.FLAT$self.savePicture$tk.LEFT'
               )
        self.imgToolbar= []
        for v in set:
            text, image, relief, command, side = v.split('$')
            self.imgToolbar.append(tk.PhotoImage(file=image+'.gif'))
            button = tk.Button(toolbar_frame, image=self.imgToolbar[-1], text=text, relief=eval(relief), command=eval(command))
            button.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
        return toolbar_frame

    def drawRectangle(self):
        print('Draw rectangle!')
        self.x0 = None
        self.y0 = None
        self.x1 = None
        self.y1 = None
        self.xp0 = None
        self.yp0 = None
        self.xp1 = None
        self.yp1 = None
        self.rectangle = Rectangle((0,0), 1, 1, facecolor='None', edgecolor='green')
        self.subplot.add_patch(self.rectangle)
        self.ispressed = False
        self.bpe = self.canvas.mpl_connect('button_press_event', self.drawRectangle_onPress)
        self.bre = self.canvas.mpl_connect('button_release_event', self.drawRectangle_onRelease)
        self.mne = self.canvas.mpl_connect('motion_notify_event', self.drawRectangle_onMotion)

    def drawRectangle_onPress(self, event):
        self.xp0 = event.x
        self.yp0 = event.y
        self.x0 = event.xdata
        self.y0 = event.ydata
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rectangle.set_width(self.x1-self.x0)
        self.rectangle.set_xy((self.x0, self.y0))
        self.rectangle.set_linestyle('dashed')
        self.canvas.draw()
        self.ispressed = True


    def drawRectangle_onRelease(self, event):
        self.xp1 = event.x
        self.yp1 = event.y
        self.x1 = event.xdata
        self.y1 = event.ydata
        self.rectangle.set_width(self.x1-self.x0)
        self.rectangle.set_height(self.y1-self.y0)
        self.rectangle.set_xy((self.x0, self.y0))
        self.rectangle.set_linestyle('solid')
        self.canvas.draw()
        self.ispressed = False
        self.canvas.mpl_disconnect(self.bpe)
        self.canvas.mpl_disconnect(self.bre)
        self.canvas.mpl_disconnect(self.mne)
        print(self.xp0, self.yp0, self.xp1, self.yp1)
        self.inform('<DrawRectangle>')
        return (self.xp0, self.yp0, self.xp1, self.yp1)

    def getRectanglePoints(self):
        return (self.xp0, self.yp0, self.xp1, self.yp1)

    def drawRectangle_onMotion(self, event):
        if self.ispressed is True:
            self.x1 = event.xdata
            self.y1 = event.ydata
            self.rectangle.set_width(self.x1-self.x0)
            self.rectangle.set_height(self.y1-self.y0)
            self.rectangle.set_xy((self.x0, self.y0))
            self.rectangle.set_linestyle('dashed')
            self.canvas.draw()

    def deleteRectangle(self):
        print('Delete rectangle!')
        self.rectangle.remove()
        self.canvas.draw()
        self.inform('<DeleteRectangle>')

    def zoomIn(self):
        print('Zoom in!')
        print(np.shape(self.images))
        self.images = self.images[:,10:-10, 10:-10]
        self.show_images()
        self.nZoom = self.nZoom+1


    def zoomOut(self):
        print('ZoomOut!')
        if np.shape(self.images) != np.shape(self.original_img):
            if self.nZoom>1:
                self.images = self.original_img[:,(self.nZoom-1)*10:-(self.nZoom-1)*10, (self.nZoom-1)*10:-(self.nZoom-1)*10]
                self.show_images()
                self.nZoom = self.nZoom-1
            else:
                self.images = self.original_img
                self.nZoom = 0



    def resetZoom(self):
        print('Reset zoom!')
        self.images = self.original_img
        self.show_images()
        self.nZoom = 0

    def histogram(self):
        print('Histogram!')
        histo = tk.Toplevel()
        f = Figure(figsize=(4,4), dpi=100)
        subplot = f.add_subplot(111)
        subplot.set_title('Histogram', fontsize=10)
        plt.setp(subplot.get_xticklabels(), fontsize=8)
        plt.setp(subplot.get_yticklabels(), fontsize=8)
        canvas = FigureCanvasTkAgg(f, master=histo)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        subplot.hist(self.images.flatten(), 100, normed=True, histtype='step', fc='k', ec='k')
        canvas.draw()
        close_button = tk.Button(histo, text='Close', command = histo.destroy)
        close_button.pack(side=tk.TOP)

    def savePicture(self):
        print('Save!')
        savefile = tk.filedialog.asksaveasfilename(title='Save image as ...', defaultextension='png',
                                                  filetypes=[('all files', '.*'), ('png files', '.png')])
        if savefile:
            self.f.savefig(savefile, dpi=1200, format='png', )

    def mouseWheel(self, event):
        print('Test mouseWheel.')
        if event.button == 'down':
            self.indexOfImg = self.indexOfImg+1
            self.show_images()
            self.inform('<MouseWheelDown')
        if event.button == 'up':
            self.indexOfImg = self.indexOfImg-1
            self.show_images()
            self.inform('<MouseWheelUp')

    def change_wl(self, arg):
        print('Button press event test')

    def set_images(self, images):
        self.images = images
        if self.img_is_set == False:
            self.original_img = images
        self.show_images()
        self.img_is_set = True

    def set_metadata(self, data):
        self.metadata = data

    def show_images(self):
        plt.clf()
        if (self.indexOfImg < np.size(self.images, 0))and (self.indexOfImg >= 0):
            self.img = self.subplot.imshow(self.images[self.indexOfImg])
            if self.level_is_set == False:
                self.level = (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2
                self.window = 2*self.level
                self.levelScale.config(from_=np.min(self.images[self.indexOfImg]))
                self.levelScale.config(to=np.max(self.images[self.indexOfImg]))
                self.levelScale.set(self.level)
                self.windowScale.config(from_=0)
                self.windowScale.config(to=self.window)
                self.windowScale.set(self.window)
                if self.window < 1:
                    self.levelScale.config(resolution=0.0001)
                    self.windowScale.config(resolution=0.0001)
                self.img.set_clim(self.level-self.window/2, self.level+self.window/2)
        else:
            self.indexOfImg = 0
            self.img = self.subplot.imshow(self.images[self.indexOfImg])

            if self.level_is_set == False:
                self.level = (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2
                self.window = 2*self.level
                self.levelScale.config(from_=np.min(self.images[self.indexOfImg]))
                self.levelScale.config(to=np.max(self.images[self.indexOfImg]))
                self.levelScale.set(self.level)
                self.windowScale.config(from_=0)
                self.windowScale.config(to=self.window)
                self.windowScale.set(self.window)
                if self.window < 1:
                    self.levelScale.config(resolution=0.0001)
                    self.windowScale.config(resolution=0.0001)
                self.img.set_clim(self.level-self.window/2, self.level+self.window/2)

        if self.cb:
                if self.cbar:
                    self.cbar.set_clim(np.min(self.images[self.indexOfImg]), np.max(self.images[self.indexOfImg]))
                else:
                    self.cbar = self.f.colorbar(self.img)
        self.canvas.draw()

    def set_level(self, event):
        self.level = self.levelScale.get()
        if self.level >= (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2:
             self.window = 2*(np.max(self.images[self.indexOfImg])-self.level)
        elif self.level < (np.max(self.images[self.indexOfImg])-np.min(self.images[self.indexOfImg]))/2:
             self.window = 2*(self.level-np.min(self.images[self.indexOfImg]))
        print(self.level, self.window)
        if self.windowScale.get() <= self.window:
             self.img.set_clim(float(self.level-self.windowScale.get()/2), float(self.level+self.windowScale.get()/2))
        else:
             self.img.set_clim(float(self.level-self.window/2), float(self.level+self.window/2))
        #self.level_is_set = True
        self.windowScale.config(to = self.window)
        self.canvas.draw()

    def set_window(self, event):
        self.window = self.windowScale.get()
        self.img.set_clim(float(self.level-self.window/2), float(self.level+self.window/2))
        #self.level_is_set = True
        self.canvas.draw()



    def set_indexOfImg(self, index):
        self.indexOfImg = index

    def ruler(self):
        print('Measure!')

    def move(self):
        print('Move!')

    def info(self):
        info = tk.Toplevel()
        tk.Button(info, text='Close', command = info.destroy).pack(side=tk.TOP)
Example #2
0
class wishbone_gui(tk.Tk):
    def __init__(self, parent):
        tk.Tk.__init__(self, parent)
        self.parent = parent
        self.initialize()

    def initialize(self):
        self.grid()
        self.vals = None
        self.currentPlot = None

        #set up menu bar
        self.menubar = tk.Menu(self)
        self.fileMenu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="File", menu=self.fileMenu)
        self.fileMenu.add_command(label="Load data", command=self.loadData)
        self.fileMenu.add_command(label="Save data",
                                  state='disabled',
                                  command=self.saveData)
        self.fileMenu.add_command(label="Exit Wishbone", command=self.quitWB)

        self.analysisMenu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Analysis", menu=self.analysisMenu)
        self.analysisMenu.add_command(label="Principal component analysis",
                                      state='disabled',
                                      command=self.runPCA)
        self.analysisMenu.add_command(label="tSNE",
                                      state='disabled',
                                      command=self.runTSNE)
        self.analysisMenu.add_command(label="Diffusion map",
                                      state='disabled',
                                      command=self.runDM)
        self.analysisMenu.add_command(label="GSEA",
                                      state='disabled',
                                      command=self.runGSEA)
        self.analysisMenu.add_command(label="Wishbone",
                                      state='disabled',
                                      command=self.runWishbone)

        self.visMenu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Visualization", menu=self.visMenu)
        self.visMenu.add_command(label="Principal component analysis",
                                 state='disabled',
                                 command=self.plotPCA)
        self.visMenu.add_command(label="tSNE",
                                 state='disabled',
                                 command=self.plotTSNE)
        self.visMenu.add_command(label="Diffusion map",
                                 state='disabled',
                                 command=self.plotDM)
        self.visMenu.add_command(label="GSEA Results",
                                 state='disabled',
                                 command=self.showGSEAResults)
        self.wishboneMenu = tk.Menu(self)
        self.visMenu.add_cascade(label="Wishbone", menu=self.wishboneMenu)
        self.wishboneMenu.add_command(label="On tSNE",
                                      state='disabled',
                                      command=self.plotWBOnTsne)
        self.wishboneMenu.add_command(label="Marker trajectory",
                                      state='disabled',
                                      command=self.plotWBMarkerTrajectory)
        self.wishboneMenu.add_command(label="Heat map",
                                      state='disabled',
                                      command=self.plotWBHeatMap)
        self.visMenu.add_command(label="Gene expression",
                                 state='disabled',
                                 command=self.plotGeneExpOntSNE)
        self.visMenu.add_command(label="Set gate",
                                 state='disabled',
                                 command=self.setGate)

        self.config(menu=self.menubar)

        #intro screen
        tk.Label(self,
                 text=u"Wishbone",
                 font=('Helvetica', 48),
                 fg="black",
                 bg="white",
                 padx=100,
                 pady=50).grid(row=0)
        tk.Label(
            self,
            text=
            u"To get started, select a data file by clicking File > Load Data",
            fg="black",
            bg="white",
            padx=100,
            pady=25).grid(row=1)

        #update
        self.protocol('WM_DELETE_WINDOW', self.quitWB)
        self.grid_columnconfigure(0, weight=1)
        self.resizable(True, True)
        self.update()
        self.geometry(self.geometry())
        self.focus_force()

    def loadData(self):
        self.dataFileName = filedialog.askopenfilename(
            title='Load data file', initialdir='~/.wishbone/data')
        if (self.dataFileName != ""):
            #pop up data options menu
            self.fileInfo = tk.Toplevel()
            self.fileInfo.title("Data options")
            tk.Label(self.fileInfo, text=u"File name: ").grid(column=0, row=0)
            tk.Label(self.fileInfo,
                     text=self.dataFileName.split('/')[-1]).grid(column=1,
                                                                 row=0)

            tk.Label(self.fileInfo, text=u"Name:", fg="black",
                     bg="white").grid(column=0, row=1)
            self.fileNameEntryVar = tk.StringVar()
            tk.Entry(self.fileInfo,
                     textvariable=self.fileNameEntryVar).grid(column=1, row=1)

            if self.dataFileName.split('.')[len(self.dataFileName.split('.')) -
                                            1] == 'fcs':
                tk.Label(self.fileInfo,
                         text=u"Cofactor:",
                         fg="black",
                         bg="white").grid(column=0, row=2)
                self.cofactorVar = tk.IntVar()
                self.cofactorVar.set(5)
                tk.Entry(self.fileInfo,
                         textvariable=self.cofactorVar).grid(column=1, row=2)
            elif self.dataFileName.split('.')[len(self.dataFileName.split('.'))
                                              - 1] == 'csv':
                self.normalizeVar = tk.BooleanVar()
                tk.Checkbutton(self.fileInfo,
                               text=u"Normalize",
                               variable=self.normalizeVar).grid(column=0,
                                                                row=2,
                                                                columnspan=2)
                tk.Label(
                    self.fileInfo,
                    text=
                    u"The normalize parameter is used for correcting for library size among cells."
                ).grid(column=0, row=3, columnspan=2)

            tk.Button(self.fileInfo,
                      text="Cancel",
                      command=self.fileInfo.destroy).grid(column=0, row=4)
            tk.Button(self.fileInfo, text="Load",
                      command=self.processData).grid(column=1, row=4)

            self.wait_window(self.fileInfo)

    def processData(self):
        #clear intro screen
        for item in self.grid_slaves():
            item.grid_forget()

        #display file name
        tk.Label(self,
                 text=u"File name: " + self.fileNameEntryVar.get(),
                 fg="black",
                 bg="white").grid(column=0, row=0)

        #set up canvas for plots
        self.fig, self.ax = wishbone.wb.get_fig()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1,
                                         row=1,
                                         rowspan=10,
                                         columnspan=4,
                                         sticky='NSEW')
        tk.Label(self, text=u"Visualizations:", fg='black',
                 bg='white').grid(column=0, row=1)

        #load data based on input type
        if self.dataFileName.split('.')[len(self.dataFileName.split('.')) -
                                        1] == 'fcs':  # mass cytometry data
            self.scdata = wishbone.wb.SCData.from_fcs(
                os.path.expanduser(self.dataFileName),
                cofactor=self.cofactorVar.get())
            self.wb = None
        elif self.dataFileName.split('.')[len(self.dataFileName.split('.')) -
                                          1] == 'csv':  # sc-seq data
            self.scdata = wishbone.wb.SCData.from_csv(
                os.path.expanduser(self.dataFileName),
                data_type='sc-seq',
                normalize=self.normalizeVar.get())
            self.wb = None
        else:
            self.wb = wishbone.wb.Wishbone.load(self.dataFileName)
            self.scdata = self.wb.scdata

        #set up buttons based on data type
        if self.scdata.data_type == 'sc-seq':
            self.PCAButton = tk.Button(self,
                                       text=u"PCA",
                                       state='disabled',
                                       command=self.plotPCA)
            self.PCAButton.grid(column=0, row=2)
            self.tSNEButton = tk.Button(self,
                                        text=u"tSNE",
                                        state='disabled',
                                        command=self.plotTSNE)
            self.tSNEButton.grid(column=0, row=3)
            self.DMButton = tk.Button(self,
                                      text=u"Diffusion map",
                                      state='disabled',
                                      command=self.plotDM)
            self.DMButton.grid(column=0, row=4)
            self.GSEAButton = tk.Button(self,
                                        text=u"GSEA Results",
                                        state='disabled',
                                        command=self.showGSEAResults)
            self.GSEAButton.grid(column=0, row=5)
            self.WBButton = tk.Button(self,
                                      text=u"Wishbone",
                                      state='disabled',
                                      command=self.plotWBOnTsne)
            self.WBButton.grid(column=0, row=6)
            self.geneExpButton = tk.Button(self,
                                           text=u"Gene expression",
                                           state='disabled',
                                           command=self.plotGeneExpOntSNE)
            self.geneExpButton.grid(column=0, row=7)
            self.setGateButton = tk.Button(self,
                                           text=u"Set gate",
                                           state='disabled',
                                           command=self.setGate)
            self.setGateButton.grid(column=0, row=8)
            self.saveButton = tk.Button(self,
                                        text=u"Save plot",
                                        state='disabled',
                                        command=self.savePlot)
            self.saveButton.grid(column=4, row=0)
            self.diff_component = tk.StringVar()
            self.diff_component.set('Component 1')
            self.component_menu = tk.OptionMenu(self, self.diff_component,
                                                'Component 1', 'Component 2',
                                                'Component 3', 'Component 4',
                                                'Component 5', 'Component 6',
                                                'Component 7', 'Component 8',
                                                'Component 9')
            self.component_menu.config(state='disabled')
            self.component_menu.grid(row=0, column=2)
            self.updateButton = tk.Button(self,
                                          text=u"Update component",
                                          command=self.updateComponent,
                                          state='disabled')
            self.updateButton.grid(column=3, row=0)

            #enable buttons based on current state of scdata object
            if self.scdata.pca:
                self.analysisMenu.entryconfig(1, state='normal')
                self.visMenu.entryconfig(0, state='normal')
                self.PCAButton.config(state='normal')
            if isinstance(self.scdata.tsne, pd.DataFrame):
                self.analysisMenu.entryconfig(2, state='normal')
                self.visMenu.entryconfig(1, state='normal')
                self.visMenu.entryconfig(5, state='normal')
                self.tSNEButton.config(state='normal')
                self.geneExpButton.config(state='normal')
            if isinstance(self.scdata.diffusion_eigenvectors, pd.DataFrame):
                self.analysisMenu.entryconfig(3, state='normal')
                self.analysisMenu.entryconfig(4, state='normal')
                self.visMenu.entryconfig(2, state='normal')
                self.DMButton.config(state='normal')
        else:
            self.tSNEButton = tk.Button(self,
                                        text=u"tSNE",
                                        state='disabled',
                                        command=self.plotTSNE)
            self.tSNEButton.grid(column=0, row=2)
            self.DMButton = tk.Button(self,
                                      text=u"Diffusion map",
                                      state='disabled',
                                      command=self.plotDM)
            self.DMButton.grid(column=0, row=3)
            self.WBButton = tk.Button(self,
                                      text=u"Wishbone",
                                      state='disabled',
                                      command=self.plotWBOnTsne)
            self.WBButton.grid(column=0, row=4)
            self.geneExpButton = tk.Button(self,
                                           text=u"Gene expression",
                                           state='disabled',
                                           command=self.plotGeneExpOntSNE)
            self.geneExpButton.grid(column=0, row=5)
            self.setGateButton = tk.Button(self,
                                           text=u"Set gate",
                                           state='disabled',
                                           command=self.setGate)
            self.setGateButton.grid(column=0, row=6)
            self.saveButton = tk.Button(self,
                                        text=u"Save plot",
                                        state='disabled',
                                        command=self.savePlot)
            self.saveButton.grid(column=4, row=0)

            self.analysisMenu.delete(0)
            self.analysisMenu.delete(2)
            self.visMenu.delete(0)
            self.visMenu.delete(2)
            self.analysisMenu.entryconfig(1, state='normal')

            #enable buttons based on current state of scdata object
            if isinstance(self.scdata.tsne, pd.DataFrame):
                self.visMenu.entryconfig(0, state='normal')
                self.visMenu.entryconfig(3, state='normal')
                self.tSNEButton.config(state='normal')
                self.geneExpButton.config(state='normal')
            if isinstance(self.scdata.diffusion_eigenvectors, pd.DataFrame):
                self.analysisMenu.entryconfig(2, state='normal')
                self.visMenu.entryconfig(1, state='normal')
                self.DMButton.config(state='normal')

        #enable buttons
        self.analysisMenu.entryconfig(0, state='normal')
        self.fileMenu.entryconfig(1, state='normal')
        if self.wb:
            if isinstance(self.wb.trajectory, pd.Series):
                self.wishboneMenu.entryconfig(0, state='normal')
                self.wishboneMenu.entryconfig(1, state='normal')
                self.wishboneMenu.entryconfig(2, state='normal')
                self.WBButton.config(state='normal')
        #get genes
        self.genes = self.scdata.data.columns.values
        self.gates = {}
        self.geometry('800x550')
        #destroy pop up menu
        self.fileInfo.destroy()

    def saveData(self):
        pickleFileName = filedialog.asksaveasfilename(
            title='Save Wishbone Data',
            defaultextension='.p',
            initialfile=self.fileNameEntryVar.get())
        if pickleFileName != None:
            if self.wb != None:
                self.wb.save(pickleFileName)
            else:
                self.scdata.save_as_wishbone(pickleFileName)

    def runPCA(self):
        self.scdata.run_pca()

        #enable buttons
        self.analysisMenu.entryconfig(1, state='normal')
        self.visMenu.entryconfig(0, state='normal')
        self.PCAButton.config(state='normal')

    def runTSNE(self):
        #pop up for # components
        self.tsneOptions = tk.Toplevel()
        self.tsneOptions.title("tSNE options")
        if self.scdata.data_type == 'sc-seq':
            tk.Label(self.tsneOptions,
                     text=u"Number of components:",
                     fg="black",
                     bg="white").grid(column=0, row=0)
            self.nCompVar = tk.IntVar()
            self.nCompVar.set(15)
            tk.Entry(self.tsneOptions,
                     textvariable=self.nCompVar).grid(column=1, row=0)
        tk.Label(self.tsneOptions, text=u"Perplexity:", fg="black",
                 bg="white").grid(column=0, row=1)
        self.perplexityVar = tk.IntVar()
        self.perplexityVar.set(30)
        tk.Entry(self.tsneOptions,
                 textvariable=self.perplexityVar).grid(column=1, row=1)
        tk.Button(self.tsneOptions, text="Run",
                  command=self._runTSNE).grid(column=1, row=2)
        tk.Button(self.tsneOptions,
                  text="Cancel",
                  command=self.tsneOptions.destroy).grid(column=0, row=2)
        self.wait_window(self.tsneOptions)

    def _runTSNE(self):
        if self.scdata.data_type == 'sc-seq':
            self.scdata.run_tsne(n_components=self.nCompVar.get(),
                                 perplexity=self.perplexityVar.get())
        else:
            self.scdata.run_tsne(n_components=None,
                                 perplexity=self.perplexityVar.get())
        self.gates = {}

        #enable buttons
        if self.scdata.data_type == 'sc-seq':
            self.analysisMenu.entryconfig(2, state='normal')
            self.visMenu.entryconfig(1, state='normal')
            self.visMenu.entryconfig(5, state='normal')
        else:
            self.visMenu.entryconfig(0, state='normal')
            self.visMenu.entryconfig(3, state='normal')
        self.tSNEButton.config(state='normal')
        self.geneExpButton.config(state='normal')
        self.tsneOptions.destroy()

    def runDM(self):
        self.scdata.run_diffusion_map()

        #enable buttons
        if self.scdata.data_type == 'sc-seq':
            self.analysisMenu.entryconfig(3, state='normal')
            self.analysisMenu.entryconfig(4, state='normal')
            self.visMenu.entryconfig(2, state='normal')
        else:
            self.analysisMenu.entryconfig(2, state='normal')
            self.visMenu.entryconfig(1, state='normal')
        self.DMButton.config(state='normal')

    def runGSEA(self):
        self.GSEAFileName = filedialog.askopenfilename(
            title='Select gmt File', initialdir='~/.wishbone/tools')
        if self.GSEAFileName != "":
            self.scdata.run_diffusion_map_correlations()
            self.scdata.data.columns = self.scdata.data.columns.str.upper()
            self.outputPrefix = filedialog.asksaveasfilename(
                title='Input file prefix for saving output',
                initialdir='~/.wishbone/gsea')
            if 'mouse' in self.GSEAFileName:
                gmt_file_type = 'mouse'
            else:
                gmt_file_type = 'human'
            self.reports = self.scdata.run_gsea(
                output_stem=os.path.expanduser(self.outputPrefix),
                gmt_file=(gmt_file_type, self.GSEAFileName.split('/')[-1]))
            #enable buttons
            self.visMenu.entryconfig(3, state='normal')
            self.GSEAButton.config(state='normal')

    def runWishbone(self):
        #popup menu for wishbone options
        self.wbOptions = tk.Toplevel()
        self.wbOptions.title("Wishbone Options")

        #s
        tk.Label(self.wbOptions, text=u"Start cell:", fg="black",
                 bg="white").grid(column=0, row=0)
        self.start = tk.StringVar()
        tk.Entry(self.wbOptions, textvariable=self.start).grid(column=1, row=0)
        if (len(self.gates) > 0):
            self.cell_gate = tk.StringVar()
            self.cell_gate.set('Use cell gate')
            self.gate_menu = tk.OptionMenu(self.wbOptions, self.cell_gate,
                                           *list(self.gates.keys()))
            self.gate_menu.grid(row=0, column=2)

        #k
        tk.Label(self.wbOptions, text=u"k:", fg="black",
                 bg="white").grid(column=0, row=1)
        self.k = tk.IntVar()
        tk.Entry(self.wbOptions, textvariable=self.k).grid(column=1, row=1)
        self.k.set(15)

        #components list
        tk.Label(self.wbOptions,
                 text=u"Components list:",
                 fg='black',
                 bg='white').grid(column=0, row=2)
        self.compList = tk.StringVar()
        tk.Entry(self.wbOptions, textvariable=self.compList).grid(column=1,
                                                                  row=2)
        self.compList.set("1, 2, 3")

        #num waypoints
        tk.Label(self.wbOptions,
                 text=u"Number of waypoints:",
                 fg='black',
                 bg='white').grid(column=0, row=3)
        self.numWaypoints = tk.IntVar()
        tk.Entry(self.wbOptions, textvariable=self.numWaypoints).grid(column=1,
                                                                      row=3)
        self.numWaypoints.set(250)

        #branch
        self.branch = tk.BooleanVar()
        self.branch.set(True)
        tk.Checkbutton(self.wbOptions, text=u"Branch",
                       variable=self.branch).grid(column=0,
                                                  row=4,
                                                  columnspan=2)

        tk.Button(self.wbOptions, text="Run",
                  command=self._runWishbone).grid(column=1, row=5)
        tk.Button(self.wbOptions,
                  text="Cancel",
                  command=self.wbOptions.destroy).grid(column=0, row=5)
        self.wait_window(self.wbOptions)

    def _runWishbone(self):
        self.wb = wishbone.wb.Wishbone(self.scdata)

        if self.cell_gate.get() == 'Use cell gate':
            self.wb.run_wishbone(start_cell=self.start.get(),
                                 k=self.k.get(),
                                 components_list=[
                                     int(comp)
                                     for comp in self.compList.get().split(',')
                                 ],
                                 num_waypoints=self.numWaypoints.get())
        else:
            #randomly select start cell in gate
            print('Using cell gate:')
            print(self.cell_gate.get())
            start_cell = random.sample(list(self.gates[self.cell_gate.get()]),
                                       1)[0]
            print(start_cell)
            self.wb.run_wishbone(start_cell=start_cell,
                                 k=self.k.get(),
                                 components_list=[
                                     int(comp)
                                     for comp in self.compList.get().split(',')
                                 ],
                                 num_waypoints=self.numWaypoints.get())

        #enable buttons
        self.wishboneMenu.entryconfig(0, state='normal')
        self.wishboneMenu.entryconfig(1, state='normal')
        self.wishboneMenu.entryconfig(2, state='normal')
        self.WBButton.config(state='normal')
        self.wbOptions.destroy()

    def plotPCA(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='disabled')
        else:
            self.visMenu.entryconfig(4, state='disabled')

        #pop up for # components
        self.PCAOptions = tk.Toplevel()
        self.PCAOptions.title("PCA Plot Options")
        tk.Label(self.PCAOptions,
                 text=u"Max variance explained (ylim):",
                 fg="black",
                 bg="white").grid(column=0, row=0)
        self.yLimVar = tk.DoubleVar()
        self.yLimVar.set(round(self.scdata.pca['eigenvalues'][0][0], 2))
        tk.Entry(self.PCAOptions, textvariable=self.yLimVar).grid(column=1,
                                                                  row=0)
        tk.Label(self.PCAOptions,
                 text=u"Number of components:",
                 fg='black',
                 bg='white').grid(column=0, row=1)
        self.compVar = tk.IntVar()
        self.compVar.set(15)
        tk.Entry(self.PCAOptions, textvariable=self.compVar).grid(column=1,
                                                                  row=1)
        tk.Button(self.PCAOptions, text="Plot",
                  command=self._plotPCA).grid(column=1, row=2)
        tk.Button(self.PCAOptions,
                  text="Cancel",
                  command=self.PCAOptions.destroy).grid(column=0, row=2)
        self.wait_window(self.PCAOptions)

    def _plotPCA(self):
        self.resetCanvas()
        self.fig, self.ax = self.scdata.plot_pca_variance_explained(
            ylim=(0, self.yLimVar.get()), n_components=self.compVar.get())
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1,
                                         row=1,
                                         rowspan=10,
                                         columnspan=4,
                                         sticky='NW')
        self.currentPlot = 'pca'

        #enable buttons
        self.saveButton.config(state='normal')
        self.PCAOptions.destroy()

    def plotTSNE(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='normal')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='normal')
        else:
            self.visMenu.entryconfig(4, state='normal')

        self.resetCanvas()
        self.fig, self.ax = self.scdata.plot_tsne()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1,
                                         row=1,
                                         rowspan=10,
                                         columnspan=4,
                                         sticky='NW')
        self.currentPlot = 'tsne'

    def plotDM(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='disabled')
        else:
            self.visMenu.entryconfig(4, state='disabled')

        self.geometry('950x550')

        self.resetCanvas()
        self.fig, self.ax = self.scdata.plot_diffusion_components()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1,
                                         row=1,
                                         rowspan=10,
                                         columnspan=4,
                                         sticky='W')
        self.currentPlot = 'dm_components'

    def showGSEAResults(self):
        self.saveButton.config(state='disabled')
        self.component_menu.config(state='normal')
        self.updateButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        self.visMenu.entryconfig(6, state='disabled')

        self.resetCanvas()
        self.canvas = tk.Canvas(self, width=600, height=300)
        self.canvas.grid(column=1, row=1, rowspan=17, columnspan=4)
        self.outputText(1)
        self.currentPlot = 'GSEA_result_' + self.diff_component.get()

    def updateComponent(self):
        self.resetCanvas()
        self.canvas = tk.Canvas(self, width=600, height=300)
        self.canvas.grid(column=1,
                         row=1,
                         rowspan=17,
                         columnspan=4,
                         sticky='NSEW')
        self.outputText(int(self.diff_component.get().split(' ')[-1]))
        self.currentPlot = 'GSEA_result_' + self.diff_component.get()

    def outputText(self, diff_component):
        pos_text = str(self.reports[diff_component]['pos']).split('\n')
        pos_text = pos_text[1:len(pos_text) - 1]
        pos_text = '\n'.join(pos_text)
        neg_text = str(self.reports[diff_component]['neg']).split('\n')
        neg_text = neg_text[1:len(neg_text) - 1]
        neg_text = '\n'.join(neg_text)
        self.canvas.create_text(5,
                                5,
                                anchor='nw',
                                text='Positive correlations:\n\n',
                                font=('Helvetica', 16, 'bold'))
        self.canvas.create_text(5, 50, anchor='nw', text=pos_text)
        self.canvas.create_text(5,
                                150,
                                anchor='nw',
                                text='Negative correlations:\n\n',
                                font=('Helvetica', 16, 'bold'))
        self.canvas.create_text(5, 200, anchor='nw', text=neg_text)

    def plotWBOnTsne(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='disabled')
        else:
            self.visMenu.entryconfig(4, state='disabled')

        self.resetCanvas()
        self.fig, self.ax = self.wb.plot_wishbone_on_tsne()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1,
                                         row=1,
                                         rowspan=10,
                                         columnspan=4)
        self.currentPlot = 'wishbone_on_tsne'

    def plotWBMarkerTrajectory(self):
        self.getGeneSelection()
        if len(self.selectedGenes) < 1:
            print('Error: must select at least one gene')

        else:
            self.saveButton.config(state='normal')
            self.setGateButton.config(state='disabled')
            if self.scdata.data_type == 'sc-seq':
                self.component_menu.config(state='disabled')
                self.updateButton.config(state='disabled')
                self.visMenu.entryconfig(6, state='disabled')
            else:
                self.visMenu.entryconfig(4, state='disabled')

            self.resetCanvas()
            self.vals, self.fig, self.ax = self.wb.plot_marker_trajectory(
                self.selectedGenes)
            self.fig.set_size_inches(10, 4, forward=True)
            self.fig.tight_layout()
            self.fig.subplots_adjust(right=0.8)
            self.canvas = FigureCanvasTkAgg(self.fig, self)
            self.canvas.show()
            self.canvas.get_tk_widget().grid(column=1,
                                             row=1,
                                             rowspan=10,
                                             columnspan=5,
                                             sticky='W')
            self.currentPlot = 'wishbone_marker_trajectory'
            self.geometry('1050x550')

            #enable buttons
            self.wishboneMenu.entryconfig(2, state='normal')

    def plotWBHeatMap(self):
        self.getGeneSelection()
        if len(self.selectedGenes) < 1:
            print('Error: must select at least one gene')

        else:
            self.saveButton.config(state='normal')
            self.setGateButton.config(state='disabled')
            if self.scdata.data_type == 'sc-seq':
                self.component_menu.config(state='disabled')
                self.updateButton.config(state='disabled')
                self.visMenu.entryconfig(6, state='disabled')
            else:
                self.visMenu.entryconfig(4, state='disabled')

            self.resetCanvas()
            self.vals, self.fig, self.ax = self.wb.plot_marker_trajectory(
                self.selectedGenes)
            self.fig, self.ax = self.wb.plot_marker_heatmap(self.vals)
            self.fig.set_size_inches(10, 4, forward=True)
            self.fig.tight_layout()
            self.canvas = FigureCanvasTkAgg(self.fig, self)
            self.canvas.show()
            self.canvas.get_tk_widget().grid(column=1,
                                             row=1,
                                             rowspan=10,
                                             columnspan=5,
                                             sticky='W')
            self.currentPlot = 'wishbone_marker_heatmap'

    def plotGeneExpOntSNE(self):
        self.getGeneSelection()
        if len(self.selectedGenes) < 1:
            print('Error: must select at least one gene')

        else:
            self.saveButton.config(state='normal')
            self.setGateButton.config(state='disabled')
            if self.scdata.data_type == 'sc-seq':
                self.component_menu.config(state='disabled')
                self.updateButton.config(state='disabled')
                self.visMenu.entryconfig(6, state='disabled')
            else:
                self.visMenu.entryconfig(4, state='disabled')

            self.resetCanvas()
            self.fig, self.ax = self.scdata.plot_gene_expression(
                self.selectedGenes)
            self.canvas = FigureCanvasTkAgg(self.fig, self)
            self.canvas.show()
            self.canvas.get_tk_widget().grid(column=1,
                                             row=1,
                                             rowspan=10,
                                             columnspan=4,
                                             sticky='W')
            self.currentPlot = 'gene_expression_tsne'
            self.geometry('950x550')

    def getGeneSelection(self):
        #popup menu to get selected genes
        self.geneSelection = tk.Toplevel()
        self.geneSelection.title("Select Genes")
        tk.Label(self.geneSelection, text=u"Genes:", fg="black",
                 bg="white").grid(row=0)

        self.geneInput = wishbone.autocomplete_entry.AutocompleteEntry(
            self.genes.tolist(), self.geneSelection, listboxLength=6)
        self.geneInput.grid(row=1)
        self.geneInput.bind('<Return>', self.AddToSelected)

        self.geneSelectBox = tk.Listbox(self.geneSelection,
                                        selectmode=tk.EXTENDED)
        self.geneSelectBox.grid(row=2, rowspan=10)
        self.geneSelectBox.bind('<BackSpace>', self.DeleteSelected)
        self.selectedGenes = []

        tk.Button(self.geneSelection,
                  text="Use selected genes",
                  command=self.geneSelection.destroy).grid(row=12)
        tk.Button(self.geneSelection,
                  text="Cancel",
                  command=self.cancelGeneSelection).grid(row=13)
        self.wait_window(self.geneSelection)

    def cancelGeneSelection(self):
        self.selectedGenes = []
        self.geneSelection.destroy()

    def AddToSelected(self, event):
        self.selectedGenes.append(self.geneInput.get())
        self.geneSelectBox.insert(
            tk.END, self.selectedGenes[len(self.selectedGenes) - 1])

    def DeleteSelected(self, event):
        selected = self.geneSelectBox.curselection()
        pos = 0
        for i in selected:
            idx = int(i) - pos
            self.geneSelectBox.delete(idx, idx)
            self.selectedGenes = self.selectedGenes[:idx] + self.selectedGenes[
                idx + 1:]
            pos = pos + 1

    def savePlot(self):
        self.plotFileName = filedialog.asksaveasfilename(
            title='Save Plot',
            defaultextension='.png',
            initialfile=self.fileNameEntryVar.get() + "_" + self.currentPlot)
        if self.plotFileName != None:
            self.fig.savefig(self.plotFileName)

    def setGate(self):
        #pop up for gate name
        self.gateOptions = tk.Toplevel()
        self.gateOptions.title("Create gate for start cells")
        tk.Label(self.gateOptions, text=u"Gate name:", fg="black",
                 bg="white").grid(column=0, row=0)
        self.gateName = tk.StringVar()
        self.gateName.set('Gate ' + str(len(self.gates) + 1))
        tk.Entry(self.gateOptions, textvariable=self.gateName).grid(column=1,
                                                                    row=0)
        tk.Button(self.gateOptions, text="Select gate",
                  command=self._setGate).grid(column=1, row=1)
        tk.Button(self.gateOptions,
                  text="Cancel",
                  command=self.gateOptions.destroy).grid(column=0, row=1)
        self.wait_window(self.gateOptions)

    def _setGate(self):
        self.gateOptions.destroy()
        self.buttonPress = self.canvas.mpl_connect('button_press_event',
                                                   self._startGate)
        self.buttonRelease = self.canvas.mpl_connect('button_release_event',
                                                     self._endGate)
        self.canvas.get_tk_widget().config(cursor='plus')

    def _startGate(self, event):
        self.start_x = event.xdata
        self.start_y = event.ydata

    def _endGate(self, event):
        #draw gate rectangle
        start_x = self.start_x if self.start_x < event.xdata else event.xdata
        start_y = self.start_y if self.start_y < event.ydata else event.ydata
        width = np.absolute(event.xdata - self.start_x)
        height = np.absolute(event.ydata - self.start_y)
        rect = Rectangle((start_x, start_y),
                         width,
                         height,
                         fill=False,
                         ec='black',
                         alpha=1,
                         lw=2)
        self.ax.add_patch(rect)
        self.canvas.draw()

        #disable mouse events
        self.canvas.mpl_disconnect(self.buttonPress)
        self.canvas.mpl_disconnect(self.buttonRelease)
        self.canvas.get_tk_widget().config(cursor='arrow')

        #save cell gate
        gate = Path([[start_x, start_y], [start_x + width, start_y],
                     [start_x + width, start_y + height],
                     [start_x, start_y + height], [start_x, start_y]])
        gated_cells = self.scdata.tsne.index[gate.contains_points(
            self.scdata.tsne)]
        self.gates[self.gateName.get()] = gated_cells

        #replot tSNE w gate colored
        self.fig.clf()
        plt.scatter(self.scdata.tsne['x'],
                    self.scdata.tsne['y'],
                    s=10,
                    edgecolors='none',
                    color='lightgrey')
        plt.scatter(self.scdata.tsne.ix[gated_cells, 'x'],
                    self.scdata.tsne.ix[gated_cells, 'y'],
                    s=10,
                    edgecolors='none')
        self.canvas.draw()

        self.setGateButton.config(state='disabled')
        self.visMenu.entryconfig(6, state='disabled')

    def resetCanvas(self):
        self.fig.clf()
        if type(self.canvas) is FigureCanvasTkAgg:
            for item in self.canvas.get_tk_widget().find_all():
                self.canvas.get_tk_widget().delete(item)
        else:
            for item in self.canvas.find_all():
                self.canvas.delete(item)

    def quitWB(self):
        self.quit()
        self.destroy()
class MultilevelEditingEditingLayout:
    def __init__(self, root_frame, figure, max_lod):
        print('hi from MultilevelEditingEditingLayout')

        self.root_frame = root_frame
        self.fig = figure
        self.max_lod = max_lod

        self.root_frame.columnconfigure(0, weight=1)
        self.root_frame.rowconfigure(0, weight=1)

        self.left_frame = ttk.Frame(self.root_frame)
        self.left_frame.grid(column=0, row=0, sticky=('N', 'E', 'S', 'W'))
        self.left_frame.columnconfigure(0, weight=1)
        self.left_frame.rowconfigure(0, weight=1)

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.left_frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().grid(column=0,
                                         row=0,
                                         sticky=('N', 'S', 'E', 'W'))

        self.display_lod_scale_head = ttk.Label(
            self.left_frame, text='Level of Detail of the displayed curve:')
        self.display_lod_scale_head.grid(column=0,
                                         row=1,
                                         sticky=('W', 'N', 'E', 'S'))

        self.display_lod_scale = ttk.Scale(self.left_frame,
                                           from_=0,
                                           to=self.max_lod,
                                           orient='horizontal')
        self.display_lod_scale.grid(column=0,
                                    row=2,
                                    sticky=('W', 'N', 'E', 'S'))

        self.edit_lod_scale_head = ttk.Label(
            self.left_frame, text='Level of Detail for editing:')
        self.edit_lod_scale_head.grid(column=0,
                                      row=3,
                                      sticky=('W', 'N', 'E', 'S'))

        self.edit_lod_scale = ttk.Scale(self.left_frame,
                                        from_=0,
                                        to=self.max_lod,
                                        orient='horizontal')
        self.edit_lod_scale.grid(column=0, row=4, sticky=('W', 'N', 'E', 'S'))

        self.toolbar_frame = ttk.Frame(self.root_frame)
        self.toolbar_frame.grid(column=1, row=0, sticky=('N', 'E', 'S', 'W'))

        self.toolbar_frame.columnconfigure(0, weight=1)
        self.toolbar_frame.rowconfigure(1, weight=1)

        self.toolbar_label = ttk.Label(self.toolbar_frame, text='Toolbar')
        self.toolbar_label.grid(column=0, row=0, sticky=('W', 'E'))

        self.back_btn = ttk.Button(self.toolbar_frame, text='Back')
        self.back_btn.grid(column=0, row=1, sticky=('W', 'E', 'S'))

    def mpl_connect(self, event_type, callback):
        return self.canvas.mpl_connect(event_type, callback)

    def mpl_disconnect(self, cid):
        self.canvas.mpl_disconnect(cid)

    def redraw_figure(self):
        self.canvas.draw()

    def set_display_lod_scale_value(self, value):
        self.display_lod_scale.set(value)

    def set_edit_lod_scale_value(self, value):
        self.edit_lod_scale.set(value)

    def set_display_lod_scale_callback(self, callback):
        self.display_lod_scale['command'] = callback

    def set_edit_lod_scale_callback(self, callback):
        self.edit_lod_scale['command'] = callback

    def set_back_callback(self, callback):
        self.back_btn['command'] = callback

    def clean_up(self):
        print('MultilevelEditingEditingLayout cleaning up')

        self.back_btn.grid_forget()
        self.toolbar_label.grid_forget()
        self.toolbar_frame.grid_forget()
        self.edit_lod_scale.grid_forget()
        self.edit_lod_scale_head.grid_forget()
        self.display_lod_scale.grid_forget()
        self.display_lod_scale_head.grid_forget()
        self.canvas.get_tk_widget().grid_forget()
        self.left_frame.grid_forget()
Example #4
0
class Graph(tk.Frame):
    ax, original_xlim, original_ylim, coll, pick_id = None, None, None, None, None
    start_end_bool = -1  # 0 is start, 1 is end, -1 is None
    start_index, end_index, move_index, remove_index = 0, None, None, None
    max_time, max_speed, max_height, min_height = 0, 0, 0, 0
    data = []
    connect_ids, move_ids = [], []
    current_color_scheme = 'd'

    def __init__(self, master):
        super().__init__(master)
        self.master = master
        self.fig = Figure(figsize=(10, 7), dpi=100, tight_layout=True)
        self.fig.set_facecolor('#f0f0ed')

        self.zoom_pan = GraphInteractions.ZoomPan()
        self.master_string = tk.StringVar()

        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

    def redraw(self, input_file_location):
        x, y, c = zip(*self.read_data(input_file_location))
        self.fig.clear()
        self.ax = self.fig.add_subplot(111, frameon=False)
        self.coll = self.ax.scatter(x, y, color=c, picker=True)
        self.end_index = len(self.data) - 1
        self.connect_ids.append(
            GraphInteractions.ZoomPan.zoom_factory(self.zoom_pan,
                                                   self.ax,
                                                   base_scale=1.3))
        self.connect_ids.extend(
            GraphInteractions.ZoomPan.pan_factory(self.zoom_pan, self.ax))
        self.original_xlim = self.ax.get_xlim()
        self.original_ylim = self.ax.get_ylim()
        self.canvas.draw()

    def redraw_color(self, x, y, c):
        self.fig.clear()
        self.ax = self.fig.add_subplot(111, frameon=False)
        self.coll = self.ax.scatter(x, y, color=c, picker=True)
        self.ax.set_xlim(self.zoom_pan.cur_xlim)
        self.ax.set_ylim(self.zoom_pan.cur_ylim)
        self.connect_ids.append(
            GraphInteractions.ZoomPan.zoom_factory(self.zoom_pan,
                                                   self.ax,
                                                   base_scale=1.3))
        self.connect_ids.extend(
            GraphInteractions.ZoomPan.pan_factory(self.zoom_pan, self.ax))
        self.canvas.draw()

    def reset_zoom(self):
        self.ax.set_xlim(self.original_xlim)
        self.ax.set_ylim(self.original_ylim)
        self.ax.figure.canvas.draw()  # force re-draw

    def reset_start(self, master_string):
        self.start_index = 0
        master_string.set("")
        self.redraw_ext()

    def reset_end(self, master_string):
        self.end_index = len(self.data) - 1
        master_string.set("")
        self.redraw_ext()

    def read_data(self, input_file_location):
        x_array = []
        y_array = []
        color_array = []
        self.data.clear()
        json_file = open(input_file_location, "r")
        file_data = json.load(json_file)
        json_file.close()
        old_time, old_x, old_y = 0, file_data['recording']['path'][0][
            'x'], file_data['recording']['path'][0]['y']
        self.max_time, self.max_speed, self.max_height, self.min_height = 0, 0, 0, file_data[
            'recording']['path'][0]['z']
        speed = 0
        for time in file_data['recording']['path']:
            x_array.append(time['x'])
            y_array.append(time['y'])
            time_div = time['t'] - old_time
            if time['t'] > self.max_time:
                self.max_time = time['t']
            if time_div != 0:
                speed = distance(time['x'], old_x, time['y'], old_y) / time_div
            if speed > self.max_speed:
                self.max_speed = speed
            if time['z'] > self.max_height:
                self.max_height = time['z']
            elif time['z'] < self.min_height:
                self.min_height = time['z']
            self.data.append(
                [time['x'], time['y'], time['t'], speed, time['z']])
            color_array.append('tab:blue')
            old_time = time['t']
            old_x, old_y = time['x'], time['y']
        return zip(x_array, y_array, color_array)

    def redraw_ext(self):
        for cid in self.connect_ids:
            self.canvas.mpl_disconnect(cid)
        self.connect_ids.clear()
        x = []
        y = []
        c = []
        for idx, row in enumerate(self.data):
            x.append(row[0])
            y.append(row[1])
            if idx == self.start_index or idx == self.end_index or idx == self.remove_index:
                c.append('tab:red')
            elif idx < self.start_index or idx > self.end_index or\
                    (self.start_index == 0 and self.end_index == len(self.data) - 1):
                c.append('tab:blue')
            elif self.start_index < idx < self.end_index:
                c.append('c')

        self.redraw_color(x, y, c)

    def redraw_simp(self):
        for cid in self.connect_ids:
            self.canvas.mpl_disconnect(cid)
        self.connect_ids.clear()
        x = []
        y = []
        c = []
        for idx, row in enumerate(self.data):
            x.append(row[0])
            y.append(row[1])
            if idx == self.move_index:
                c.append('tab:red')
            else:
                c.append('tab:blue')
        self.redraw_color(x, y, c)

    def change_color(self, event):
        if event.mouseevent.button != 1: return
        if self.start_end_bool == 0:
            self.start_index = event.ind[0]
        elif self.start_end_bool == 1:
            self.end_index = event.ind[0]
        elif self.start_end_bool == 2:
            self.remove_index = event.ind[0]
        self.redraw_ext()
        self.master_string.set(
            'x: %.4f, y: %.4f' %
            (self.data[event.ind[0]][0], self.data[event.ind[0]][1]))

    def show_time(self):
        self.current_color_scheme = 't'
        for cid in self.connect_ids:
            self.canvas.mpl_disconnect(cid)
        self.connect_ids.clear()
        x = []
        y = []
        c = []
        for idx, row in enumerate(self.data):
            x.append(row[0])
            y.append(row[1])
            gradient = row[2] / self.max_time
            c.append((0, 1 - gradient, gradient))
        self.redraw_color(x, y, c)

    def show_speed(self):
        self.current_color_scheme = 's'
        for cid in self.connect_ids:
            self.canvas.mpl_disconnect(cid)
        self.connect_ids.clear()
        x = []
        y = []
        c = []
        for idx, row in enumerate(self.data):
            x.append(row[0])
            y.append(row[1])
            gradient = row[3] / self.max_speed
            c.append((1 - gradient, gradient, 0))
        self.redraw_color(x, y, c)

    def show_height(self):
        self.current_color_scheme = 'h'
        for cid in self.connect_ids:
            self.canvas.mpl_disconnect(cid)
        self.connect_ids.clear()
        x = []
        y = []
        c = []
        for idx, row in enumerate(self.data):
            x.append(row[0])
            y.append(row[1])
            gradient = (row[4] - self.min_height) / (self.max_height -
                                                     self.min_height)
            c.append((gradient * 0.5 + 0.5, gradient * 0.8, gradient * 0.8))
        self.redraw_color(x, y, c)

    def reset_color(self):
        self.current_color_scheme = 'd'
        for cid in self.connect_ids:
            self.canvas.mpl_disconnect(cid)
        self.connect_ids.clear()
        x = []
        y = []
        c = []
        for idx, row in enumerate(self.data):
            x.append(row[0])
            y.append(row[1])
            c.append('tab:blue')
        self.redraw_color(x, y, c)

    def attach_start_stop(self, master_string_var, start_end):
        self.detach_start_stop()
        self.start_end_bool = start_end
        self.master_string = master_string_var
        self.pick_id = self.canvas.mpl_connect('pick_event', self.change_color)

    def detach_start_stop(self):
        if self.pick_id is None: return
        self.start_end_bool = -1
        self.canvas.mpl_disconnect(self.pick_id)
        for move_id in self.move_ids:
            self.canvas.mpl_disconnect(move_id)

    def attach_move_node(self):
        def on_press(event):
            if event.mouseevent.button != 1: return
            self.move_index = event.ind[0]
            self.master.move_node_location.set(
                'x: %.4f, y: %.4f' %
                (self.data[self.move_index][0], self.data[self.move_index][1]))

        def on_release(event):
            self.redraw_simp()

        def on_motion(event):
            if event.button != 1: return
            self.data[self.move_index][0] = event.xdata
            self.data[self.move_index][1] = event.ydata
            self.master.move_node_location.set(
                'x: %.4f, y: %.4f' %
                (self.data[self.move_index][0], self.data[self.move_index][1]))

            self.redraw_simp()

        self.detach_start_stop()
        self.pick_id = self.canvas.mpl_connect('pick_event', on_press)
        self.move_ids.append(
            self.canvas.mpl_connect('key_press_event', self.move_node_button))
        self.move_ids.append(
            self.canvas.mpl_connect('button_release_event', on_release))
        self.move_ids.append(
            self.canvas.mpl_connect('motion_notify_event', on_motion))

    def attach_remove_node(self, master_string):
        self.detach_start_stop()
        self.start_end_bool = 2
        self.master_string = master_string
        self.pick_id = self.canvas.mpl_connect('pick_event', self.change_color)

    def next_start(self, master_string, diff):
        self.start_index += diff
        if self.start_index < 0:
            self.start_index = 0
        self.redraw_ext()
        master_string.set(
            'x: %.4f, y: %.4f' %
            (self.data[self.start_index][0], self.data[self.start_index][1]))

    def next_end(self, master_string, diff):
        self.end_index += diff
        if self.end_index > len(self.data) - 1:
            self.end_index = len(self.data) - 1
        self.redraw_ext()
        master_string.set(
            'x: %.4f, y: %.4f' %
            (self.data[self.end_index][0], self.data[self.end_index][1]))

    def move_node_button(self, event):
        direction = ""
        if event.key == "up":
            direction = "N"
        elif event.key == "right":
            direction = "E"
        elif event.key == "down":
            direction = "S"
        elif event.key == "left":
            direction = "W"
        if direction != "":
            self.move_node(direction, float(self.master.move_entry.get()))

    def move_node(self, direction, move_distance):
        if direction == "N":
            self.data[self.move_index][1] += move_distance
        elif direction == "E":
            self.data[self.move_index][0] += move_distance
        elif direction == "S":
            self.data[self.move_index][1] -= move_distance
        elif direction == "W":
            self.data[self.move_index][0] -= move_distance
        self.master.move_node_location.set(
            'x: %.4f, y: %.4f' %
            (self.data[self.move_index][0], self.data[self.move_index][1]))
        self.redraw_simp()

    def remove_node(self):
        del self.data[self.remove_index]
        self.end_index = len(self.data) - 1
        self.redraw_ext()
        self.master_string.set(
            'x: %.4f, y: %.4f' %
            (self.data[self.remove_index][0], self.data[self.remove_index][1]))

    def apply_local_speedup(self, value):
        speedup = 1
        speed = 0
        previous_time = 0
        previous_old_time = 0
        old_x, old_y = self.data[0][0], self.data[0][1]
        for idx, row in enumerate(self.data):
            if self.start_index == idx:
                speedup = 1 - float(value) / 100
            elif self.end_index == idx:
                speedup = 1
            old_time = row[2]
            if old_time < previous_old_time:
                previous_old_time = old_time / 2
            row[2] = previous_time + (min(old_time - previous_old_time, 2) *
                                      speedup)
            time_div = row[2] - previous_time
            if row[2] > self.max_time:
                self.max_time = row[2]
            if time_div != 0:
                speed = distance(row[0], old_x, row[1], old_y) / time_div
            if speed > self.max_speed:
                self.max_speed = speed
            row[3] = speed
            previous_time = row[2]
            previous_old_time = old_time
            old_x, old_y = row[0], row[1]
            self.update_unknown()

    def update_unknown(self):
        if self.current_color_scheme == 'h':
            self.show_height()
        elif self.current_color_scheme == 's':
            self.show_speed()
        elif self.current_color_scheme == 't':
            self.show_time()
        else:
            self.reset_color()
Example #5
0
class PASAview(Frame):

    #define parent window
    def __init__(self, parent):
        Frame.__init__(self, parent)

        #save a reference to the parent widget
        self.parent = parent

        #delegate the creation of the user interface to the initUI() method
        self.fig = Figure(figsize=(12, 8), dpi=100)
        self.fig.subplots_adjust(bottom=0.15, left=0.13, right=0.95, top=0.95)

        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self)
        self.toolbar.pack(side=TOP)

        #frame for buttons (at bottom)
        #buttons are arranged on grid, not pack
        self.frame_button = Frame(self)
        self.frame_button.pack(side='bottom', fill=BOTH, expand=1)

        #global variables
        #list containing wavelength domain values
        self.wavelength = []
        self.wavelength_reference = []
        #list containing wavenumber domain values
        self.wavenumber = []
        self.wavenumber_reference = []
        #list containing reflectance values
        self.refl = []
        self.refl_reference = []

        #list containing filename for legend
        self.spec_name = []
        self.spec_name_legend = []
        self.spec_name_reference = []
        self.spec_name_reference_legend = []
        self.legend_fontsize = 10

        #offset/scale values
        self.offset = [0.0]
        self.scale = [1.0]
        self.offset_reference = []
        self.scale_reference = []

        #flag to indicate autoscaling or user-defined scaling of axis
        #autoscale flag=0
        #user-defined flag=1
        self.define_axis_flag = 0
        self.xlim = [1.6, 3.6]
        self.ylim = [0, 1]

        #linestyle definition
        self.linestyle_format = ['k-']
        self.linestyle_format_legend = ['k-']
        self.linestyle_format_reference = []
        self.linestyle_format_reference_legend = []

        #flag to indicate whether wavelength or wavenumber is displayed
        #wavelength flag=0
        #wavenumber flag=1
        self.wavelength_wavenumber_flag = 0

        self.display_spectrum = IntVar()
        self.display_spectrum.set(1)
        self.display_spectrum_reference = []

        #list containing label values
        self.label_wavelength = []
        self.label_wavenumber = []
        self.label_refl = []
        self.label_size = float(10)
        #self.label_format = "%.0f"
        self.label_value = []
        #self.digits_after = 0
        #self.label_offset = 0.0
        #calibration point id
        self.cid = -99
        self.initUI()

    #container for other widgets
    def initUI(self):
        #set the title of the window using the title() method
        self.parent.title("PASA View")

        #apply a theme to widget
        self.style = Style()
        self.style.theme_use('default')

        #the Frame widget (accessed via the delf attribute) in the root window
        #it is expanded in both directions
        self.pack(fill=BOTH, expand=1)

        menubar = Menu(self.parent)
        self.parent.config(menu=menubar)

        #contains file menu items
        fileMenu = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=fileMenu)
        self.openMenu = Menu(menubar, tearoff=0)
        fileMenu.add_cascade(label="Open", menu=self.openMenu, state=NORMAL)
        self.openMenu.add_command(label="Open PASA Spectrum",
                                  command=self.onOpen)
        self.openMenu.add_command(label="Open Reference Spectrum",
                                  command=self.onOpenReference,
                                  state=DISABLED)
        #fileMenu.add_command(label="Open", command=self.onOpen)
        fileMenu.add_command(label="Export Data (ASCII file)",
                             command=self.onExport)
        fileMenu.add_command(label="Quit", command=self.quit_destroy)

        #generate figure (no data at first)
        self.generate_figure([0, 1], [[], []], ' ', [[], []])

        Label(self.frame_button, text="Modify Spectrum").grid(row=0,
                                                              column=0,
                                                              padx=5,
                                                              pady=5,
                                                              sticky=W)

        #smooth spectrum
        self.smoothButton = Button(self.frame_button,
                                   text="Smooth",
                                   command=self.smooth_data,
                                   state=DISABLED)
        self.smoothButton.grid(row=0, column=1, padx=5, pady=5, sticky=W)

        #offset spectrum
        self.offsetButton = Button(self.frame_button,
                                   text="Offset",
                                   command=self.offset_data,
                                   state=DISABLED)
        self.offsetButton.grid(row=0, column=2, padx=5, pady=5, sticky=W)

        Label(self.frame_button, text="Label Spectrum").grid(row=1,
                                                             column=0,
                                                             padx=5,
                                                             pady=5,
                                                             sticky=W)

        #label features in figure
        self.labelButton = Button(self.frame_button,
                                  text="Label Feature",
                                  command=self.label_feature,
                                  state=DISABLED)
        self.labelButton.grid(row=1, column=1, padx=5, pady=5, sticky=W)

        #remove all labels
        self.deletelabelButton = Button(self.frame_button,
                                        text="Remove Labels",
                                        command=self.delete_labels,
                                        state=DISABLED)
        self.deletelabelButton.grid(row=1, column=2, padx=5, pady=5, sticky=W)

        #define the font size of labels
        self.formatelabelButton = Button(self.frame_button,
                                         text="Format Label",
                                         command=self.format_labels)
        self.formatelabelButton.grid(row=1, column=3, padx=5, pady=5, sticky=W)

        Label(self.frame_button, text="Convert Domain").grid(row=2,
                                                             column=0,
                                                             padx=5,
                                                             pady=5,
                                                             sticky=W)

        #convert to wavelength domain
        self.wavelengthButton = Button(self.frame_button,
                                       text="Wavelength",
                                       command=self.wavelength_domain,
                                       state=DISABLED)
        self.wavelengthButton.grid(row=2, column=1, padx=5, pady=5, sticky=W)

        #convert to wavenumber domain
        self.wavenumberButton = Button(self.frame_button,
                                       text="Wavenumber",
                                       command=self.wavenumber_domain,
                                       state=DISABLED)
        self.wavenumberButton.grid(row=2, column=2, padx=5, pady=5, sticky=W)

        Label(self.frame_button, text="Configure Plot").grid(row=3,
                                                             column=0,
                                                             padx=5,
                                                             pady=5,
                                                             sticky=W)

        #define axes
        self.axesButton = Button(self.frame_button,
                                 text="Define Axes",
                                 command=self.define_axes,
                                 state=DISABLED)
        self.axesButton.grid(row=3, column=1, padx=5, pady=5, sticky=W)

        #define linestyle and legend
        self.legendButton = Button(self.frame_button,
                                   text="Legend Format",
                                   command=self.define_legend,
                                   state=DISABLED)
        self.legendButton.grid(row=3, column=2, padx=5, pady=5, sticky=W)

        #remove all spectra from plotting windows, reset variables
        self.resetButton = Button(self.frame_button,
                                  text="Reset",
                                  command=self.reset_plots,
                                  state=DISABLED)
        self.resetButton.grid(row=3, column=5, padx=5, pady=5, sticky=W)

        #quit PASAview
        self.quitButton = Button(self.frame_button,
                                 text="Quit",
                                 command=self.quit_destroy)
        self.quitButton.grid(row=3, column=6, padx=5, pady=5, sticky=E)

    #plot figure
    def generate_figure(self, data, label, xaxis_title, data_reference):
        #clear figure
        plt.clf()
        ax = self.fig.add_subplot(111)
        #clear axis
        ax.cla()
        spectrum = ax.plot(data[0],
                           data[1],
                           self.linestyle_format_legend[0],
                           label=self.spec_name_legend)
        ax.set_xlabel(xaxis_title)  #, fontsize=6)
        ax.set_ylabel('reflectance')  #, fontsize=6)
        #for autoscale
        if self.define_axis_flag == 0:
            ax.autoscale_view()
        #for user-defined scaling
        if self.define_axis_flag == 1:
            ax.set_xlim(self.xlim)
            ax.set_ylim(self.ylim)

        #add reference spectra
        for index, wave in enumerate(data_reference[0]):
            ax.plot(wave,
                    data_reference[1][index],
                    self.linestyle_format_reference_legend[index],
                    label=self.spec_name_reference_legend[index])

        #insert legend
        #the position could be user-defined
        #might consider adding this...
        ax.legend(fontsize=self.legend_fontsize)

        #add labels
        for index, label_x in enumerate(label[0]):
            an1 = ax.annotate(self.label_value[index],
                              xy=(label_x, label[1][index]),
                              xytext=(label_x, label[1][index]),
                              fontsize=self.label_size)
            an1.draggable(state=True)

        self.canvas.show()
        self.canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)

        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=True)

    #reset figure
    def reset_figure(self, data, label, xaxis_title):
        #clear figure
        plt.clf()
        ax = self.fig.add_subplot(111)
        #clear axis
        ax.cla()
        spectrum = ax.plot(data[0], data[1])
        ax.set_xlabel(xaxis_title)  #, fontsize=6)
        ax.set_ylabel('reflectance')  #, fontsize=6)
        #for autoscale
        if self.define_axis_flag == 0:
            ax.autoscale_view()
        #for user-defined scaling
        if self.define_axis_flag == 1:
            ax.set_xlim(self.xlim)
            ax.set_ylim(self.ylim)

        for index, label_x in enumerate(label[0]):
            an1 = ax.annotate(str(
                self.label_format %
                round(label_x + self.label_offset, int(self.digits_after))),
                              xy=(label_x, label[1][index]),
                              xytext=(label_x, label[1][index]),
                              fontsize=self.label_size)
            an1.draggable(state=True)

        self.canvas.show()
        self.canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=True)

    #open file
    def onOpen(self):
        #displays .txt files in browser window
        #only reads wavelength domain data files
        ftypes = [('txt files', '*.txt'), ('csv files', '*.csv'),
                  ('ASCII files', '*.asc')]
        dlg = tkFileDialog.Open(self, filetypes=ftypes)
        fl = dlg.show()
        self.spec_name = fl.rsplit('/', 1)[1][0:-4]

        if fl != '':
            if fl[-3:] == 'txt':
                data = self.readFile(fl)
                self.refl = data[1]
                #self.refl = [x+0.00075 for x in data[1]]
                self.wavelength = data[0]

            elif fl[-3:] == 'csv':
                data = self.readFile(fl)
                self.refl = data[1]
                #self.refl = [x+0.00075 for x in data[1]]
                self.wavelength = data[0]

            elif fl[-3:] == 'asc':
                data = self.readFile(fl)
                #ignore data with refl values less than 0
                index_pos = bisect.bisect(data[1], 0)
                self.refl = data[1][index_pos:]
                self.wavelength = data[0][index_pos:]

            if self.wavelength_wavenumber_flag == 0:
                self.wavelength_domain()
            elif self.wavelength_wavenumber_flag == 1:
                self.wavenumber_domain()

            #allows reference spectrum to be added
            self.openMenu.entryconfig("Open Reference Spectrum", state=NORMAL)
            #allows labels to be generated
            self.labelButton.config(state=NORMAL)
            self.deletelabelButton.config(state=NORMAL)
            #allows for smoothing/offset of data
            self.smoothButton.config(state=NORMAL)
            self.offsetButton.config(state=NORMAL)
            #allows for domain conversion
            self.wavelengthButton.config(state=NORMAL)
            self.wavenumberButton.config(state=NORMAL)
            #allows plot to be configured
            self.axesButton.config(state=NORMAL)
            self.resetButton.config(state=NORMAL)
            self.legendButton.config(state=NORMAL)

    def onOpenReference(self):
        #displays .txt files in browser window
        #only reads wavelength domain data files
        ftypes = [('txt files', '*.txt'), ('csv files', '*.csv'),
                  ('ASCII files', '*.asc')]
        dlg = tkFileDialog.Open(self, filetypes=ftypes)
        fl = dlg.show()
        self.spec_name_reference.append(fl.rsplit('/', 1)[1][0:-4])
        self.linestyle_format_reference.append('g-')

        if fl != '':
            if fl[-3:] == 'txt':
                data = self.readFile(fl)
                #self.refl_reference=data[1]
                self.refl_reference.append(data[1])
                self.wavelength_reference.append(data[0])

            elif fl[-3:] == 'csv':
                data = self.readFile(fl)
                #self.refl_reference=data[1]
                self.refl_reference.append(data[1])
                self.wavelength_reference.append(data[0])

            elif fl[-3:] == 'asc':
                data = self.readFile(fl)
                #ignore leading negative values
                index_pos = bisect.bisect(data[1], 0)
                self.refl_reference.append(data[1][index_pos:])
                self.wavelength_reference.append(data[0][index_pos:])

        self.display_spectrum_reference.append(IntVar())
        self.display_spectrum_reference[len(self.spec_name_reference) -
                                        1].set(1)
        if self.wavelength_wavenumber_flag == 0:
            self.wavelength_domain()
        elif self.wavelength_wavenumber_flag == 1:
            self.wavenumber_domain()

    #function for file input
    def readFile(self, filename):
        file = open(filename, 'r')
        if filename[-3:] == 'asc':
            #there is some extra formatting on the first several lines
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()
            header = file.readline()

        header = file.readline()
        #read each row in the file
        #list for temporary wavelength data
        wavelength = []
        #list for temporary reflectance data
        refl = []
        for line in file:
            #check file format:
            if ',' in line:
                #read each row - store data in columns
                wavelength = line.split(',')
                wavelength.append(float(temp[0]))
                refl.append(float(temp[1].rstrip('/n')))
            elif '\t' in line:
                temp = line.split('\t')
                wavelength.append(float(temp[0]))
                refl.append(float(temp[1].rstrip('/n')))
            elif '      ' in line:
                temp = line.split('      ')
                wavelength.append(float(temp[1]))
                refl.append(float(temp[2]))
            elif '     ' in line:
                temp = line.split('     ')
                wavelength.append(float(temp[0]))
                refl.append(float(temp[1].rstrip('/n')))
            elif ' ' in line:
                temp = line.split(' ')
                wavelength.append(float(temp[0]))
                refl.append(float(temp[1].rstrip('/n')))

        data = [wavelength, refl]
        return data

    #export data to txt file
    def onExport(self):
        #save header info (date/time, ask user for instrument)?
        #ask for save file name
        savefile = tkFileDialog.asksaveasfile(mode='wb',
                                              defaultextension=".txt")
        # asksaveasfile return `None` if dialog closed with "cancel".
        if savefile is None:
            return
        #export wavelength or wavenumber domain data depending on flag (what is plotted)
        if self.wavelength_wavenumber_flag == 0:
            x = self.wavelength
        else:
            x = self.wavenumber
        y = self.refl

        for i in range(len(x)):
            savefile.write(str(x[i]))
            savefile.write(' ')
            savefile.write(str(y[i]))
            savefile.write('\r\n')
        savefile.close()

    #convert to wavelength domain
    #disabled until spectrum is plotted
    def wavelength_domain(self):
        self.wavelength_wavenumber_flag = 0
        #self.generate_figure([self.wavelength,self.refl], [self.label_wavelength, self.label_refl], 'wavelength ($\mu$m)', [self.wavelength_reference, self.refl_reference])
        #only display checked spectra
        if self.display_spectrum.get() == 1:
            wavelength_temp = self.wavelength
            refl_temp = self.refl
            self.linestyle_format_legend = self.linestyle_format
            self.spec_name_legend = self.spec_name
        elif self.display_spectrum.get() == 0:
            wavelength_temp = []
            refl_temp = []
            self.linestyle_format_legend = ['']
            self.spec_name_legend = ''
        wavelength_ref_temp = []
        refl_ref_temp = []
        self.spec_name_reference_legend = []
        self.linestyle_format_reference_legend = []
        for index, i in enumerate(self.wavelength_reference):
            if self.display_spectrum_reference[index].get() == 1:
                wavelength_ref_temp.append(self.wavelength_reference[index])
                refl_ref_temp.append(self.refl_reference[index])
                self.spec_name_reference_legend.append(
                    self.spec_name_reference[index])
                self.linestyle_format_reference_legend.append(
                    self.linestyle_format_reference[index])

        self.generate_figure([wavelength_temp, refl_temp],
                             [self.label_wavelength, self.label_refl],
                             'wavelength ($\mu$m)',
                             [wavelength_ref_temp, refl_ref_temp])

    #convert to wavenumber domain
    #disabled until spectrum is plotted
    def wavenumber_domain(self):
        self.wavelength_wavenumber_flag = 1
        self.label_wavenumber = [10000 / x for x in self.label_wavelength]
        #convert wavelength reference spectra to wavenumber
        self.wavenumber_reference = []
        for i in self.wavelength_reference:
            temp = [10000 / x for x in i]
            self.wavenumber_reference.append(temp)
        self.wavenumber = [10000 / x for x in self.wavelength]
        #self.generate_figure([self.wavenumber,self.refl], [self.label_wavenumber, self.label_refl], 'wavenumber (cm$^{-1}$)', [self.wavenumber_reference ,self.refl_reference])
        if self.display_spectrum.get() == 1:
            wavenumber_temp = self.wavenumber
            refl_temp = self.refl
            self.linestyle_format_legend = self.linestyle_format
            self.spec_name_legend = self.spec_name
        elif self.display_spectrum.get() == 0:
            wavenumber_temp = []
            refl_temp = []
            self.linestyle_format_legend = ['']
            self.spec_name_legend = ''
        wavenumber_ref_temp = []
        refl_ref_temp = []
        self.spec_name_reference_legend = []
        self.linestyle_format_reference_legend = []
        for index, i in enumerate(self.wavelength_reference):
            if self.display_spectrum_reference[index].get() == 1:
                wavenumber_ref_temp.append(self.wavenumber_reference[index])
                refl_ref_temp.append(self.refl_reference[index])
                self.spec_name_reference_legend.append(
                    self.spec_name_reference[index])
                self.linestyle_format_reference_legend.append(
                    self.linestyle_format_reference[index])

        self.generate_figure([wavenumber_temp, refl_temp],
                             [self.label_wavenumber, self.label_refl],
                             'wavenumber (cm$^{-1}$)',
                             [wavenumber_ref_temp, refl_ref_temp])

    #smooth data
    #disabled until spectrum is plotted
    def smooth_data(self):
        #purpose of smoothing function: to display smoothed plot
        self.SmoothDialog(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        if self.window != 0:
            smoothed_signal = scipy.signal.savgol_filter(
                self.refl, self.window, self.poly)
            #convert from array to list
            self.refl = smoothed_signal.tolist()

        if self.spec_name_reference != []:
            for index, name in enumerate(self.spec_name_reference):
                if self.window_reference[index] != 0:
                    smoothed_signal = scipy.signal.savgol_filter(
                        self.refl_reference[index],
                        self.window_reference[index],
                        self.poly_reference[index])
                    self.refl_reference[index] = smoothed_signal.tolist()

        if self.wavelength_wavenumber_flag == 1:
            self.wavenumber_domain()
        else:
            self.wavelength_domain()

    #called when Smooth button is pressed
    #asks user for smooth input data
    def SmoothDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        Label(top, text="PASA Spectrum:").grid(row=0,
                                               column=0,
                                               sticky=W,
                                               padx=5,
                                               pady=5)

        #window length for smoothing function
        #must be greater than poly value, positive, odd (51)
        Label(top, text=self.spec_name).grid(row=1,
                                             column=0,
                                             sticky=W,
                                             padx=5,
                                             pady=5)

        Label(top, text="Window Length:").grid(row=1,
                                               column=1,
                                               sticky=W,
                                               padx=5,
                                               pady=5)
        self.w = Entry(top)
        self.w.insert(0, '51')
        self.w.grid(row=1, column=2, padx=5, pady=5)

        #polynomial order
        #must be less than window length (3)
        Label(top, text="Polynomial Order:").grid(row=1,
                                                  column=3,
                                                  sticky=W,
                                                  padx=5,
                                                  pady=5)
        self.p = Entry(top)
        self.p.insert(0, '3')
        self.p.grid(row=1, column=4, padx=5, pady=5)

        index = -2
        if self.spec_name_reference != []:
            Label(top, text="Reference Spectrum:").grid(row=2,
                                                        column=0,
                                                        sticky=W,
                                                        padx=5,
                                                        pady=5)
            for index, name in enumerate(self.spec_name_reference):
                if index == 0:
                    self.rw = [' '] * len(self.spec_name_reference)
                    self.rp = [' '] * len(self.spec_name_reference)
                Label(top, text=name).grid(row=3 + index,
                                           column=0,
                                           sticky=W,
                                           padx=5,
                                           pady=5)
                Label(top, text="Window Length:").grid(row=3 + index,
                                                       column=1,
                                                       sticky=W,
                                                       padx=5,
                                                       pady=5)
                self.rw[index] = Entry(top)
                self.rw[index].insert(0, '0')
                self.rw[index].grid(row=3 + index, column=2, padx=5, pady=5)

                Label(top, text="Polynomial Order:").grid(row=3 + index,
                                                          column=3,
                                                          sticky=W,
                                                          padx=5,
                                                          pady=5)
                self.rp[index] = Entry(top)
                self.rp[index].insert(0, '0')
                self.rp[index].grid(row=3 + index, column=4, padx=5, pady=5)

        #calls DialogSmoothOK to set these values
        b = Button(top, text="OK", command=self.DialogSmoothOK)
        b.grid(row=4 + index, column=4, padx=5, pady=5)

    #called from smooth dialog box within smooth routine
    def DialogSmoothOK(self):
        #sets user-defined window length
        self.window = float(self.w.get())
        #sets user-defined polynomail order
        self.poly = float(self.p.get())
        if self.spec_name_reference != []:
            self.window_reference = []
            self.poly_reference = []
            for index, wave in enumerate(self.wavelength_reference):
                #self.spec_name_reference.append(str(self.rn.get()))
                self.window_reference.append(float(self.rw[index].get()))
                self.poly_reference.append(float(self.rp[index].get()))
        self.top.destroy()

    #offset data
    #disabled until spectrum is plotted
    def offset_data(self):
        self.OffsetDialog(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        #scale/offset spectrum
        self.refl = [(x * self.scale) + self.offset for x in self.refl]
        if self.spec_name_reference != []:
            temp_refl = []
            for index, name in enumerate(self.spec_name_reference):
                temp_refl.append([(x * self.scale_reference[index]) +
                                  self.offset_reference[index]
                                  for x in self.refl_reference[index]])
            self.refl_reference = temp_refl
        if self.wavelength_wavenumber_flag == 1:
            self.wavenumber_domain()
        else:
            self.wavelength_domain()

    #called when Offset button is pressed
    #asks user for smooth input data
    def OffsetDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        Label(top, text="PASA Spectrum:").grid(row=1,
                                               column=0,
                                               sticky=W,
                                               padx=5,
                                               pady=5)
        Label(top, text=self.spec_name).grid(row=2,
                                             column=0,
                                             sticky=W,
                                             padx=5,
                                             pady=5)
        Label(top, text="Offset:").grid(row=2,
                                        column=1,
                                        sticky=W,
                                        padx=5,
                                        pady=5)
        self.po = Entry(top)
        self.po.insert(0, '0')
        self.po.grid(row=2, column=2, padx=5, pady=5)

        Label(top, text="Scale:").grid(row=2,
                                       column=3,
                                       sticky=W,
                                       padx=5,
                                       pady=5)
        self.ps = Entry(top)
        self.ps.insert(0, '1.0')
        self.ps.grid(row=2, column=4, padx=5, pady=5)

        index = -2
        if self.spec_name_reference != []:
            Label(top, text="Reference Spectrum:").grid(row=3,
                                                        column=0,
                                                        sticky=W,
                                                        padx=5,
                                                        pady=5)
            for index, name in enumerate(self.spec_name_reference):
                if index == 0:
                    self.ro = [' '] * len(self.spec_name_reference)
                    self.rs = [' '] * len(self.spec_name_reference)
                Label(top, text=name).grid(row=4 + index,
                                           column=0,
                                           sticky=W,
                                           padx=5,
                                           pady=5)
                Label(top, text="Offset:").grid(row=4 + index,
                                                column=1,
                                                sticky=W,
                                                padx=5,
                                                pady=5)
                self.ro[index] = Entry(top)
                self.ro[index].insert(0, '0')
                self.ro[index].grid(row=4 + index, column=2, padx=5, pady=5)

                Label(top, text="Scale:").grid(row=4 + index,
                                               column=3,
                                               sticky=W,
                                               padx=5,
                                               pady=5)
                self.rs[index] = Entry(top)
                self.rs[index].insert(0, '1.0')
                self.rs[index].grid(row=4 + index, column=4, padx=5, pady=5)

        #calls DialogOffsetOK to set these values
        b = Button(top, text="OK", command=self.DialogOffsetOK)
        b.grid(row=5 + index, column=4, padx=5, pady=5)

    #called from offset dialog box within smooth routine
    def DialogOffsetOK(self):
        self.offset = float(self.po.get())
        self.scale = float(self.ps.get())
        if self.spec_name_reference != []:
            self.offset_reference = []
            self.scale_reference = []
            for index, wave in enumerate(self.wavelength_reference):
                #self.spec_name_reference.append(str(self.rn.get()))
                self.offset_reference.append(float(self.ro[index].get()))
                self.scale_reference.append(float(self.rs[index].get()))
        self.top.destroy()

    #format labels
    def format_labels(self):
        self.FormatLabelDialog(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        self.label_size = float(self.label_size)
        #self.label_format = "%."+self.digits_after+"f"
        if self.wavelength_wavenumber_flag == 0:
            self.wavelength_domain()
        elif self.wavelength_wavenumber_flag == 1:
            self.wavelength_domain()

    def FormatLabelDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        #font size
        Label(top, text="Font Size:").grid(row=0,
                                           column=0,
                                           sticky=W,
                                           padx=5,
                                           pady=5)
        self.fs = Entry(top)
        self.fs.insert(0, '10')
        self.fs.grid(row=0, column=1, padx=5, pady=5)

        #calls DialogLabelOK to set these values
        b = Button(top, text="OK", command=self.DialogLabelOK)
        b.grid(row=3, column=1, padx=5, pady=5)

    #called from label dialog box within label format routine
    def DialogLabelOK(self):
        #sets user-defined font size
        self.label_size = float(self.fs.get())
        self.top.destroy()

    #function to label features on figure in order to save figure as an image file with labels
    #disabled until spectrum is plotted
    def label_feature(self):
        #ask for peak (on_click_label)
        self.cid = self.canvas.mpl_connect('button_press_event',
                                           self.on_click_label)

    #called when click is made to label peak
    def on_click_label(self, event):
        temp_len = len(self.label_refl)
        #if wavelength flag is set
        if self.wavelength_wavenumber_flag == 0:
            #temp_len=len(self.label_wavenumber)
            #when the click is made within the plotting window
            if event.inaxes is not None:
                self.label_wavelength.append(event.xdata)
                self.label_refl.append(event.ydata)
                #self.LabelDialog(self.parent)
                #self.wavelength_domain()
            #if click is outside plotting window
            else:
                print 'Clicked ouside axes bounds but inside plot window'
        #if the wavenumber flag is set
        elif self.wavelength_wavenumber_flag == 1:
            #temp_len=len(self.label_wavelength)
            #when the click is made within the plotting window
            if event.inaxes is not None:
                self.label_wavenumber.append(event.xdata)
                self.label_refl.append(event.ydata)
                #self.LabelDialog(self.parent)
                #self.wavenumber_domain()
            #if click is outside plotting window
            else:
                print 'Clicked ouside axes bounds but inside plot window'
        #self.peak_intensity=event.ydata
        #plot label
        #disconnect from click event when a new peak label value is set
        if temp_len < len(self.label_refl):
            self.LabelDialog(self.parent)
            self.canvas.mpl_disconnect(self.cid)

    #asks user for featue label associated with selection
    def LabelDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        Label(top, text="Spectral Feature:").pack()
        self.v = Entry(top)
        self.v.insert(0, 'H$_2$O')
        self.v.pack(padx=5)
        #calls DialogOK to set mass value to input
        b = Button(top, text="OK", command=self.DialogOK)
        b.pack(pady=5)

    #called from label dialog box within feature label routine
    def DialogOK(self):
        #sets user-defined mass calibration value to mass cal list
        self.label_value.append(self.v.get())
        #replots with labels
        if self.wavelength_wavenumber_flag == 0:
            self.wavelength_domain()
        elif self.wavelength_wavenumber_flag == 1:
            self.wavelength_domain()
        #closes dialog box
        self.top.destroy()

    #remove labels when button is selected
    #disabled until spectrum is plotted
    def delete_labels(self):
        #deletes peak label arrays
        self.label_wavenumber = []
        self.label_wavelength = []
        self.label_refl = []
        #if wavelength/wavenumber flag is set
        if self.wavelength_wavenumber_flag == 0:
            self.wavelength_domain()
        elif self.wavelength_wavenumber_flag == 1:
            self.wavenumber_domain()

    #called when define axes button is pressed
    #asks user to define axes range
    #disabled until spectrum is plotted
    def define_axes(self):
        self.DefineAxes(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        self.define_axis_flag = 1
        if self.wavelength_wavenumber_flag == 1:
            self.wavenumber_domain()
        else:
            self.wavelength_domain()

    def DefineAxes(self, parent):
        top = self.top = Toplevel(self.parent)

        #x axis range
        Label(top, text="X Axis:").grid(row=0,
                                        column=0,
                                        sticky=W,
                                        padx=5,
                                        pady=5)
        self.x1 = Entry(top)
        if self.wavelength_wavenumber_flag == 0:
            self.x1.insert(0, 1.6)
        elif self.wavelength_wavenumber_flag == 1:
            self.x1.insert(0, 2780)
        self.x1.grid(row=0, column=1, padx=5, pady=5)
        self.x2 = Entry(top)
        if self.wavelength_wavenumber_flag == 0:
            self.x2.insert(0, 3.6)
        elif self.wavelength_wavenumber_flag == 1:
            self.x2.insert(0, 6250)
        self.x2.grid(row=0, column=2, padx=5, pady=5)

        #y axis range
        Label(top, text="Y Axis:").grid(row=1,
                                        column=0,
                                        sticky=W,
                                        padx=5,
                                        pady=5)
        self.y1 = Entry(top)
        self.y1.insert(0, self.ylim[0])
        self.y1.grid(row=1, column=1, padx=5, pady=5)
        self.y2 = Entry(top)
        self.y2.insert(0, self.ylim[1])
        self.y2.grid(row=1, column=2, padx=5, pady=5)
        #calls DialogSmoothOK to set these values
        b = Button(top, text="OK", command=self.DialogAxesOK)
        b.grid(row=2, column=1, padx=5, pady=5)

    #called from axes define dialog box
    def DialogAxesOK(self):
        #sets user-defined x axis values
        x_temp1 = float(self.x1.get())
        x_temp2 = float(self.x2.get())
        self.xlim = [x_temp1, x_temp2]
        #sets user-defined y axis values
        y_temp1 = float(self.y1.get())
        y_temp2 = float(self.y2.get())
        self.ylim = [y_temp1, y_temp2]
        self.top.destroy()

    #called when legend button is pressed
    #asks user to define linestyle, legend name, legend font size
    #disabled until spectrum is plotted
    def define_legend(self):
        self.DefineLegend(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        if self.wavelength_wavenumber_flag == 1:
            self.wavenumber_domain()
        else:
            self.wavelength_domain()

    def DefineLegend(self, parent):
        top = self.top = Toplevel(self.parent)
        #PASA spectrum
        Label(top, text="PASA Spectrum:").grid(row=1,
                                               column=0,
                                               sticky=W,
                                               padx=5,
                                               pady=5)
        Label(top, text="Name:").grid(row=2,
                                      column=0,
                                      sticky=W,
                                      padx=5,
                                      pady=5)
        self.pn = Entry(top)
        self.pn.insert(0, self.spec_name)
        self.pn.grid(row=2, column=1, padx=5, pady=5)

        Label(top, text="Linestyle:").grid(row=2,
                                           column=2,
                                           sticky=W,
                                           padx=5,
                                           pady=5)
        self.pl = Entry(top)
        self.pl.insert(0, self.linestyle_format[0])
        self.pl.grid(row=2, column=3, padx=5, pady=5)
        Checkbutton(top,
                    variable=self.display_spectrum,
                    text="Display",
                    onvalue=1,
                    offvalue=0).grid(row=2, column=4, sticky=W, padx=5, pady=5)

        index = -2
        if self.spec_name_reference != []:
            Label(top, text="Reference Spectrum:").grid(row=3,
                                                        column=0,
                                                        sticky=W,
                                                        padx=5,
                                                        pady=5)
            for index, name in enumerate(self.spec_name_reference):
                if index == 0:
                    self.rn = [' '] * len(self.spec_name_reference)
                    self.rl = [' '] * len(self.spec_name_reference)

                Label(top, text="Name:").grid(row=4 + index,
                                              column=0,
                                              sticky=W,
                                              padx=5,
                                              pady=5)
                self.rn[index] = Entry(top)
                self.rn[index].insert(0, name)
                self.rn[index].grid(row=4 + index, column=1, padx=5, pady=5)

                Label(top, text="Linestyle:").grid(row=4 + index,
                                                   column=2,
                                                   sticky=W,
                                                   padx=5,
                                                   pady=5)
                self.rl[index] = Entry(top)
                self.rl[index].insert(0,
                                      self.linestyle_format_reference[index])
                self.rl[index].grid(row=4 + index, column=3, padx=5, pady=5)
                Checkbutton(top,
                            variable=self.display_spectrum_reference[index],
                            text="Display",
                            onvalue=1,
                            offvalue=0).grid(row=4 + index,
                                             column=4,
                                             sticky=W,
                                             padx=5,
                                             pady=5)

        #asks for legend font size
        Label(top, text="Legend:").grid(row=5 + index,
                                        column=0,
                                        sticky=W,
                                        padx=5,
                                        pady=5)
        Label(top, text="Font Size:").grid(row=6 + index,
                                           column=0,
                                           sticky=W,
                                           padx=5,
                                           pady=5)
        self.lf = Entry(top)
        self.lf.insert(0, self.legend_fontsize)
        self.lf.grid(row=6 + index, column=1, padx=5, pady=5)

        #calls DialogLegendOK to set these values
        b = Button(top, text="OK", command=self.DialogLegendOK)
        b.grid(row=7 + index, column=4, padx=5, pady=5)

    #called from linestyle define dialog box
    def DialogLegendOK(self):
        #sets user-defined x axis values
        self.spec_name = str(self.pn.get())
        self.linestyle_format = [str(self.pl.get())]
        if self.spec_name_reference != []:
            self.spec_name_reference = []
            self.linestyle_format_reference = []
            for index, wave in enumerate(self.wavelength_reference):
                #self.spec_name_reference.append(str(self.rn.get()))
                self.spec_name_reference.append(str(self.rn[index].get()))
                self.linestyle_format_reference.append(
                    str(self.rl[index].get()))
        self.legend_fontsize = (self.lf.get())
        self.top.destroy()

    #reset plotting window
    #disabled until spectrum is plotted
    def reset_plots(self):
        #generate figure (no data at first)
        #resets all necessary variables
        self.wavelength_reference = []
        self.wavenumber_reference = []
        self.refl_reference = []
        self.wavelength_wavenumber_flag = 0
        self.label_wavelength = []
        self.label_wavenumber = []
        self.label_refl = []
        self.label_value = []
        self.define_axis_flag = 0
        self.xlim = [1.6, 3.6]
        self.ylim = [0, 1]
        self.linestyle_format = ['k-']
        self.reset_figure([0, 1], [[], []], ' ')
        self.spec_name_reference = []
        self.spec_name = []
        self.rn = []
        self.rl = []
        self.ro = []
        self.rs = []
        self.rw = []
        self.rp = []

        #prohibits reference spectrum to be added
        self.openMenu.entryconfig("Open Reference Spectrum", state=DISABLED)
        #prohibits labels to be generated
        self.labelButton.config(state=DISABLED)
        self.deletelabelButton.config(state=DISABLED)
        #prohibits for modification of data
        self.smoothButton.config(state=DISABLED)
        self.offsetButton.config(state=DISABLED)
        #prohibits for domain conversion
        self.wavelengthButton.config(state=DISABLED)
        self.wavenumberButton.config(state=DISABLED)
        #prohibits plot to be configured
        self.axesButton.config(state=DISABLED)
        self.legendButton.config(state=DISABLED)
        self.resetButton.config(state=DISABLED)

    #need to destroy parent before quitting, otherwise python crashes on Windows
    def quit_destroy(self):
        self.parent.destroy()
        self.parent.quit()
class Unsplit_Proliferation_Gating_GUI(tk.Frame):
    def __init__(self,master):
        self.root = master.root
        tk.Frame.__init__(self, master)
        
        experimentNameWindow = tk.Frame(self)
        experimentNameWindow.pack(side=tk.TOP,padx=10,pady=10)
        experimentNameLabel = tk.Label(experimentNameWindow,text=folderName+':').pack()
        
        plotFrame = tk.Frame(self)
        plotFrame.pack()
        row = pickle.load(open('inputFiles/rowValIterationRange.pkl','rb'))
        groupedGateList = pickle.load(open('inputFiles/groupedGateList.pkl','rb'))
        if groupVariable == 'Condition-Time':
            currentDf = logicleDataStacked.to_frame('GFI')
            rawDf = rawDataStacked.to_frame('GFI')
        else:
            currentLevelValues = logicleDataUnstacked.iloc[row,:].name
            currentDf = logicleDataStacked.xs(currentLevelValues,level=levelNames).to_frame('GFI')
            rawDf = rawDataStacked.xs(currentLevelValues,level=levelNames).to_frame('GFI')
        plottingDf = currentDf.reset_index()
        if groupVariable == 'Condition-Time' or groupVariable == 'Condition':
            nonEventLevelNames = currentDf.index.names[:-1]
            groupingColumn = []
            for conditionGroupbyTuple in currentDf.groupby(level=nonEventLevelNames,sort=False):
                conditionGroupbyTupleNew = [str(i) for i in conditionGroupbyTuple[0]]
                conditionName = '-'.join(conditionGroupbyTupleNew)
                for event in range(conditionGroupbyTuple[1].shape[0]):
                    groupingColumn.append(conditionName)
            plottingDf[groupVariable] = groupingColumn        
        #Plot facetgrid of histograms of ctv values of all times for current condition
        g = sns.FacetGrid(plottingDf,legend_out=True,hue=groupVariable,height=6,palette=sns.color_palette("Purples", len(pd.unique(plottingDf[groupVariable]))))
        #g.map(sns.distplot,'GFI',kde=False,bins=256)
        g.map(sns.kdeplot,'GFI',bw=15)
        plt.subplots_adjust(top=0.95)
        xtickValues,xtickLabels = returnTicks([-1000,100,1000,10000,100000])
        axis = g.fig.get_axes()[0]
        axis.set_xticks(xtickValues)
        axis.set_xticklabels(xtickLabels)
        
        startingGateLogicle = 725
        startingGateRaw = rawDf.values[find_nearest(currentDf,startingGateLogicle)[1]][0]
        logicleGates = returnGates(currentDf,rawDf,startingGateRaw,numGens)
        maxY = list(plt.gca().get_yticks())[-1]
        X = startingGateLogicle
        Ymin = -1
        Ymax = maxY
        gates = logicleGates[1:]
        numGates = len(logicleGates)-1
        self.canvas = FigureCanvasTkAgg(g.fig,master=plotFrame)
        self.ax = plt.gca() 
        self.canvas.draw()
        self.canvas.get_tk_widget().pack()
        self.X = X
        self.gates= gates
        self.gateVals = gates
        gateLengths = [y-x for x, y in zip(gates[:-1], gates[1:])][1:]
        self.gateLengths = gateLengths 
        self.numGates = numGates
        x = [X, X]
        y = [Ymin, Ymax]
        
        self.line = linesmpl.Line2D(x, y, picker=5,linestyle=':',color='r')
        self.ax.add_line(self.line)
        self.childlines = []
        for gate in range(self.numGates):
            newX = self.gates[gate]
            childline = linesmpl.Line2D([newX,newX], y,linestyle=':',color='k',picker=5)
            self.childlines.append(childline)
        for childline in self.childlines:
            self.ax.add_line(childline)
        self.canvas.draw()
        self.sid = self.canvas.mpl_connect('pick_event', self.clickOnParentLine)
        childsids = []
        for childline,i in zip(self.childlines,range(self.numGates)):
            childsids.append(self.canvas.mpl_connect('pick_event', self.clickOnChildLines))
        self.childsids = childsids
        
        #Add title
        if groupVariable == 'Condition-Time':
            plt.title(titleVariable)
        else:
            if not isinstance(currentLevelValues, (tuple,)):
                currentLevelValues = [str(currentLevelValues)]
            plt.title('-'.join(currentLevelValues)+' ('+titleVariable+' '+str(row+1)+'/'+str(logicleDataUnstacked.shape[0])+')')
        
        def collectInputs():
            for names in range(len(pd.unique(plottingDf[groupVariable]))):
                groupedGateList.append(self.getAllX())
            with open('inputFiles/groupedGateList.pkl','wb') as f:
                pickle.dump(groupedGateList,f)
            row = pickle.load(open('inputFiles/rowValIterationRange.pkl','rb'))
            row+=1
            with open('inputFiles/rowValIterationRange.pkl','wb') as f:
                pickle.dump(row,f)
            if row != pickle.load(open('inputFiles/iterationRange.pkl','rb')):
                master.switch_frame(Unsplit_Proliferation_Gating_GUI)
            else:
                i = 0
                row = 0
                singleCellProliferationDf = pd.DataFrame(np.zeros(logicleDataStacked.shape),logicleDataStacked.index,columns=['Generation'])
                for outerVariable in outerVariableValues:
                    for innerVariable in innerVariableValues:
                        sampleGenerationGates = groupedGateList[i]
                        #sampleGenerationGates = groupedGate.getAllX()
                        if groupVariable == 'Condition':
                            indexingTuple = tuple(list(innerVariable)+[outerVariable,slice(None)])
                        else:
                            indexingTuple = tuple(list(outerVariable)+[innerVariable,slice(None)])
                        ctvValues = logicleDataStacked.loc[indexingTuple]
                        generationValues = np.zeros(ctvValues.shape)
                        for sampleEvent,row in zip(ctvValues,range(ctvValues.shape[0])):
                            for generation in range(len(sampleGenerationGates)-1):
                                upperGate = sampleGenerationGates[generation]
                                lowerGate = sampleGenerationGates[generation+1]
                                if(sampleEvent > lowerGate and sampleEvent <= upperGate):
                                    generationValues[row] = generation
                        singleCellProliferationDf.loc[indexingTuple,:] = generationValues

                print(singleCellProliferationDf)
                with open('semiProcessedData/singleCellDataFrame-proliferation-'+folderName+'.pkl', 'wb') as f:
                    pickle.dump(singleCellProliferationDf,f)
                master.switch_frame(secondaryhomepage,folderName,expNum,ex_data)

        buttonWindow = tk.Frame(self)
        buttonWindow.pack(side=tk.TOP,pady=10)

        tk.Button(buttonWindow, text="OK",command=lambda: collectInputs()).grid(row=5,column=0)
        tk.Button(buttonWindow, text="Quit",command=quit).grid(row=5,column=2)

    def clickOnParentLine(self, event):
        if event.artist == self.line:
            print("line selected ", event.artist)
            self.follower = self.canvas.mpl_connect("motion_notify_event", self.followParentMouse)
            self.releaser = self.canvas.mpl_connect("button_press_event", self.releaseParentOnClick)
    
    def clickOnChildLines(self, event):
        if event.artist in self.childlines:
            print("line selected ", event.artist)
            self.currentArtist = event.artist
            self.follower = self.canvas.mpl_connect("motion_notify_event", self.followChildMouse)
            self.releaser = self.canvas.mpl_connect("button_press_event", self.releaseChildOnClick)
    
    def followChildMouse(self, event):
        for childline,gate in zip(self.childlines,range(self.numGates)):
            if self.childlines[gate] == self.currentArtist:
                self.childlines[gate].set_xdata([event.xdata, event.xdata])
        self.canvas.draw()
        #self.c.draw_idle()
    
    def releaseChildOnClick(self, event):
        newGates = []
        for childline in self.childlines:
            newGates.append(childline.get_xdata()[0])
        self.gates = newGates
        self.canvas.mpl_disconnect(self.releaser)
        self.canvas.mpl_disconnect(self.follower)

    def followParentMouse(self, event):
        self.line.set_xdata([event.xdata, event.xdata])
        newGates = []
        for childline,gate in zip(self.childlines,range(self.numGates)):
            newX = (event.xdata-self.X)+self.gates[gate]
            childline.set_xdata([newX,newX])
            newGates.append(newX)
        self.gateVals = newGates
        self.canvas.draw()
    
    def releaseParentOnClick(self, event):
        self.X = self.line.get_xdata()[0]
        newGates = []
        for childline in self.childlines:
            newGates.append(childline.get_xdata()[0])
        self.gates = newGates
        self.canvas.mpl_disconnect(self.releaser)
        self.canvas.mpl_disconnect(self.follower)

    def getParentX(self):
        return self.X
    
    def getChildX(self):
        childGates = []
        for childline in self.childlines:
            childGates.append(childline.get_xdata()[0])
        return childGates

    def getAllX(self):
        return [self.getParentX()]+self.getChildX()
Example #7
0
class DrawLineLayout:
    def __init__(self, root_frame, figure):
        print('hi from DrawLineLayout')

        self.root_frame = root_frame

        self.root_frame.columnconfigure(0, weight=1)
        self.root_frame.rowconfigure(0, weight=1)

        self.fig = figure

        self.canvas = FigureCanvasTkAgg(self.fig, master=self.root_frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().grid(column=0,
                                         row=0,
                                         sticky=('N', 'S', 'E', 'W'))

        self.toolbar_frame = ttk.Frame(self.root_frame)
        self.toolbar_frame.grid(column=1, row=0, sticky=('N', 'E', 'S', 'W'))

        self.toolbar_frame.columnconfigure(0, weight=1)
        self.toolbar_frame.rowconfigure(5, weight=1)

        self.toolbar_label = ttk.Label(self.toolbar_frame, text='Toolbar')
        self.toolbar_label.grid(column=0, row=0, sticky=('W', 'E'))

        self.upsample_btn = ttk.Button(self.toolbar_frame, text='Upsample')
        self.upsample_btn.grid(column=0, row=1, sticky=('W', 'E'))
        self.upsample_btn.state(['disabled'])

        self.done_btn = ttk.Button(self.toolbar_frame, text='Done')
        self.done_btn.grid(column=0, row=2, sticky=('W', 'E', 'S'))
        self.done_btn.state(['disabled'])

        self.num_points_head = ttk.Label(self.toolbar_frame,
                                         text='Number of Points:')
        self.num_points_head.grid(column=0, row=3, sticky=('W', 'E'))

        self.num_points_label = ttk.Label(self.toolbar_frame)
        self.num_points_label.grid(column=0, row=4, sticky=('W', 'E', 'S'))

        self.num_points_var = tk.StringVar()
        self.num_points_var.set(0)

        self.num_points_label['textvariable'] = self.num_points_var

        self.discard_btn = ttk.Button(self.toolbar_frame, text='Discard')
        self.discard_btn.grid(column=0, row=5, sticky=('W', 'E', 'S'))

    def enable_upsample_btn(self):
        self.upsample_btn.state(['!disabled'])

    def enable_done_btn(self):
        self.done_btn.state(['!disabled'])

    def disable_upsample_btn(self):
        self.upsample_btn.state(['disabled'])

    def disable_done_btn(self):
        self.done_btn.state(['disabled'])

    def set_num_points(self, num_points):
        self.num_points_var.set(num_points)

    def redraw_figure(self):
        self.canvas.draw()

    def mpl_connect(self, event_type, callback):
        return self.canvas.mpl_connect(event_type, callback)

    def mpl_disconnect(self, cid):
        self.canvas.mpl_disconnect(cid)

    def set_upsample_callback(self, callback):
        self.upsample_btn['command'] = callback

    def set_done_callback(self, callback):
        self.done_btn['command'] = callback

    def set_discard_callback(self, callback):
        self.discard_btn['command'] = callback

    def clean_up(self):
        print('DrawLineLayout cleaning up')

        self.discard_btn.grid_forget()
        self.num_points_label.grid_forget()
        self.num_points_head.grid_forget()
        self.done_btn.grid_forget()
        self.upsample_btn.grid_forget()
        self.toolbar_label.grid_forget()
        self.toolbar_frame.grid_forget()
        self.canvas.get_tk_widget().grid_forget()
class PlotWindow(tk.Toplevel):

    def __init__(self, plot_type='', master=None, parameters=dict(), data=list(), figure_number=None, application=None, *args, **kwargs):

        # Class parameters
        self.master = master
        self.parameters = parameters
        self.application = application
        self.data = data
        self.pick_data_points_flag = False
        self.normalization_flag = False
        self.normalization_single_flag = False
        self.normalization_value = 1
        self.new_normalization_value = 1
        self.base_value = 0
        self.new_base_value = 0
        self.right_profile = None
        self.bottom_profile = None
        self.plot_type = plot_type
        self.widgets = dict() # To be used by class descendants
        self.picker_tolerance = 5.0
        self.selected_artist = None
        self.profiler = Profiler()
        self.figure_number = figure_number

        # Init window
        tk.Toplevel.__init__(self, master=self.master)

        # Set window title
        if plot_type == 'Clipboard':
            self.title('Clipboard') 
        elif plot_type == 'MogonioCalibration':
            self.title('Mogonio Calibration Wizard')
        elif plot_type == 'Calibration':
            self.title('Calibration Fit Curve') 
        else:
            if figure_number is not None:
                self.title('Figure %.0f - %s - %s' % (figure_number, plot_type, (self.application.filename))) 

        self.protocol("WM_DELETE_WINDOW", self.action_close)
        self.fig = Figure()

        self.main_axes = self.fig.add_subplot(111)

        self.config_plot()
        self.add_default_widgets()

        # This functions loops every 10 seconds
        self.after(0, self.timer())

    def artist_label_prefix(self):
        return 'Fig. ' + str(self.figure_number)

    def find_closest_in_array(self, X, x0):
            # Find x position in array X
            x_pos = 0
            x_index = -1
            last_diff = np.abs(np.amax(X)-np.amin(X))
            for x in X:
                if abs(x-x0) < last_diff:
                    x_index = x_pos
                    last_diff = abs(x-x0) 
                x_pos += 1
            return x_index


    def onpick(self, event):

        xy = [ event.mouseevent.x, event.mouseevent.y ]
        xydata = [event.mouseevent.xdata, event.mouseevent.ydata]

        # Reset previous selected artist
        if self.selected_artist is not None:
            if xy == self.selected_artist['xy'] and xydata == self.selected_artist['xydata']:
                return # Make sure that only one artist is selected by a single mouseclick
            self.selected_artist['artist'].set_color(self.selected_artist['color'])  
            self.selected_artist['artist'].set_linewidth(self.selected_artist['width'])

        if self.selected_artist is not None and self.selected_artist['artist'] is event.artist:
            self.selected_artist = None # Clear selection if clicking twice on the same object
        else:
            self.select_artist(event.artist, xy, xydata)
            self.log('* Selected plot object: ' + event.artist.get_label())

        # Redraw changes
        self.fig.canvas.draw()

    def select_artist(self, artist, xy, xydata):
        # Store current selected artist
        self.selected_artist = {
            'artist': artist,
            'color': artist.get_color(),
            'width': artist.get_linewidth(),
            'xy': xy,
            'xydata': xydata
        }
        # Change some attributes to show the user that the artist is currently selected
        artist.set_color('purple')
        artist.set_linewidth(3)

    def add_profiles_and_colorbar(self):

        # Right axes sharing Y axis
        divider = make_axes_locatable(self.main_axes)
        self.right_axes = divider.append_axes("right", size=1, pad=0.2, sharey=self.main_axes)

        # Colorbar axes
        self.colorbar_axes = divider.append_axes("right", size="5%", pad=0.2)

        # Bottom axes sharing X axis 
        self.bottom_axes = divider.append_axes("bottom", size=1, pad=0.2, sharex=self.main_axes)

    def add_default_widgets(self):

        ##########################
        # Top frame
        ##########################

        # New container for buttons
        self.widgets['frame_widgets'] = ttk.Frame(self)

        # Normalization button
        self.widgets['btn_normalization'] = ttk.Button(self.widgets['frame_widgets'], text='Normalize y-axis')
        self.widgets['btn_normalization']["command"] = self.action_btn_normalization

        # Zoom all button
        self.widgets['btn_zoomall'] = ttk.Button(self.widgets['frame_widgets'], text='Zoom all')
        self.widgets['btn_zoomall']["command"] = self.action_btn_zoomall
        self.widgets['btn_zoomall'].pack(side=tk.LEFT, padx=10, pady=5)

        # Export button
        self.widgets['btn_export'] = ttk.Button(self.widgets['frame_widgets'], text='Export data')
        self.widgets['btn_export']["command"] = self.action_btn_export
        self.widgets['btn_export'].pack(side=tk.LEFT, padx=10, pady=5)

        # Quick normalization button
        self.widgets['btn_quick_normalization'] = ttk.Button(self.widgets['frame_widgets'], text='Auto normalization')
        self.widgets['btn_quick_normalization']["command"] = self.action_btn_quick_normalization
        self.widgets['btn_quick_normalization'].pack(side=tk.LEFT, padx=10, pady=5)

        # Sum plots checkbox
        #self.widgets['cb_auto_refresh'] = Checkbox(self.widgets['frame_widgets'], text='Auto refresh')
        #self.widgets['cb_auto_refresh'].pack(side=tk.LEFT, padx=10, pady=10)

        # Pack buttons frame
        self.widgets['frame_widgets'].grid(row=0, column=0)

        ##########################
        # Selection artist widgets
        ##########################

        # New container for buttons
        self.widgets['frame_artist_widgets'] = ttk.Frame(self)

        # Pack buttons frame
        self.widgets['frame_artist_widgets'].grid(row=1, column=0)

        # Copy to desktop plot
        self.widgets['btn_copy'] = ttk.Button(self.widgets['frame_artist_widgets'], text='Copy to clipboard')
        self.widgets['btn_copy']["command"] = self.action_btn_copy
        self.widgets['btn_copy'].pack(side=tk.LEFT, padx=10, pady=5)

        # Zoom line button
        self.widgets['btn_zoomsingle'] = ttk.Button(self.widgets['frame_artist_widgets'], text='Zoom curve')
        self.widgets['btn_zoomsingle']["command"] = self.action_btn_zoomsingle
        self.widgets['btn_zoomsingle'].pack(side=tk.LEFT, padx=10, pady=5)

        ##########################
        # Bottom frame
        ##########################

        self.widgets['bottom_frame'] = ttk.Frame(self)
        #self.widgets['btn_test'] = ttk.Button(self.widgets['bottom_frame'], text='Teste')
        #self.widgets['btn_test'].grid(row=0, column=0, sticky='nsew')
        self.widgets['log_listbox'] = ScrollableListbox(self.widgets['bottom_frame'], height=4)
        self.widgets['log_listbox'].grid(row=0, column=0, sticky='nsew')
        self.widgets['bottom_frame'].grid(row=3, column=0, sticky="nsew", pady=10, padx=10)

        # Elastic columns
        tk.Grid.columnconfigure(self.widgets['bottom_frame'], 0, weight=1)
        tk.Grid.columnconfigure(self, 0, weight=1)
        tk.Grid.rowconfigure(self, 2, weight=1)
        tk.Grid.rowconfigure(self, 0, weight=0)

    def log(self, text):
        self.widgets['log_listbox'].append(text)
        self.widgets['log_listbox'].see(tk.END)

    def default_config(self):
        self.main_axes.get_xaxis().get_major_formatter().set_useOffset(False)
        self.main_axes.get_yaxis().get_major_formatter().set_useOffset(False)
        self.fig.set_tight_layout(True)

    def action_btn_zoomsingle(self, *args, **kwargs):
        if self.selected_artist is not None:
            line = self.selected_artist['artist']
            min_x = min(line.get_xdata())
            max_x = max(line.get_xdata())
            min_y = min(line.get_ydata())
            max_y = max(line.get_ydata())
            self.main_axes.set_xlim([min_x, max_x])
            self.main_axes.set_ylim([min_y, max_y])
            # Redraw changes
            self.fig.canvas.draw()


    def action_btn_export(self, *args, **kwargs):
        file_path = fd.asksaveasfilename()
        if file_path:
            line_num = 0
            for line in self.main_axes.get_lines():
                line_num += 1
                path = file_path + '_' + self.plot_type + '_' + str(line_num) + '.txt'
                np.savetxt(path, np.column_stack([line.get_xdata(), line.get_ydata()]))

    def action_btn_quick_normalization(self, *args, **kwargs):
        for line in self.main_axes.get_lines():
            y = line.get_ydata()
            y = y-np.amin(y)
            y = np.divide(y, np.amax(y))
            line.set_ydata(y)
        self.action_btn_zoomall()

    def disable_picker(self, *args, **kwargs):
        for line in self.main_axes.get_lines():
            line.set_picker(None)

    def action_btn_copy(self, *args, **kwargs):
        if self.application is not None and self.selected_artist is not None:
            if self.application.clipboard_plot is None:
                self.application.clipboard_plot = ClipboardPlot(master = self.application.master, application = self.application)
            self.application.clipboard_plot.main_axes.plot(self.selected_artist['artist'].get_xdata(), self.selected_artist['artist'].get_ydata(), picker=self.picker_tolerance, label=self.selected_artist['artist'].get_label())
            self.application.clipboard_plot.fig.canvas.draw()

    def action_cb_transferred_click(self, *args, **kwargs):
        self.refresh_plot()

    # This functions loops every 10 seconds
    def timer(self):
        #auto_refresh = self.widgets['cb_auto_refresh'].var.get()
        auto_refresh = False
        if auto_refresh:
            self.application.update_current_selected_data()
            self.data = self.application.current_selected_data
            self.parameters = self.application.current_parameters
            self.refresh_plot()
        self.after(10000, self.timer)

    def show(self):
        # Show plot
        self.widgets['canvas_frame'] = ttk.Frame(self)
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.widgets['canvas_frame'])
        self.canvas.show()
        self.canvas.get_tk_widget().pack()
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.widgets['canvas_frame'])
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        self.canvas.mpl_connect('pick_event', self.onpick)
        self.widgets['canvas_frame'].grid(row=2, column=0, sticky="nsew", pady=10, padx=10)

    def config_plot(self):
        self.default_config()
        # Try to execute custom config from children, if exists
        try:
            self.config_plot_custom()
        except AttributeError: # If method does not exist
            pass

    def plot_redraw(self):
        self.config_plot()
        self.fig.canvas.draw()

    def columns_names_parse_as_int(self, columns_names):
        return_list = list()
        for name in columns_names:
            return_list.append(int(re.findall('([0-9]+)', str(name))[0]))
        return return_list

    def columns_names_parse_as_float(self, columns_names):
        return_list = list()
        for name in columns_names:
            return_list.append(float(re.findall('([0-9]+)', str(name))[0]))
        return np.array(return_list)

    def action_close(self):
        # Custom code when closing plot window
        try:
            self.action_close_custom()
        except AttributeError: # If method does not exist
            pass
        plt.close(self.fig) 
        self.destroy()

    def roi_axis(self):
        ' Used on plots which have ROI as x axis '
        p = self.parameters
        rois_numbers = self.columns_names_parse_as_float(p['intensity_names'])
        if p['use_calibration'] and p['calibration_data']:
            try:
                self.bottom_axes.set_xlabel('Energy (keV)')
                self.main_axes.set_xlabel('')
            except:
                self.main_axes.set_xlabel('Energy (keV)')
            return self.rois_to_energies()
        else:
            try:
                self.bottom_axes.set_xlabel('ROI')
                self.main_axes.set_xlabel('')
            except:
                self.main_axes.set_xlabel('ROI')
            return rois_numbers

    def mogonio_to_energy(self):
        p = self.parameters
        energies_values = np.array(self.data[:, p['energy_column']], dtype=float)
        if p['use_mogonio_calibration']:
            A = p['mogonio_calibration_a']
            B = p['mogonio_calibration_b']
            hc = 1239.8 # nm.eV
            a = 0.543102 # lattice parameter for Si, in nm 
            miller_indices = [1, 1, 1]
            m = miller_indices
            return (hc * np.sqrt(m[0]**2 + m[1]**2 + m[2]**2)/(2*a*np.sin(np.radians(A + B*energies_values))))/1000.0
        else:
            return energies_values

    def rois_to_energies(self, fresh=False):
        ' Used on plots which have ROI as x axis '
        p = self.parameters
        rois_numbers = self.columns_names_parse_as_int(p['intensity_names'])

        # Fitting
        if not fresh:
            calib = Tools.list_to_numpy(p['calibration_data']) 
        else:
            calib = Tools.list_to_numpy(self.application.widgets['calib_tree'].get_data())
        equation_parameters = np.polyfit(calib[:, 1], calib[:, 0], min(2, calib.shape[0]-1))
        self.log('* Energy calibration coefficients: ' + str(equation_parameters))

        # Apply fitting equation to ROIs numbers
        energies = np.polyval(equation_parameters, rois_numbers)

        return energies

    def action_btn_zoomall(self, *args, **kwargs):
        first = True
        for line in self.main_axes.lines:
            if first:
                min_x = min(line.get_xdata()) 
                max_x = max(line.get_xdata()) 
                min_y = min(line.get_ydata()) 
                max_y = max(line.get_ydata()) 
                first = False
            else:
                min_x = min(min_x, min(line.get_xdata()))
                max_x = max(max_x, max(line.get_xdata()))
                min_y = min(min_y, min(line.get_ydata()))
                max_y = max(max_y, max(line.get_ydata()))
        if not first: # If there is at least 1 line
            self.main_axes.set_xlim([min_x, max_x])
            self.main_axes.set_ylim([min_y, max_y])
            # Redraw changes
            self.fig.canvas.draw()

    def action_btn_normalization(self, *args, **kwargs):
        if not self.normalization_flag:
            self.normalization_flag = True
            self.widgets['btn_normalization']['text'] = 'Please double-click on y=0...'
            self.normalization_connection = self.canvas.mpl_connect('button_press_event', self.action_normalization_firstclick)
        else:
            self.widgets['btn_normalization']['text'] = 'Normalize y-axis'
            self.normalization_flag = False
            self.canvas.mpl_disconnect(self.normalization_connection)

    def action_normalization_firstclick(self, event, *args, **kwargs):
        if event.dblclick and event.inaxes == self.main_axes:
            y = event.ydata
            self.new_base_value = self.base_value + y * self.normalization_value
            self.canvas.mpl_disconnect(self.normalization_connection)
            self.normalization_connection = self.canvas.mpl_connect('button_press_event', self.action_normalization_secondclick)
            self.widgets['btn_normalization']['text'] = 'Please double-click on y=1...'

    def action_normalization_secondclick(self, event, *args, **kwargs):
        if event.dblclick and event.inaxes == self.main_axes:
            y = event.ydata
            self.normalization_value = (self.normalization_value * y + self.base_value - self.new_base_value)
            self.base_value = self.new_base_value
            self.action_btn_normalization()
            self.refresh_plot()

    def action_btn_derivative(self, *args, **kwargs):
        if self.selected_artist is not None:
            y = self.selected_artist['artist'].get_ydata()
            x = self.selected_artist['artist'].get_xdata()
            # Border effects may exist
            derivative_data = np.convolve(np.array([-1, 0, 1]), y, mode='same')
            delta_data = np.convolve(np.array([-1, 0, 1]), x, mode='same')
            derivative_data = np.divide(derivative_data, delta_data)
            self.main_axes.plot(x, derivative_data, picker=self.picker_tolerance, label='<Derivative of ' + self.selected_artist['artist'].get_label() + '>')
        self.fig.canvas.draw()
Example #9
0
class PhasePlot:
    def __init__(self, frame, tag_filter, tag_var, menubar):

        self.tag_filter = tag_filter
        self.tag_var = tag_var
        self.menubar = menubar

        # filter_frame2 = tk.LabelFrame(frame, text='Phase Filter', bg='white', bd=0,
        #                               font=('Times New Roman', 12, 'bold'), labelanchor='n')
        # filter_frame2.pack(side=tk.LEFT, fill=tk.BOTH)
        self.phase_vars = [tk.IntVar() for i in range(16)]
        self.phase_filter = CheckFilter(self.menubar, self.phase_vars)

        self.x_start = 0
        self.x_end = 400
        self.frame = frame

        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(111)



        self.canvas = FigureCanvasTkAgg(self.fig, master=frame)
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        self.canvas.mpl_connect("scroll_event", self.zoom)
        self.canvas.mpl_connect("button_press_event", self.input_Motionx_y)
        self.canvas.mpl_connect("button_release_event", self.output_Motionx_y)

    def update_plot(self, data):

        self.phase_filter.update_filter([i for i in range(16)])

        self.ax.cla()
        self.ax.set(xlabel='sample (#)', ylabel='phase (rad)',
                    title='Phase Plot')
        ys = data[self.tag_var.get()]['phase']
        self.data_len = len(ys[0])
        if self.data_len > 400 and self.x_end == self.data_len-1:
            self.x_start +=1
            self.x_end += 1
        if self.x_end - self.x_start <400 and self.x_end == self.data_len-1:
            self.x_start += 1
            self.x_end += 1


        ls = []
        labels = []
        # print(self.tag_var.get())
        for i in range(16):
            l, = self.ax.plot(ys[i], label='antenna%d' % (i + 1),
                              visible=self.phase_vars[i].get())
            if l.get_visible():
                ls.append(l)
                labels.append(l.get_label())
        self.ax.set_ylim(-6, 6)
        self.ax.set_xlim(self.x_start, self.x_end)
        self.ax.legend(ls, labels, loc=1)




        self.canvas.draw()

    def zoom(self,event):
        if event.button == "up":
            if self.x_end-self.x_start >50:
                self.x_end -= 50
                self.ax.set_xlim(self.x_start, self.x_end)
        else:
            if self.x_end-self.x_start <400:
                if self.x_start <= 25:
                    mid = self.x_start
                    self.x_start = 0
                    self.x_end += 25+abs(mid)
                    self.ax.set_xlim(self.x_start, self.x_end)
                elif self.x_end >=400:
                    mid = self.x_end - 400
                    self.x_end = self.data_len - 1
                    self.x_start += 25 + mid
                    self.ax.set_xlim(self.x_start, self.x_end)
                else:
                    self.x_start -= 25
                    self.x_end += 25
                    self.ax.set_xlim(self.x_start, self.x_end)
            elif self.x_end-self.x_start >= 400:
                pass


    def input_Motionx_y(self,event):
        self.c_list_x = []
        self.c_list_y = []
        self.c_list_x.append(event.x)
        self.c_list_y.append(event.y)
        self.move_f = self.canvas.mpl_connect("motion_notify_event", self.moveon)

    def output_Motionx_y(self,event):
        self.canvas.mpl_disconnect(self.move_f)

    def moveon(self,event):
        self.c_list_x.append(event.x)

        if self.c_list_x[-1]-self.c_list_x[-2] >0:
            if self.x_start >= 0:
                self.x_start -= 1
                self.x_end -= 1
            if self.x_start <= 0:
                mid = self.x_start
                self.x_start =0
                self.x_end += abs(mid)

        else:
            if self.data_len > self.x_end:
                self.x_start += 1
                self.x_end += 1

        self.ax.set_xlim(self.x_start, self.x_end)
Example #10
0
class GUI:
    def __init__(self, env_name, n_channels):
        self.n_channels = n_channels

        # The seaborn color_palette cubhelix is used to assign visually distinct colors to each channel for the env
        self.cmap = sns.color_palette("cubehelix", self.n_channels)
        self.cmap.insert(0, (0, 0, 0))
        self.cmap = colors.ListedColormap(self.cmap)
        bounds = [i for i in range(self.n_channels + 2)]
        self.norm = colors.BoundaryNorm(bounds, self.n_channels + 1)

        self.root = Tk.Tk()
        self.root.title(env_name)
        self.root.config(background='white')

        self.root.attributes("-topmost", True)
        if platform() == 'Darwin':  # How Mac OS X is identified by Python
            system(
                '''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' '''
            )
        self.root.focus_force()

        self.text_message = Tk.StringVar()
        self.label = Tk.Label(self.root, textvariable=self.text_message)

        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.root)
        self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
        self.key_press_handler = self.canvas.mpl_connect(
            'key_press_event', self.on_key_event)
        self.key_release_handler = self.canvas.mpl_connect(
            'key_press_event', lambda x: None)

    # Set the message for the label on screen
    def set_message(self, str):
        self.text_message.set(str)
        self.label.pack()

    # Show the current frame
    def display_state(self, state):
        self.ax.cla()
        numerical_state = np.amax(
            state * np.reshape(np.arange(self.n_channels) + 1,
                               (1, 1, -1)), 2) + 0.5
        self.ax.imshow(numerical_state,
                       cmap=self.cmap,
                       norm=self.norm,
                       interpolation='none')
        self.canvas.draw()

    # Allow user to handle their own keyboard input
    def overwrite_key_handle(self,
                             key_press_handler,
                             key_release_handler=None):
        self.canvas.mpl_disconnect(self.key_press_handler)
        self.key_press_handler = self.canvas.mpl_connect(
            'key_press_event', key_press_handler)
        if (key_release_handler is not None):
            self.canvas.mpl_disconnect(self.key_release_handler)
            self.key_release_handler = self.canvas.mpl_connect(
                'key_release_event', key_release_handler)

    # Default key handler
    def on_key_event(self, event):
        if event.key == "q":
            self.quit()

    # Quit the GUI
    def quit(self):
        self.root.quit()

    # After millisecond, calls function func
    def update(self, millisecond, func):
        self.root.after(millisecond, func)

    # Start the GUI
    def run(self):
        self.root.mainloop()
class PyplotEmbed(tk.Frame):
    """ Class that will make a tkinter frame with a matplotlib plot area embedded in the frame
    """
    def __init__(self, master, data):
        tk.Frame.__init__(self, master=master)
        self.index = 1
        self.lines = []
        self.labels = []
        self.colors = []
        self.vert_line = None
        self.data = data
        self.cursor_connect = None

        self.graph_area = tk.Frame(self)
        self.figure_bed = plt.figure(figsize=(6, 4))
        self.axis = self.figure_bed.add_subplot(111)

        self.canvas = FigureCanvasTkAgg(self.figure_bed, master=self)
        self.canvas._tkcanvas.config(highlightthickness=0)
        self.toolbar = NavToolbar(self.canvas, self)  # TODO: check this
        # self.toolbar.pack_forget()
        self.toolbar.pack()

        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side='left', fill=tk.BOTH, expand=1)

    def plot(self, data, _label, color=None):
        # self.data.plot(ax=self.graph_area.axis, label='channel {0}'.format(self.index))
        # line = self.axis.plot(data.index, data['voltage'], label=_label)[0]
        line = self.axis.plot(data.index, data, label=_label)[0]
        if color:
            line.set_color(color)
        self.colors.append(line.get_color())
        self.labels.append(_label)
        self.lines.append(line)
        self.axis.legend()
        self.index += 1
        self.canvas.show()

    def delete_all(self):
        while self.lines:
            l = self.lines.pop()
            l.remove()
            del l
        self.canvas.draw()
        self.index = 1
        self.axis.legend()

    def delete_some_data(self, picks):
        print('delete in graph: ', picks)
        for index in reversed(picks):
            self.delete_line(index)

    def delete_line(self, _index):
        self.index -= 1
        del self.labels[_index]
        line = self.lines.pop(_index)
        line.remove()
        del line
        self.update_legend()

    def change_line_color(self, _color, index):
        print('change line:', index, _color)
        self.lines[index].set_color(_color)
        self.colors[index] = _color

    def change_line_style(self, style, index):
        if style != 'solid':
            self.lines[index].set_linestyle(style)
            self.lines[index].set_dashes((1, 5))

    def update_legend(self):
        """ Update the legend and redraw the graph """
        handle, labels = self.axis.get_legend_handles_labels()

        self.axis.legend(
            handle,
            self.labels,
            loc='best',
            # bbox_to_anchor=(1, 0.5),
            # title='Data series',
            prop={'size': 10},
            fancybox=True)  # not adding all this screws it up
        # up for some reason
        self.canvas.show()  # update the canvas where the data is being shown

    def time_shift(self, data_index: int, time_to_shift: float):
        adj_time_shift = time_to_shift - self.data.time_start[data_index]

        x_data = self.data.adjusted_data[data_index].index - adj_time_shift
        self.lines[data_index].set_xdata(x_data)
        self.canvas.draw()

    def get_fit_start(self):
        print('make cursor')
        # cursor = self.axis.axvline(color='r')
        self.cursor_connect = self.canvas.mpl_connect('motion_notify_event',
                                                      self.onMouseMove)
        self.canvas.mpl_connect('button_press_event', self.onclick)
        self.canvas.show()

    def onMouseMove(self, event):
        if not event.xdata:  # mouse is not over the plot area
            return
        if self.vert_line:
            self.vert_line.remove()
            del self.vert_line
            self.vert_line = None
        self.vert_line = self.axis.axvline(x=event.xdata,
                                           color='r',
                                           linewidth=2)
        self.canvas.show()

    def onclick(self, event):
        if event.dblclick == 1:
            full_data_set = self.data.adjusted_data[-1]
            start_index = full_data_set.index.get_loc(event.xdata, 'nearest')
            # start_index = pd.Index(self.data.adjusted_data[-1]).get_loc(event.xdata, 'nearest')
            start_num = full_data_set.index[start_index]
            data_to_fit = self.data.adjusted_data[-1][start_num:start_num + 20]

            self.fit_data(data_to_fit, start_num)

    def fit_data(self, _data, starting_place):
        print('fitting')
        self.canvas.mpl_disconnect(self.cursor_connect)
        t = _data.index - starting_place  # change the time so t=0 at the start of the recording
        amplitude_guess = -_data.voltage.min()
        time_shift = 0
        bounds = (0.0, [
            1.2 * amplitude_guess, 1.2 * amplitude_guess,
            1.2 * amplitude_guess, 1.2 * amplitude_guess, 0.2, 2, 100, 100
        ])
        initial_guess = (2. * amplitude_guess / 3, amplitude_guess / 3.,
                         amplitude_guess / 2., amplitude_guess / 2., 0.2, 2, 2,
                         15)

        fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp,
                                         t,
                                         _data.voltage,
                                         p0=initial_guess,
                                         bounds=bounds,
                                         ftol=0.0000005,
                                         xtol=0.0000005)
        # fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp, t, _data.voltage, p0=initial_guess)
        print('fitting params: {0}'.format(fitted_parameters))

        # make a new line with the fitted parameters and draw it
        y_fitted = fitting_func_2a_2i_exp(t, *fitted_parameters)
        # plt.plot(t + _data.index, y_fitted, linewidth=2, label="Check")
        fitted_line = self.axis.plot(_data.index,
                                     y_fitted,
                                     linewidth=2,
                                     label='fitted')[0]

    def toogle_data_decimation(self, data):
        # line: matplotlib.lines.Line2D  # type hint the for loop variable
        for i, line in enumerate(self.lines):
            line.set_xdata(data[i].index.values)
            line.set_ydata(data[i])
        self.canvas.show()
Example #12
0
class App(object):  #swapped out object, tk.Frame
    def __init__(self, master):
        self.rt = master
        self.rt.protocol("WM_DELETE_WINDOW", self.onClosing)
        self.menu = tk.Menu(self.rt)
        self.rt.title('NMR GUI - Potter')
        self.rt.config(menu=self.menu)
        self.filemenu = tk.Menu(self.menu)
        self.menu.add_cascade(label='File', menu=self.filemenu)
        self.Master = master
        self.filemenu.add_command(label='New')
        self.filemenu.add_command(label='Open', command=self.openFile)
        self.filemenu.add_separator()
        self.filemenu.add_command(
            label='Exit',
            command=lambda: [root.quit(), root.destroy()])
        self.helpmenu = tk.Menu(self.menu)
        self.menu.add_cascade(label='Help', menu=self.helpmenu)
        self.helpmenu.add_command(label='About', command=self.launchHelpWindow)
        self.analysismenu = tk.Menu(self.menu)
        self.menu.add_cascade(label='Analysis', menu=self.analysismenu)
        self.analysismenu.add_command(label='Integrate',
                                      command=self.openIntegrationModule)
        self.analysismenu.add_command(label='EditIntegralList',
                                      command=self.showIntegralList)
        self.analysismenu.add_command(label='Calibrate',
                                      command=self.calibrate)
        self.xShift = 0.0
        self.showIntVar1 = tk.IntVar()
        self.calOn = 0
        self.intVar1 = tk.IntVar()
        self.showPeakVar1 = tk.IntVar()
        self.calVar1 = tk.IntVar()
        self.startCoords = []
        self.endCoords = []
        self.integrals = []
        self.intListVar = []
        self.intGraphics1 = []
        self.intGraphics2 = []
        self.peakList = []
        self.peakGraphics1 = []
        self.intCheckBoxes = []
        self.intDeleteButtons = []

        self.rt.mainloop()

    def openFile(self):

        self.filename = askopenfilename(parent=self.rt)
        with open(self.filename, mode='r') as file:
            self.data = pd.read_csv(file, names=['x', 'y'])
        self.th = 0.0
        self.t1Top = tk.Frame(self.rt)
        self.t1Bottom = tk.Frame(self.rt)
        self.t1Top.pack(side=tk.TOP)
        self.t1Bottom.pack(side=tk.BOTTOM)
        self.t1Left = tk.Frame(self.t1Top)
        self.t1Right = tk.Frame(self.t1Top)
        self.t1Left.pack(side=tk.LEFT)
        self.t1Right.pack(side=tk.RIGHT)
        self.fig = plt.figure()
        self.ax = self.fig.add_subplot(111)
        self.ax.set_xlim(self.data['x'].max(), self.data['x'].min())
        self.ax.plot(self.data['x'], self.data['y'])
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.rt)
        self.canvas.draw()
        #self.canvas.get_tk_widget().pack(in_ = self.t1Right, fill = tk.BOTH, expand = 1)
        self.canvas.get_tk_widget().pack(in_=self.t1Right,
                                         fill=tk.BOTH,
                                         expand=True)
        self.toolbar = NavigationToolbar2Tk(self.canvas, self.rt)
        self.toolbar.update()
        #self.canvas.get_tk_widget().pack(in_ = self.t1Right, fill = tk.BOTH, expand = 1)
        self.canvas.get_tk_widget().pack(in_=self.t1Right,
                                         fill=tk.BOTH,
                                         expand=True)
        self.xShiftScale = tk.Scale(self.rt,
                                    from_=self.data['y'].max(),
                                    to_=self.data['y'].min())
        self.xShiftScale.pack(in_=self.t1Left)
        self.showIntToggle = tk.Checkbutton(self.rt,
                                            text='Show Integrals',
                                            variable=self.showIntVar1,
                                            command=self.showIntegrals)
        self.showIntToggle.pack(in_=self.t1Bottom, side=tk.RIGHT)
        self.showPeaksToggle = tk.Checkbutton(self.rt,
                                              text='Show Peaks',
                                              variable=self.showPeakVar1,
                                              command=self.showPeaks)
        self.showPeaksToggle.pack(in_=self.t1Bottom, side=tk.RIGHT)

    def openIntegrationModule(self):
        self.t = tk.Toplevel(self.rt)
        self.t.protocol("WM_DELETE_WINDOW", self.onIntClosing)
        self.t.wm_title("Integration Module")
        self.intFig = plt.figure()
        self.intAx = self.intFig.add_subplot(111)
        self.intAx.set_xlim(self.data['x'].max(), self.data['x'].min())
        self.intAx.plot(self.data['x'], self.data['y'])
        self.canvas2 = FigureCanvasTkAgg(self.intFig, master=self.t)
        self.canvas2.draw()
        self.canvas2.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        self.toolbar2 = NavigationToolbar2Tk(self.canvas2, self.t)
        self.toolbar2.update()
        self.canvas2.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
        self.intToggle = tk.Checkbutton(self.t,
                                        text="Integration Mode",
                                        variable=self.intVar1,
                                        command=self.integrate)
        self.intToggle.pack(side=tk.LEFT)

    def onclick(self, event):
        ix = event.xdata
        self.startCoords.append(ix)

    def onrelease(self, event):
        ix = event.xdata
        self.endCoords.append(ix)
        pint.drawTraps(self.data,
                       min([self.startCoords[-1], self.endCoords[-1]]),
                       max([self.startCoords[-1], self.endCoords[-1]]),
                       self.intAx)
        self.canvas2.draw()

    def integrate(self):
        if self.intVar1.get() == 1:
            self.cid1 = self.canvas2.mpl_connect('button_press_event',
                                                 self.onclick)
            self.cid2 = self.canvas2.mpl_connect('button_release_event',
                                                 self.onrelease)
        else:
            self.canvas2.mpl_disconnect(self.cid1)
            self.canvas2.mpl_disconnect(self.cid2)

    def onClosing(self):
        if messagebox.askokcancel("Quit", "Do you want to quit?"):
            self.rt.quit()
            self.rt.destroy()

    def onIntClosing(self):
        if messagebox.askokcancel("Quit", "Save integrals?"):
            tempInts = []
            for i in range(len(self.startCoords)):
                tempInts.append(min([self.startCoords[i], self.endCoords[i]]))
                tempInts.append(max([self.startCoords[i], self.endCoords[i]]))
                tempInts.append(
                    pint.trapInt(self.data, tempInts[0], tempInts[1]))
                tempInts.append(1)
                self.integrals.append(tempInts.copy())
                tempInts.clear()
            self.startCoords.clear()
            self.endCoords.clear()
        self.t.destroy()

    def showIntegrals(self):
        if self.showIntVar1.get() == 1:
            for i in range(len(self.integrals)):  #this is the region marker
                if (self.integrals[i][3] == 1 and not self.intListVar) or (
                        self.integrals[i][3] == 1
                        and self.intListVar[i].get() == 1):
                    self.intGraphics1.append(
                        self.ax.annotate('',
                                         xy=(self.integrals[i][0], 0),
                                         xytext=(self.integrals[i][1], 0),
                                         arrowprops=dict(arrowstyle='<->',
                                                         facecolor='red'),
                                         annotation_clip=False))
            for i in range(len(self.integrals)
                           ):  #this is the line connecting the integral value
                if (self.integrals[i][3] == 1 and not self.intListVar) or (
                        self.integrals[i][3] == 1
                        and self.intListVar[i].get() == 1):
                    self.intGraphics2.append(
                        self.ax.annotate(
                            '{:.2f}'.format(self.integrals[i][2]),
                            xy=(self.integrals[i][0] + (
                                (self.integrals[i][1] - self.integrals[i][0]) /
                                2), 0),
                            xytext=(self.integrals[i][0] + (
                                (self.integrals[i][1] - self.integrals[i][0]) /
                                2), -3),
                            arrowprops=dict(arrowstyle='-', facecolor='red'),
                            annotation_clip=False))
            self.canvas.draw()
        else:
            for i in self.intGraphics1:
                i.remove()
            for i in self.intGraphics2:
                i.remove()
            self.intGraphics1.clear()
            self.intGraphics2.clear()
            self.canvas.draw()

    def showIntegralList(self):
        self.t2 = tk.Toplevel(self.rt)
        self.t2.protocol("WM_DELETE_WINDOW", self.onCloseIntegralListWindow)
        self.t2.wm_title("Integrals")
        self.t2Top = tk.Frame(self.t2)
        self.t2Bottom = tk.Frame(self.t2)
        self.t2Top.pack(side=tk.TOP)
        self.t2Bottom.pack(side=tk.BOTTOM)

        self.t2Left = tk.Frame(self.t2Bottom)
        self.t2Right = tk.Frame(self.t2Bottom)

        self.t2Left.pack(side=tk.LEFT)
        self.t2Right.pack(side=tk.RIGHT)

        for i in range(len(self.integrals)):
            self.intListVar.append(tk.IntVar(value=1))
            self.intCheckBoxes.append(
                tk.Checkbutton(self.t2Left,
                               text=str(len(self.integrals) - i) + '\t' +
                               '{:.2f}'.format(self.integrals[i][0]) + '\t' +
                               '{:.2f}'.format(self.integrals[i][1]) + '\t' +
                               '{:.2f}'.format(self.integrals[i][2]),
                               variable=self.intListVar[i],
                               width=40))
            self.intDeleteButtons.append(
                tk.Button(
                    self.t2Right,
                    text='Delete: ' + str((len(self.integrals) - i)),
                    command=lambda c=i: self.deleteInt(self.integrals, c))
            )  # why not lambda:self.integrals[len(self.integrals)-i-1] ????
            self.intCheckBoxes[i].pack(in_=self.t2Left,
                                       side=tk.BOTTOM,
                                       fill=tk.X)
            self.intDeleteButtons[i].pack(in_=self.t2Right, side=tk.BOTTOM)

    def deleteInt(self, ar, inx):
        del self.integrals[int(inx)]

    def onCloseIntegralListWindow(self):
        self.intCheckBoxes.clear()
        self.intDeleteButtons.clear()
        self.canvas.draw()
        self.t2Left.destroy()
        self.t2Right.destroy()
        self.t2Bottom.destroy()
        self.t2Top.destroy()
        self.t2.destroy()

    def showPeaks(self):  # removed parameter th
        self.th = self.xShiftScale.get()
        self.peakList = find_peaks(self.data['y'].to_numpy(), self.th)
        if self.showPeakVar1.get() == 1:
            a = 0
            for i in range(len(self.peakList[0])):
                if ((self.data.iloc[self.peakList[0][i - 1]][1] <
                     self.data.iloc[self.peakList[0][i]][1]) and
                    ((self.data.iloc[self.peakList[0][i - 1]][1]) >=
                     (self.data.iloc[self.peakList[0][i]][1] - 0.1))
                        or ((self.data.iloc[self.peakList[0][i - 1]][1] >
                             (self.data.iloc[self.peakList[0][i]][1])) and
                            ((self.data.iloc[self.peakList[0][i - 1]][1]) <=
                             (self.data.iloc[self.peakList[0][i]][1] + 0.1)))):
                    a = a + 1
                else:
                    a = a + 0
                self.peakGraphics1.append(
                    self.ax.annotate(
                        '{:.2f}'.format(
                            self.data.iloc[self.peakList[0][i]][0]),
                        xy=(self.data.iloc[self.peakList[0][i]][0],
                            self.data.iloc[self.peakList[0][i]][1]),
                        xytext=(self.data.iloc[self.peakList[0][i]][0],
                                self.data.iloc[self.peakList[0][i]][1] + a)))
            self.canvas.draw()
        else:
            for i in self.peakGraphics1:
                i.remove()
            self.peakGraphics1.clear()
            self.canvas.draw()

    def onclick2(self, event):
        ix = event.xdata
        self.xShift = ix
        self.data['x'] = self.data['x'] - self.xShift
        self.shiftIntegrals(self.integrals, self.xShift)
        self.calOn = 0
        self.canvas.mpl_disconnect(self.cid3)
        self.rt.config(cursor='')

    def shiftIntegrals(self, iL, sh):
        msgBox = tk.messagebox.askquestion(
            'Shift Integrals',
            'Shift integrals along with spectrum?',
            icon='warning')
        if msgBox == 'yes':
            self.integralShift(iL, sh)
            self.ax.cla()
            self.ax.set_xlim(self.data['x'].max(), self.data['x'].min())
            self.ax.plot(self.data['x'], self.data['y'])
            self.canvas.draw()
        else:
            self.ax.cla()
            self.ax.set_xlim(self.data['x'].max(), self.data['x'].min())
            self.ax.plot(self.data['x'], self.data['y'])
            self.canvas.draw()

    def integralShift(self, ints, xsh):
        for i in range(len(self.integrals)):
            self.integrals[i][0] = self.integrals[i][0] - xsh
            self.integrals[i][1] = self.integrals[i][1] - xsh

    def calibrate(self):
        self.rt.config(cursor='cross')
        self.calOn = 1
        self.cid3 = self.canvas.mpl_connect('button_press_event',
                                            self.onclick2)

    def onHelpClosing(self):
        self.t3.destroy()

    def launchHelpWindow(self):
        self.t3 = tk.Toplevel(self.rt)
        self.t3.protocol("WM_DELETE_HELPWINDOW", self.onHelpClosing)
        self.helpText = tk.Text(self.t3, height=10, width=30, wrap='word')
        self.helpText.pack(expand=True, fill=tk.BOTH)
        __location__ = os.path.realpath(
            os.path.join(os.getcwd(), os.path.dirname(__file__)))
        aboutFile = open(os.path.join(__location__, 'about.rtf'))
        self.helpText.insert(tk.END, aboutFile.read())
        aboutFile.close()
Example #13
0
class GUI():
    def __init__(self,root,song):
        # given parameters
        self.root = root
        self.song = song

        # main window
        self.root.title("Song segment player")
        self.root.iconbitmap(r'Images/icon.ico')
        self.root.configure(background='white')

        # menubar
        self.menubar = Menu(self.root)
        self.filemenu = Menu(self.menubar,tearoff=0)
        self.filemenu.add_command(label="Open",
                                  command=lambda:b.openSong(self))
        self.menubar.add_cascade(label="File",menu=self.filemenu)

        # images for buttons
        self.segmentIm = PhotoImage(file=r'Images/SegmentB.png')
        self.repSegIm = PhotoImage(file=r'Images/Repeat.png')
        self.playIm = PhotoImage(file=r'Images/PlayB.png')
        self.pauseIm = PhotoImage(file=r'Images/PauseB.png')
        self.stopIm = PhotoImage(file=r'Images/StopB.png')
        self.ffIm = PhotoImage(file=r'Images/ffB.png')
        self.rwIm = PhotoImage(file=r'Images/rwB.png')
        self.fullSpeedIm = PhotoImage(file=r'Images/FullSpeedB.png')
        self.halfSpeedIm = PhotoImage(file=r'Images/HalfSpeedB.png')
        self.sliderIm = PhotoImage(file=r'Images/SliderB.png')
        self.cursorIm = PhotoImage(file=r'Images/Cursor.png')
        self.magPlusIm = PhotoImage(file=r'Images/MagPlus.png')
        self.magMinusIm = PhotoImage(file=r'Images/MagMinus.png')

        # making buttons
        self.segmentB = Button(image=self.segmentIm,
                               command=lambda:b.playSeg(self.song))
        self.repSegB = Button(image=self.repSegIm,
                                 command=lambda:b.repeatSeg(self.song,self.repSegB))
        self.playB = Button(image=self.playIm,
                            command=lambda:b.playStream(self.song))
        self.pauseB = Button(image=self.pauseIm,
                             command=lambda:b.pauseStream(self.song))
        self.stopB = Button(image=self.stopIm,
                            command=lambda:b.stopStream(self.song))
        self.ffB = Button(image=self.ffIm,
                          command=lambda:b.ffStream(self.song))
        self.rwB = Button(image=self.rwIm,
                          command=lambda:b.rwStream(self.song))
        self.fullSpeedB = Button(image=self.fullSpeedIm)
        self.halfSpeedB = Button(image=self.halfSpeedIm)
        # making radio buttons
        self.CLICKMODE = StringVar(value="slide")
        self.sliderB = Radiobutton(
            self.root,
            image=self.sliderIm,
            variable=self.CLICKMODE,
            value='slide',
            indicatoron=0)
        self.cursorB = Radiobutton(
            self.root,
            image=self.cursorIm,
            variable=self.CLICKMODE,
            value='curse',
            indicatoron=0)
        self.magPlusB = Radiobutton(
            self.root,
            image=self.magPlusIm,
            variable=self.CLICKMODE,
            value='mag+',
            indicatoron=0)
        self.magMinusB = Radiobutton(
            self.root,
            image=self.magMinusIm,
            variable=self.CLICKMODE,
            value='mag-',
            indicatoron=0)

        # setting button parameters
        self.allButts = [self.segmentB,self.repSegB,self.playB,self.stopB,
                         self.pauseB,self.ffB,self.rwB,self.fullSpeedB,
                         self.halfSpeedB,self.sliderB,self.cursorB,
                         self.magPlusB,self.magMinusB]
        [butt.config(bg='white') for butt in self.allButts]
        # disable all buttons to start with
        [butt.config(state='disabled') for butt in self.allButts]
        self.sliderB.config(state='normal')

        # placing buttons
        rowc = 3
        self.segmentB.grid(row=0,column=2)
        self.repSegB.grid(row=0,column=3)
        self.playB.grid(row=rowc,column=3)
        self.pauseB.grid(row=rowc,column=2)
        self.stopB.grid(row=rowc,column=1)
        self.ffB.grid(row=rowc,column=4)
        self.rwB.grid(row=rowc,column=0)
        self.fullSpeedB.grid(row=0,column=4,columnspan=3)
        self.halfSpeedB.grid(row=0,column=5,columnspan=3)
        self.sliderB.grid(row=2,column=0)
        self.cursorB.grid(row=2,column=1)
        self.magPlusB.grid(row=2,column=2)
        self.magMinusB.grid(row=2,column=3)

        # display song title
        if self.song.songname:
            t = self.song.songname[0:-4]
        else:
            t = ''
        self.songTitleL = Label(self.root,text=t,bg='white')
        self.songTitleL.grid(row=0,column=0)

        # making figure canvas
        self.canvas = FigureCanvasTkAgg(self.song.fig,master=self.root)
        self.canvas.draw()
        self.canvas.get_tk_widget().grid(row=rowc-2,column=0,columnspan=5)

        # connecting canvas to monitor events
        self.cidpress = self.canvas.mpl_connect(
            'button_press_event',
            lambda event:e.on_press(event,self.song,self.CLICKMODE))
        self.cidrelease = self.canvas.mpl_connect(
            'button_release_event',
            lambda event:e.on_release(event,self.song))
        self.cidmotion = self.canvas.mpl_connect(
            'motion_notify_event',
            lambda event:e.on_motion(event,self.song))

        self.root.bind('<space>', lambda event:b.playPauseStream(self.song))
        self.root.bind('<Return>', lambda event:b.playSeg(self.song))

        # set cursor updating
        self.root.after(10000,lambda: e.updateCursor(self))

        # insert menu bar
        self.root.config(menu=self.menubar)

        # closing behaviour
        self.root.protocol("WM_DELETE_WINDOW",self.on_closing)



    def on_closing(self):
        self.canvas.mpl_disconnect(self.cidpress)
        self.canvas.mpl_disconnect(self.cidrelease)
        self.canvas.mpl_disconnect(self.cidmotion)
        self.root.destroy()
        self.song.wf.close()
        self.song.stream.close()
        self.song.p.terminate()
        [os.remove(s) for s in self.song.createdFilepaths]

    def updateCursor(self):
        if self.song.wf:
            pos = self.song.wf.tell()/self.song.RATE
            self.song.cursor[0].set_x(pos)
            self.canvas.draw()
        self.root.after(250,self.updateCursor)
Example #14
0
class MapPage(tk.Frame):
    '''
    A page that will show the map of currently plotted earthquakes from the 'current_data.json' file
    '''
    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller
        self.local_url = None
        self.mappage_balloon = Pmw.Balloon(self)

        self.bind("<<RefreshPlot>>", self.refresh_plot)

        self.menubar = Pmw.MenuBar(self, hull_relief="raised", hull_borderwidth=1, balloon=self.mappage_balloon)
        self.menubar.pack(side="top", fill="x")

        self.menubar.addmenu("pages", "Switch Pages", "", "right")
        self.menubar.addmenu("file", "File And Data Options")
        self.menubar.addmenuitem("file", "command", "Quit The Program",
            command=self.controller.on_close_window, label="Quit")

        self.menubar.addmenuitem("pages", "command", "Switch To Settings Page",
            command=lambda: self.controller.show_frame("SettingsPage"), label="Settings Page")

        self.map_frame = tk.Frame(self)
        self.map_frame.pack(side="bottom", fill="both", expand=True)

        #Line2D objects are used here to be placed in the legend of the graph for more detail on the map
        legend_elements = [Line2D([0], [0], marker="o", color="green", label="Small (below 3)"),
                    Line2D([0], [0], marker="o", color="yellow", label="Medium (below 6)"),
                    Line2D([0], [0], marker="o", color="red", label="Large (above 6)")]

        self.map_figure = plt.figure(num=None, figsize=(12, 4))
        self.map_axes = self.map_figure.add_subplot(111)
        self.map_axes_legend = self.map_axes.legend(handles=legend_elements, loc="upper right") #placing the legend
        self.map_axes.set_title("Earthquake Events - Mercator Projection")
        self.map_figure.tight_layout() #makes sure that when placing the map onto the GUI, it is responsive

        self.figure_basemap = Basemap(projection="merc", llcrnrlat=-80, urcrnrlat=80,
            llcrnrlon=-180, urcrnrlon=180, resolution="c") #defines that the map is using mercator projection
        
        self.figure_basemap.drawcoastlines()
        self.figure_basemap.fillcontinents(color="tan", lake_color="lightblue")
        self.figure_basemap.drawstates(color="darkred")
        self.figure_basemap.drawparallels(np.arange(-90.,91.,30.), labels=(True, True, False, False), dashes=(2,2))
        self.figure_basemap.drawmeridians(np.arange(-180.,181.,60.), labels=(False, False, False, True), dashes=(2,2))
        self.figure_basemap.drawmapboundary(fill_color="lightblue")
        self.figure_basemap.drawcountries()

        self.figure_canvas = FigureCanvasTkAgg(self.map_figure, self.map_frame) #creates the figure and draws the map onto it
        self.figure_canvas.draw()
        self.figure_canvas.get_tk_widget().pack(side="bottom", fill="both", expand=True)
        self.canvas_pick_event = self.figure_canvas.mpl_connect("pick_event", self.display_point_info)
        
        self.figure_toolbar = NavigationToolbar2Tk(self.figure_canvas, self.map_frame) #Toolbar with additional options is added to the figure
        self.figure_toolbar.update()
        self.figure_canvas._tkcanvas.pack(side="top", fill="both", expand=True)
    
    def refresh_plot(self, event):
        '''
        Method for checking whether there is any different data to plot and if so
        reads it from the json file, done by checking the local_url against controller's current_url
        '''
        if self.local_url == self.controller.current_url:
            return "Same Request"

        self.local_url = self.controller.current_url
        with open("current_data.json", "r") as json_file:
            data = json.load(json_file)
        
        self.plot_points(data)
        messagebox.showinfo(title="Data Plotted", message="{} points plotted".format(data["metadata"]["count"]))

    def plot_points(self, filedata):
        '''
        Method for creating MapPoint objects and plotting them on the figure, by first clearing the figure of any
        previous plots and then reading 'current_data.json'
        '''
        self.map_axes.lines.clear()
        
        for quake in filedata["features"]:
            lat=quake["geometry"]["coordinates"][1]
            if lat > 80: lat=80
            elif lat <-80: lat=-80
            nx,ny = self.figure_basemap((quake["geometry"]["coordinates"][0],), (lat,))

            new_point = MapPoint(nx, ny, quake["properties"]["mag"], quake["properties"]["place"],
                quake["properties"]["time"], quake["properties"]["felt"], quake["properties"]["cdi"],
                quake["properties"]["mmi"], quake["properties"]["alert"], quake["properties"]["tsunami"],
                quake["properties"]["sig"], quake["properties"]["title"], quake["properties"]["status"],
                quake["properties"]["dmin"], quake["properties"]["gap"], quake["properties"]["magType"],
                quake["properties"]["type"])
            
            self.map_axes.add_line(new_point)
        self.figure_canvas.draw()
    
    def display_point_info(self, event):
        '''
        Method when an individual point is picked, prompts the user to view information about it
        '''
        line_obj = event.artist
        
        messagebox.showinfo(title="Point Selected", message="Here is more info about the point - {}".format(line_obj.place))
        self.figure_canvas.mpl_disconnect(self.canvas_pick_event)
        self.controller.call_display_info(line_obj)
        self.controller.show_frame("PointInfoPage")

    def reconnect_pick_event(self):
        '''
        Method to reconnect pick event with the figure after a previous disconnect
        '''
        self.canvas_pick_event = self.figure_canvas.mpl_connect("pick_event", self.display_point_info)
Example #15
0
class NeuriteDialogBox:

    def __init__(self, parent):

        top1 = self.top1 = Toplevel(parent)
        top2 = self.top2 = Toplevel(parent)
        top3 = self.top3 = Toplevel(parent)
        
        top1.title("Neurite analysis")
        top2.title("Neurite analysis")
        top3.title("Neurite analysis")
        

        top1.bind("<Escape>",self.cancel)
        top2.bind("<Escape>",self.cancel)
        top3.bind("<Escape>",self.cancel)
        

        top2.withdraw()
        top3.withdraw()
        


        # Window 1:

        self.entr_lab=[None]*6
        self.entr_var_map=[None]*6
        self.entr_map=[None]*6
        self.entr_var_data=[None]*6
        self.entr_data=[None]*6



        self.entr_lab[0]=Label(top1, text="Image 1")
        self.entr_lab[1]=Label(top1, text="Image 2")
        self.entr_lab[2]=Label(top1, text="Image 3")
        self.entr_lab[3]=Label(top1, text="Image 4")
        self.entr_lab[4]=Label(top1, text="Image 5")
        self.entr_lab[5]=Label(top1, text="Image 6")

        for i in range(0,6):
            self.entr_lab[i].grid(row=i+2,column=0,sticky=W)



        for i in range(0,6):
            self.entr_var_map[i]=StringVar()

        for i in range(0,6):
            self.entr_map[i] = Entry(top1,textvariable=self.entr_var_map[i])

        for i in range(0,6):
            self.entr_map[i].grid(row=i+2,column=1,columnspan=2)

        for i in range(0,6):
            self.entr_var_map[i].trace('w',self.nxt_button1)
            self.entr_var_map[i].trace('u',self.nxt_button1)



        for i in range(0,6):
            self.entr_var_data[i]=StringVar()

        for i in range(0,6):
            self.entr_data[i] = Entry(top1,textvariable=self.entr_var_data[i])

        for i in range(0,6):
            self.entr_data[i].grid(row=i+2,column=3,columnspan=2)

        for i in range(0,6):
            self.entr_var_data[i].trace('w',self.nxt_button1)
            self.entr_var_data[i].trace('u',self.nxt_button1)



        self.img_num_lab=Label(top1,text="Number of images:")
        self.img_num_lab.grid(row=0,column=0,columnspan=2)

        self.img_num_var=IntVar()

        self.img_num=OptionMenu(top1,self.img_num_var,1,2,3,4,5,6)
        self.img_num.grid(row=0,column=2,sticky=W)

        self.img_num_var.set(1)

        self.img_num_var.trace('w',self.refresh_win1)



        self.out_entry_lab=Label(top1,text="Output file: ")
        self.out_entry_lab.grid(row=0,column=3)

        self.out_entry_var=StringVar()

        self.out_entry=Entry(top1,textvariable=self.out_entry_var,width=10)
        self.out_entry.grid(row=0,column=4,columnspan=2)

        self.out_entry_var.trace('w',self.nxt_button1)
        self.out_entry_var.trace('u',self.nxt_button1)



        self.nxt1 = Button(top1, text="Next", command=self.wind2_open,width=10)
        canc1 = Button(top1,text="Cancel",command=self.cancel,width=10)
        
        self.nxt1.grid(row=8, column=1)
        canc1.grid(row=8, column=3)

        self.mapping_label=Label(top1,text="Mapping").grid(row=1,column=1,columnspan=2)
        self.data_label=Label(top1,text="Data").grid(row=1,column=3,columnspan=2)
        


        self.nxt1.configure(state="disabled")

        for i in range(1,6):
            self.entr_map[i].configure(state="disabled")
            self.entr_data[i].configure(state="disabled")
            self.entr_lab[i].configure(state="disabled")


        
        # Window 2:

        self.map_box_lab=Label(top2, text="Mapping box size:")
        self.data_box_lab=Label(top2, text="Data box radius:")
        self.clust_rb_lab=Label(top2, text="Clustering")
        self.clust_size_lab=Label(top2, text="Cluster size:")
        self.spac_lab=Label(top2, text="Spacing:")

        self.map_box_lab.grid(row=0,column=0,sticky=W)
        self.data_box_lab.grid(row=0,column=2,sticky=W)
        self.spac_lab.grid(row=1,column=0,sticky=W)
        self.clust_rb_lab.grid(row=2,column=0,rowspan=2,sticky=W)
        self.clust_size_lab.grid(row=2,column=2,rowspan=2,sticky=W)

        self.map_box_var=StringVar()
        self.data_box_var=StringVar()
        self.clust_rb_var=BooleanVar()
        self.clust_size_var=StringVar()
        self.spac_var=StringVar()

        self.map_box=Entry(top2,width=5,textvariable=self.map_box_var)
        self.data_box=Entry(top2,width=5,textvariable=self.data_box_var)
        self.clust_size=Entry(top2,width=5,textvariable=self.clust_size_var)
        self.spac=Entry(top2,width=5,textvariable=self.spac_var)

        self.clust_rb_y=Radiobutton(top2,text="Yes",variable=self.clust_rb_var,value=True)
        self.clust_rb_n=Radiobutton(top2,text="No",variable=self.clust_rb_var,value=False)

        self.map_box.grid(row=0,column=1)
        self.data_box.grid(row=0,column=3)
        self.clust_size.grid(row=2,column=3,rowspan=2)
        self.clust_rb_y.grid(row=2,column=1)
        self.clust_rb_n.grid(row=3,column=1)
        self.spac.grid(row=1,column=1)

        self.clust_rb_var.trace('w',self.refresh_win2)

        self.map_box_var.trace('w',self.nxt_button2)
        self.data_box_var.trace('w',self.nxt_button2)
        self.clust_rb_var.trace('w',self.nxt_button2)
        self.clust_size_var.trace('w',self.nxt_button2)
        self.spac_var.trace('w',self.nxt_button2)


        self.nxt2 = Button(top2, text="Next", command=self.wind3_open,width=10)
        canc2 = Button(top2,text="Cancel",command=self.cancel,width=10)
        
        self.nxt2.grid(row=4, column=0,columnspan=2)
        canc2.grid(row=4, column=2,columnspan=2)


        self.nxt2.configure(state="disabled")
        self.clust_size.configure(state="disabled")
        self.clust_size_lab.configure(state="disabled")
        self.clust_rb_var.set(False)



        #Window 3:

        top3.columnconfigure(0,minsize=300)
        top3.columnconfigure(1,minsize=300)
        

        #frames:
        frame=self.frame=[None]*6

        for i in range(0,6):
            frame[i]=Frame(top3,borderwidth=1,relief=SUNKEN)
            frame[i].grid(row=int(i/2),column=i%2)
            frame[i].rowconfigure(1,minsize=5)
            frame[i].columnconfigure(2,minsize=100)
            frame[i].columnconfigure(4,minsize=50)
            frame[i].columnconfigure(5,minsize=50)



        #main buttons:
        self.exe=Button(top3,text="Execute",command=self.multi_fil,width=10,pady=3)
        canc3 = Button(top3,text="Cancel",command=self.cancel,width=10,pady=3)

        self.exe.grid(row=3,column=0)
        canc3.grid(row=3,column=1)
        
        self.exe.configure(state="disabled")



        #frame elements:
        self.map_file_lab=[None]*6
        self.data_file_lab=[None]*6
        self.map_file_name=[None]*6
        self.data_file_name=[None]*6
        self.empty=[None]*6
        self.hor_distance_lab=[None]*6
        self.ver_distance_lab=[None]*6
        self.hor_distance_var=[None]*6
        self.ver_distance_var=[None]*6
        self.hor_distance=[None]*6
        self.ver_distance=[None]*6
        self.wid_lab=[None]*6
        self.hig_lab=[None]*6
        self.wid=[None]*6
        self.hig=[None]*6
        self.hor_scale_lab=[None]*6
        self.ver_scale_lab=[None]*6
        self.hor_scale=[None]*6
        self.ver_scale=[None]*6
        self.hor_var=[None]*6
        self.ver_var=[None]*6
        self.starting_point_lab=[None]*6
        self.end_point_lab=[None]*6
        self.sp_x_var=[None]*6
        self.sp_y_var=[None]*6
        self.ep_x_var=[None]*6
        self.ep_y_var=[None]*6
        self.sp_x=[None]*6
        self.sp_y=[None]*6
        self.ep_x=[None]*6
        self.ep_y=[None]*6
        self.set=[None]*6
        self.soma_lab=[None]*6
        self.soma_var=[None]*6
        self.soma=[None]*6
        self.rev_var=[None]*6
        self.rev=[None]*6
        self.tolerance_lab=[None]*6
        self.tolerance_var=[None]*6
        self.tolerance=[None]*6



        for i in range(0,6):

            self.map_file_lab[i]=Label(frame[i],text="Mapping file:",font="bold")
            self.data_file_lab[i]=Label(frame[i],text="Data file:",font="bold")

            self.map_file_lab[i].grid(row=0,column=0)
            self.data_file_lab[i].grid(row=0,column=3)

            self.map_file_name[i]=Label(frame[i],font="bold")
            self.data_file_name[i]=Label(frame[i],font="bold")

            self.map_file_name[i].grid(row=0,column=1,columnspan=2)
            self.data_file_name[i].grid(row=0,column=4,columnspan=2)


            self.empty[i]=Label(frame[i],text="")
            self.empty[i].grid(row=1)


            self.tolerance_lab[i]=Label(frame[i],text="Tolerance")

            self.tolerance_lab[i].grid(row=2,column=0,columnspan=2,sticky=W)

            self.tolerance_var[i]=IntVar()

            self.tolerance[i]=OptionMenu(frame[i],self.tolerance_var[i],1,2,3,4,5,6,7,8,9,10)
            self.tolerance[i].grid(row=2,column=2)

            self.tolerance_var[i].set(1)



            self.hor_distance_lab[i]=Label(frame[i],text="Horizontal distance [um]:   ")
            self.ver_distance_lab[i]=Label(frame[i],text="Vertical distance [um]:")
            self.hor_distance_lab[i].grid(row=3,column=0,columnspan=2,sticky=W)
            self.ver_distance_lab[i].grid(row=4,column=0,columnspan=2,sticky=W)

            self.hor_distance_var[i]=StringVar()
            self.ver_distance_var[i]=StringVar()

            self.hor_distance[i]=Entry(frame[i],textvariable=self.hor_distance_var[i],width=5)
            self.ver_distance[i]=Entry(frame[i],textvariable=self.ver_distance_var[i],width=5)
            self.hor_distance[i].grid(row=3,column=2)
            self.ver_distance[i].grid(row=4,column=2)

            self.hor_distance_var[i].trace('w',lambda a,b,c,j=i: self.scaling(a,b,c,j))
            self.hor_distance_var[i].trace('u',lambda a,b,c,j=i: self.scaling(a,b,c,j))
            self.ver_distance_var[i].trace('w',lambda a,b,c,j=i: self.scaling(a,b,c,j))
            self.ver_distance_var[i].trace('u',lambda a,b,c,j=i: self.scaling(a,b,c,j))


            self.wid_lab[i]=Label(frame[i],text="Width:")
            self.hig_lab[i]=Label(frame[i],text="Height:")

            self.wid_lab[i].grid(row=5,column=0,sticky=W)
            self.hig_lab[i].grid(row=6,column=0,sticky=W)

            self.wid[i]=Label(frame[i])
            self.hig[i]=Label(frame[i])

            self.wid[i].grid(row=5,column=2)
            self.hig[i].grid(row=6,column=2)


            self.hor_scale_lab[i]=Label(frame[i],text="Horizontal scale:")
            self.ver_scale_lab[i]=Label(frame[i],text="Vertical scale:")

            self.hor_scale_lab[i].grid(row=7,column=0,sticky=W)
            self.ver_scale_lab[i].grid(row=8,column=0,sticky=W)

            self.hor_var[i]=DoubleVar()
            self.ver_var[i]=DoubleVar()

            self.hor_var[i].trace('w',self.exe_button)
            self.ver_var[i].trace('w',self.exe_button)

            self.hor_scale[i]=Label(frame[i])
            self.ver_scale[i]=Label(frame[i])

            self.hor_scale[i].grid(row=7,column=2)
            self.ver_scale[i].grid(row=8,column=2)


            self.rev_var[i]=BooleanVar()

            self.rev[i]=Checkbutton(frame[i],text="Reverse",variable=self.rev_var[i],onvalue=True,offvalue=False)

            self.rev[i].grid(row=2,column=3,columnspan=2,sticky=W)

            self.rev_var[i].set(False)


            self.starting_point_lab[i]=Label(frame[i],text="Starting point:")
            self.end_point_lab[i]=Label(frame[i],text="End point:")

            self.starting_point_lab[i].grid(row=3,column=3,sticky=W)
            self.end_point_lab[i].grid(row=4,column=3,sticky=W)

            self.sp_x_var[i]=StringVar()
            self.sp_y_var[i]=StringVar()
            self.ep_x_var[i]=StringVar()
            self.ep_y_var[i]=StringVar()

            self.sp_x_var[i].trace('w',self.exe_button)
            self.sp_y_var[i].trace('w',self.exe_button)
            self.ep_x_var[i].trace('w',self.exe_button)
            self.ep_y_var[i].trace('w',self.exe_button)

            self.sp_x[i]=Label(frame[i])
            self.sp_y[i]=Label(frame[i])
            self.ep_x[i]=Label(frame[i])
            self.ep_y[i]=Label(frame[i])

            self.sp_x[i].grid(row=3,column=4)
            self.sp_y[i].grid(row=3,column=5)
            self.ep_x[i].grid(row=4,column=4)
            self.ep_y[i].grid(row=4,column=5)


            self.set[i]=Button(frame[i],text="Set points",width=15)
            self.set[i].grid(row=7,column=3,columnspan=3,rowspan=2)


            self.soma_lab[i]=Label(frame[i],text="Starting distance"+"\n"+"from soma [um]:",justify=LEFT)
            self.soma_lab[i].grid(row=5,column=3,rowspan=2,sticky=W)

            self.soma_var[i]=StringVar()

            self.soma_var[i].trace('w',self.exe_button)
            self.soma_var[i].trace('u',self.exe_button)

            self.soma[i]=Entry(frame[i],textvariable=self.soma_var[i],width=5)
            self.soma[i].grid(row=5,column=5,rowspan=2)



    def cancel(self,event=None):

        self.top1.destroy()
        self.top2.destroy()
        self.top3.destroy()


    def refresh_win1(self,*args):

        for i in range(self.img_num_var.get(),6):

            self.entr_map[i].configure(state="disabled")
            self.entr_data[i].configure(state="disabled")
            self.entr_lab[i].configure(state="disabled")

            self.entr_var_map[i].set("")
            self.entr_var_data[i].set("")

        for j in range(1,self.img_num_var.get()):

            self.entr_map[j].configure(state="normal")
            self.entr_data[j].configure(state="normal")
            self.entr_lab[j].configure(state="normal")
    

    def nxt_button1(self,*args):

        if self.out_entry_var.get()!="":

            if all(self.entr_var_map[i].get()!="" for i in range(0,self.img_num_var.get())) and all(self.entr_var_data[i].get()!="" for i in range(0,self.img_num_var.get())):

                self.nxt1.configure(state="normal")
                self.top1.bind("<Return>",self.wind2_open)

            else:   
                self.nxt1.configure(state="disabled")
                self.top1.unbind("<Return>")

        else:   
            self.nxt1.configure(state="disabled")
            self.top1.unbind("<Return>")


    def refresh_win2(self,*args):

        if self.clust_rb_var.get():
            self.clust_size.configure(state="normal")
            self.clust_size_lab.configure(state="normal")
        else:
            self.clust_size.configure(state="disabled")
            self.clust_size_lab.configure(state="disabled")
            self.clust_size_var.set('')


    def nxt_button2(self,*args):

        if self.clust_rb_var.get():

            try:
                int(self.clust_size.get())
                int(self.map_box.get())
                int(self.data_box.get())
                int(self.spac.get())

            except ValueError:
                self.nxt2.configure(state="disabled")

            else:
                if int(self.map_box.get())<=1:
                    self.map_box_var.set('2')
                if int(self.data_box.get())<1:
                    self.data_box_var.set('1')
                if int(self.spac.get())<0:
                    self.data_box_var.set('0')
                if int(self.clust_size.get())<2:
                    self.data_box_var.set('2')

                self.nxt2.configure(state="normal")

        else:

            try:
                int(self.map_box.get())
                int(self.data_box.get())
                int(self.spac.get())

            except ValueError:
                self.nxt2.configure(state="disabled")

            else:
                if int(self.map_box.get())<=1:
                    self.map_box_var.set('2')
                if int(self.data_box.get())<1:
                    self.data_box_var.set('1')
                if int(self.spac.get())<0:
                    self.data_box_var.set('0')

                self.nxt2.configure(state="normal")



    def exe_button(self,*args):

        if all(self.hor_var[i].get()!=0 for i in range(0,self.img_num_var.get())) and all(self.ver_var[i].get()!=0 for i in range(0,self.img_num_var.get())):

            try:
                for j in range(0,self.img_num_var.get()):
                    float(self.soma_var[j].get())
                    int(self.sp_x_var[j].get())
                    int(self.sp_y_var[j].get())
                    int(self.ep_x_var[j].get())
                    int(self.ep_y_var[j].get())

            except ValueError:
                self.exe.configure(state="disabled")

            else:
                self.exe.configure(state="normal")
         

    def wind2_open(self,event=None):

        self.top1.withdraw()
        self.top2.deiconify()


    def wind3_open(self,event=None):

        self.top2.withdraw()
        self.top3.deiconify()

        txt1=[None]*self.img_num_var.get()
        txt2=[None]*self.img_num_var.get()
        
        for i in range(0,self.img_num_var.get()):
            self.map_file_name[i].configure(text=self.entr_var_map[i].get())
            self.data_file_name[i].configure(text=self.entr_var_data[i].get())
            
            txt1[i]=str(count(self.entr_var_map[i].get())[1])+" px"
            txt2[i]=str(count(self.entr_var_map[i].get())[0])+" px"

            self.wid[i].configure(text=txt1[i])
            self.hig[i].configure(text=txt2[i])

            self.set[i].configure(command=lambda fl_name=self.entr_var_map[i].get(),j=i: self.canv(fl_name,j))

        for j in range(self.img_num_var.get(),6):
            for child in self.frame[j].winfo_children():
                child.configure(state='disabled')


    def scaling(self,a,b,c,j):

        try:
            vd=float(self.ver_distance_var[j].get())

            matrix_height=int(count(self.entr_var_map[j].get())[0])

            v_scale="{:.2f}".format(matrix_height/abs(vd))

        except ValueError:
            self.ver_scale[j].configure(text="")
            self.exe.configure(state="disabled")

        except ZeroDivisionError:
            self.ver_scale[j].configure(text="")
            self.exe.configure(state="disabled")

        else:

            txt=v_scale+" px/um"

            self.ver_scale[j].configure(text=txt)
            self.ver_var[j].set(matrix_height/abs(vd))


        try:
            hd=float(self.hor_distance_var[j].get())

            matrix_width=int(count(self.entr_var_map[j].get())[1])

            h_scale="{:.2f}".format(matrix_width/abs(hd))

        except ValueError:
            self.hor_scale[j].configure(text="")
            self.exe.configure(state="disabled")

        except ZeroDivisionError:
            self.hor_scale[j].configure(text="")
            self.exe.configure(state="disabled")

        else:

            txt=h_scale+" px/um"

            self.hor_scale[j].configure(text=txt)
            self.hor_var[j].set(matrix_width/abs(hd))


    def canv(self,fl_name,num):

        top4=self.top4=Toplevel(self.top3)
        
        top4.grab_set()

        mat=[]
        in_file=open(fl_name,"r")
        mat=[line.split() for line in in_file]

        self.fig=plt.figure()
        self.sbplt=self.fig.add_subplot(111)

        X=np.arange(1,len(mat)+1)
        Y=np.arange(1,len(mat[0])+1)
        X,Y=np.meshgrid(X,Y)

        for x in range(0,len(mat)):

            for y in range(0,len(mat[0])):

                 mat[x][y]=float(mat[x][y])

        im=plt.imshow(mat,cmap="bone")
        self.fig.suptitle(fl_name)


        self.frame=Frame(self.top4)
        self.frame.grid(row=0,column=0,rowspan=20)


        self.canvas=FigureCanvasTkAgg(self.fig,self.frame)
        self.canvas.show()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=True)


        toolbar = NavigationToolbar2TkAgg(self.canvas,self.frame)
        toolbar.update()
        toolbar.pack(side=BOTTOM)
        self.canvas._tkcanvas.pack(side=BOTTOM, fill=BOTH, expand=True)

        en=Button(top4,text="Ending point",command=self.click_en,width=10)
        en.grid(row=10,column=1)

        
        st=Button(top4,text="Starting point",command=self.click_st,width=10)
        st.grid(row=6,column=1)


        self.clr=Button(top4,text="Clear",command=lambda: self.clear(num),width=5)
        self.clr.grid(row=16,column=1)


        self.ok=Button(top4,text="OK",command=lambda: self.close_canvas(num),width=5)
        self.ok.grid(row=18,column=1)
        self.ok.configure(state="disabled")

        self.en_lab=Label(top4)
        self.st_lab=Label(top4)
        self.en_lab.grid(row=11,column=1)
        self.st_lab.grid(row=7,column=1)

        self.st_x_var=StringVar()
        self.st_y_var=StringVar()
        self.en_x_var=StringVar()
        self.en_y_var=StringVar()

        try:
            self.circ_s=patches.Circle((int(self.sp_x_var[num].get()),int(self.sp_y_var[num].get())),radius=5,color="green",fill=True)
            self.sbplt.add_patch(self.circ_s)

            self.circ_e=patches.Circle((int(self.ep_x_var[num].get()),int(self.ep_y_var[num].get())),radius=5,color="red",fill=True)
            self.sbplt.add_patch(self.circ_e)

            txt_s="X "+self.sp_x_var[num].get()+" Y "+self.sp_y_var[num].get()
            self.st_lab.configure(text=txt_s)

            txt_e="X "+self.ep_x_var[num].get()+" Y "+self.ep_y_var[num].get()
            self.en_lab.configure(text=txt_e)

            self.st_x_var.set(self.sp_x_var[num].get())
            self.st_y_var.set(self.sp_y_var[num].get())
            self.en_x_var.set(self.ep_x_var[num].get())
            self.en_y_var.set(self.ep_y_var[num].get())

        except AttributeError:
            pass
        except ValueError:
            pass

        else:
            self.ok.configure(state="normal")
            self.canvas.draw()

        self.top3.wait_window(top4)


    def clear(self,i):
        
        self.en_lab.configure(text='')
        self.st_lab.configure(text='')
        self.st_x_var.set("")
        self.st_y_var.set("")
        self.en_x_var.set("")
        self.en_y_var.set("")
        self.ok.configure(state="disabled")

        try:
            self.circ_e.remove()
        except AttributeError:
            pass

        try:
            self.circ_s.remove()
        except AttributeError:
            pass

        self.canvas.draw()

        self.sp_x_var[i].set('')
        self.sp_y_var[i].set('')
        self.ep_x_var[i].set('')
        self.ep_y_var[i].set('')
        self.sp_x[i].configure(text='')
        self.sp_y[i].configure(text='')
        self.ep_x[i].configure(text='')
        self.ep_y[i].configure(text='')

        self.clr.configure(state="disabled")


    def canv_click_en(self,event):

        try:
            self.circ_e.remove()
        except AttributeError:
            pass
        except ValueError:
            pass

        try:
            txt="X "+str(rnd(event.xdata))+" Y "+str(rnd(event.ydata))
            self.en_lab.configure(text=txt)

            self.circ_e=patches.Circle((event.xdata,event.ydata),radius=5,color="red",fill=True)
            self.sbplt.add_patch(self.circ_e)
            self.canvas.draw()

            self.en_x_var.set(str(rnd(event.xdata)))
            self.en_y_var.set(str(rnd(event.ydata)))

        except TypeError:
            pass

        self.canvas.mpl_disconnect(self.cid_en)
        self.frame.configure(cursor="")
        self.clr.configure(state="normal")

        if self.st_x_var.get()!='' and self.st_y_var.get()!='' and self.en_x_var.get()!='' and self.en_y_var.get()!='':
            self.ok.configure(state="normal")
        

    def canv_click_st(self,event):

        try:
            self.circ_s.remove()
        except AttributeError:
            pass
        except ValueError:
            pass


        try:
            txt="X "+str(rnd(event.xdata))+" Y "+str(rnd(event.ydata))
            self.st_lab.configure(text=txt)

            self.circ_s=patches.Circle((event.xdata,event.ydata),radius=5,color="green",fill=True)
            self.sbplt.add_patch(self.circ_s)
            self.canvas.draw()

            self.st_x_var.set(str(rnd(event.xdata)))
            self.st_y_var.set(str(rnd(event.ydata)))
            
        except TypeError:
            pass

        self.canvas.mpl_disconnect(self.cid_st)
        self.frame.configure(cursor="")
        self.clr.configure(state="normal")

        if self.st_x_var.get()!='' and self.st_y_var.get()!='' and self.en_x_var.get()!='' and self.en_y_var.get()!='':
            self.ok.configure(state="normal")

        
    def click_en(self):

        try:
            self.canvas.mpl_disconnect(self.cid_en)
            self.canvas.mpl_disconnect(self.cid_st)
        except AttributeError:
            pass

        self.frame.configure(cursor="cross")
        self.cid_en=self.canvas.mpl_connect('button_press_event',lambda event: self.canv_click_en(event))


    def click_st(self):

        try:
            self.canvas.mpl_disconnect(self.cid_en)
            self.canvas.mpl_disconnect(self.cid_st)
        except AttributeError:
            pass

        self.frame.configure(cursor="cross")
        self.cid_st=self.canvas.mpl_connect('button_press_event',lambda event: self.canv_click_st(event))
    

    def close_canvas(self,k):

        self.sp_x_var[k].set(self.st_x_var.get())
        self.sp_y_var[k].set(self.st_y_var.get())
        self.sp_x[k].configure(text="X "+self.st_x_var.get())
        self.sp_y[k].configure(text="Y "+self.st_y_var.get())
        self.ep_x_var[k].set(self.en_x_var.get())
        self.ep_y_var[k].set(self.en_y_var.get())
        self.ep_x[k].configure(text="X "+self.en_x_var.get())
        self.ep_y[k].configure(text="Y "+self.en_y_var.get())
        
        self.top4.destroy()
        plt.close(self.fig)
    
    
    def multi_fil(self):
        mapping_files=[]
        data_files=[]
        h_scales=[]
        v_scales=[]
        s_distances=[]
        st_points=[]
        en_points=[]
        tols=[]
        revs=[]

        if not self.clust_rb_var.get():
            self.clust_size_var.set(1)

        for i in range(0,self.img_num_var.get()):

            mapping_files.append(self.entr_var_map[i].get())
            data_files.append(self.entr_var_data[i].get())
            h_scales.append(self.hor_var[i].get())
            v_scales.append(self.ver_var[i].get())
            s_distances.append(float(self.soma_var[i].get()))
            st_points.append((int(self.sp_x_var[i].get()),int(self.sp_y_var[i].get())))
            en_points.append((int(self.ep_x_var[i].get()),int(self.ep_y_var[i].get())))
            tols.append(self.tolerance_var[i].get())
            revs.append(self.rev_var[i].get())

        self.top1.destroy()
        self.top2.destroy()
        self.top3.destroy()

        multi_filament(mapping_files,data_files,h_scales,v_scales,s_distances,st_points,en_points,int(self.map_box_var.get()),int(self.data_box_var.get()),int(self.clust_size_var.get()),int(self.spac_var.get()),tols,revs,self.out_entry_var.get())
Example #16
0
class labTOF(Frame):

	#define parent window
	def __init__(self, parent):
		#from Tkinter frame:
		#Frame.__init__(self, parent, background="white")   
		#from ttk frame:
		Frame.__init__(self, parent)

		#save a reference to the parent widget
		self.parent = parent

		#delegate the creation of the user interface to the initUI() method
		#self.parent.title("Lab TOF")
		#self.pack(fill=BOTH, expand=1)
		self.fig = Figure(figsize=(4,4), dpi=100)
		#fig = Figure(facecolor='white', edgecolor='white')
		self.fig.subplots_adjust(bottom=0.15, left=0.15)

		self.canvas = FigureCanvasTkAgg(self.fig, self)
		self.toolbar = NavigationToolbar2TkAgg(self.canvas, self)
		self.toolbar.pack(side=TOP)
		#canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True) 
		
		#list containing time domain values
		self.time=[]
		#list containing mass domain values
		self.mass=[]
		#flag to indicate whether time or mass is displayed
		#time flag=0
		#mass flag=1
		self.time_mass_flag=0
		#flag to indicate MS or MSMS calibration
		#MS = 0
		#MSMS = 1
		self.MSMS_flag=-99
		#list containing intensity values
		self.intensity=[]
		#list containing calibration values
		self.cal_time=[]
		self.cal_mass=[]
		self.label_mass=[]
		self.label_time=[]
		self.label_intensity=[]
		#calibration point id
		self.cid=-99
		self.initUI()
		#zero mass corresponds to ~40% of parent mass time
		self.MSMS_zero_time=0.40838#0.4150#0.4082
        
        
	#container for other widgets
	def initUI(self):
		#set the title of the window using the title() method
		self.parent.title("Lab TOF")
		
		#apply a theme to widget
		self.style = Style()
		self.style.theme_use('default')
		
		#the Frame widget (accessed via the delf attribute) in the root window
		#it is expanded in both directions
		#CHANGE all pack to grid layout
		self.pack(fill=BOTH, expand=1)

		menubar = Menu(self.parent)
		self.parent.config(menu=menubar)
		
		#contains file menu items
		fileMenu = Menu(menubar, tearoff=0)
		menubar.add_cascade(label="File", menu=fileMenu)
		fileMenu.add_command(label="Open", command=self.onOpen)
		fileMenu.add_command(label="Export Data (ASCII file)", command=self.onExport)
		fileMenu.add_command(label="Quit", command=self.quit_destroy)

		#contains calibration menu items
		#"self" is needed to access items later (to change state)
		#default state for save calibration is disabled
		#state is enabled once a file is loaded
		self.calMenu=Menu(menubar, tearoff=0)     
		menubar.add_cascade(label="Calibration", menu=self.calMenu)        
		self.MScalMenu=Menu(menubar, tearoff=0)
		self.calMenu.add_cascade(label="MS Calibration", menu=self.MScalMenu, state=DISABLED)
		self.MScalMenu.add_command(label="Start New Calibration", command=self.onCalStart)
		self.MScalMenu.add_command(label="Open Calibration File", command=self.onOpenCal)
		
		self.MSMScalMenu=Menu(menubar, tearoff=0)
		self.calMenu.add_cascade(label="MSMS Calibration", menu=self.MSMScalMenu, state=DISABLED)
		self.MSMScalMenu.add_command(label="Start New Calibration", command=self.onMSMSCalStart)
		self.MSMScalMenu.add_command(label="Open Calibration File", command=self.onMSMSOpenCal)

		#default state for save calibration is disabled
		#state is enabled once a calibration is defined
		self.calMenu.add_command(label="Save Calibration File", command=self.onSaveCal, state=DISABLED)


		#generate figure (no data at first)
		self.generate_figure([0,1], [[],[]], ' ')
		
		#create instance of the button widget
		#command specifies the method to be called
		quitButton = Button(self, text="Quit", command = self.quit_destroy)
		#quitButton.place(x=50, y=50)
		quitButton.pack(side=RIGHT, padx=5, pady=5)
		#quitButton.grid(row=5, column=5, padx=5)

		#convert to time domain
		timeButton = Button(self, text="Time Domain", command = self.time_domain)
		timeButton.pack(side=RIGHT, padx=5, pady=5)

		#convert to mass domain
		self.massButton = Button(self, text="Mass Domain", command = self.mass_domain, state=DISABLED)
		self.massButton.pack(side=RIGHT, padx=5, pady=5)

		#smooth spectrum
		self.smoothButton = Button(self, text="Smooth", command = self.smooth_data, state=DISABLED)
		self.smoothButton.pack(side=RIGHT, padx=5, pady=5)

		#label peaks in figure
		self.labelButton = Button(self, text="Label Peak", command = self.label_peaks, state=DISABLED)
		self.labelButton.pack(side=RIGHT, padx=5, pady=5)

		self.deletelabelButton = Button(self, text="Remove Labels", command = self.delete_labels, state=DISABLED)
		self.deletelabelButton.pack(side=RIGHT, padx=5, pady=5)
		

		#calibration
		#identify parent peak in MSMS
		self.parentButton = Button(self, text="Identify Parent Peak", command = self.calibrate_parent, state=DISABLED)
		self.parentButton.pack(side=LEFT, padx=5, pady=5)
		#add calibration point
		self.calibrateButton = Button(self, text="Add Calibration Point", command = self.calibrate, state=DISABLED)
		self.calibrateButton.pack(side=LEFT, padx=5, pady=5)

		#finish calibration and convert to mass domain
		self.finishcalButton = Button(self, text="Finish Calibration", command = self.finish_calibrate, state=DISABLED)
		self.finishcalButton.pack(side=LEFT, padx=5, pady=5)
		

	#convert to mass domain
	#disabled until calibration is defined
	def mass_domain(self):
		self.time_mass_flag=1
		self.generate_figure([self.mass,self.intensity], [self.label_mass, self.label_intensity], 'mass (Da)')
	
	#convert to time domain	
	def time_domain(self):
		self.time_mass_flag=0
		#plot in micro seconds
		self.generate_figure([[1E6*x for x in self.time],self.intensity], [self.label_time, self.label_intensity], 'time ($\mu$s)')
		
	#smooth data
	def smooth_data(self):
		#smooth self.time/mass/int variables - permanant
		#probably not a good idea
		#purpose of smoothing function: to display smoothed plot
		self.SmoothDialog(self.parent)
		#wait for dialog to close
		self.top.wait_window(self.top)
		smoothed_signal = scipy.signal.savgol_filter(self.intensity,self.window,self.poly)
		#convert from array to list
		self.intensity=smoothed_signal.tolist()
		#print 'intensity: ', len(self.intensity), type(self.intensity)
		if self.time_mass_flag == 1:
			#print 'mass: ', len(self.mass), type(self.mass)
			self.mass_domain()
		else:
			#print 'time: ', len(self.time), type(self.time)
			self.time_domain()

	#plot figure
	def generate_figure(self, data, label, xaxis_title):
		#clear figure
		plt.clf()
		ax = self.fig.add_subplot(111)
		#clear axis
		ax.cla()
		spectrum=ax.plot(data[0],data[1])
		ax.set_xlabel(xaxis_title)
		ax.set_ylabel('intensity')
		#add peak labels
		for index, label_x in enumerate(label[0]):
			#ax.text(0.94*label_x, 1.05*label[1][index], str("%.1f" % label_x))
			#ax.annotate(str("%.1f" % label_x), xy=(label_x, label[1][index]), xytext=(1.1*label_x, 1.1*label[1][index]), arrowprops=dict(facecolor='black', shrink=0.1),)
			#ax.annotate(str("%.1f" % label_x), xy=(label_x, label[1][index]), xytext=(1.0*label_x, 1.2*label[1][index]),)
			an1 = ax.annotate(str("%.1f" % label_x), xy=(label_x, label[1][index]), xytext=(label_x, label[1][index]), fontsize=12)
			an1.draggable()
		
		#remove self.label_time values
		#set label_peaks to generate figure again with loop that allows peak labeling (datacursor()) - set flag, reset flag in loop
		##otherwise label will appear when selecting peaks for calibration
		#have Tim download mpldatacursor package with pip?
		#need to figure out how to remove labels
		##canvas.delete("all") in function with a redraw function?
		#datacursor(spectrum, display='multiple', draggable=True, formatter='{x:.1f}'.format, bbox=None)
		
		self.canvas.show()
		self.canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)
		#self.can.grid(row=1, column=0, columnspan=6, rowspan=3, padx=5, sticky=E+W+S+N)

		self.toolbar.update()
		self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=True)

	#def delete_figure(self):
		#Canvas.delete("all")
		#.destroy()

	#open file
	def onOpen(self):
		#displays .txt files in browser window
		#only reads time domain data files
		ftypes = [('binary files', '*.trc'), ('txt files', '*.txt')]
		dlg = tkFileDialog.Open(self, filetypes = ftypes)
		fl = dlg.show()
		
		if fl != '':
			if fl[-3:] == 'trc':
				self.time, self.intensity = read_lecroy_binary.read_timetrace(fl)
			elif fl[-3:] == 'txt':
				data = self.readFile(fl)
				self.time=data[0]
				self.intensity=data[1]
			#plots data in time domain
			self.time_domain()
			self.labelButton.config(state=NORMAL)
			self.deletelabelButton.config(state=NORMAL)
			#allows for smoothing of data
			self.smoothButton.config(state=NORMAL)
			#allows for calibration
			self.calMenu.entryconfig("MS Calibration", state=NORMAL)
			self.calMenu.entryconfig("MSMS Calibration", state=NORMAL)

	#export data to txt file
	def onExport(self):
		#save header info (date/time, ask user for instrument)?
		#ask for save file name
		savefile = tkFileDialog.asksaveasfile(mode='wb', defaultextension=".txt")
		# asksaveasfile return `None` if dialog closed with "cancel".
		if savefile is None:
			return
		#export mass or time domain data depending on flag (what is plotted)
		if self.time_mass_flag == 0:
			x=self.time
		else:
			x=self.mass
		y=self.intensity
		
		for i in range(len(x)):
			savefile.write(str(x[i]))
			savefile.write(' ')
			savefile.write(str(y[i]))
			savefile.write('\r\n')
		savefile.close()

	#save calibration file
	def onSaveCal(self):
		#ask for save file name
		savefile = tkFileDialog.asksaveasfile(mode='wb', defaultextension=".txt")
		if savefile is None:
			return
		
		#write header information?
		#date/time, file name
		for i in range(len(self.cal_time)):
			savefile.write(str(self.cal_time[i]))
			savefile.write(' ')
			savefile.write(str(self.cal_mass[i]))
			#\r\n is the newline character for windows
			savefile.write('\r\n')
		savefile.close()
		
	#open previous MS (regular) calibration file
	def onOpenCal(self):
		#display .txt files in browser window
		ftypes = [('txt files', '*.txt')]
		dlg = tkFileDialog.Open(self, filetypes = ftypes)
		filename = dlg.show()

		if filename != '':
			#list with time calibration value
			calt_read=[]
			#list with mass calibration value
			calm_read=[]
			file=open(filename,'r')
			#header=file.readline()
			for line in file:
				#read each row - store data in columns
				temp = line.split(' ')
				calt_read.append(float(temp[0]))
				calm_read.append(float(temp[1].rstrip('/n')))
			#store values in calibration lists
			self.cal_time=calt_read
			self.cal_mass=calm_read
		#sets MSMS flag for finish_calibrate routine
		self.MSMS_flag=0
		#call finish_calibrate method to calibrate and plot data in mass domain
		self.finish_calibrate()

	#open previous MSMS calibration file
	def onMSMSOpenCal(self):
		#display .txt files in browser window
		ftypes = [('txt files', '*.txt')]
		dlg = tkFileDialog.Open(self, filetypes = ftypes)
		filename = dlg.show()

		if filename != '':
			#list with time calibration value
			calt_read=[]
			#list with mass calibration value
			calm_read=[]
			file=open(filename,'r')
			#header=file.readline()
			for line in file:
				#read each row - store data in columns
				temp = line.split(' ')
				calt_read.append(float(temp[0]))
				calm_read.append(float(temp[1].rstrip('/n')))
			#store values in calibration lists
			self.cal_time=calt_read
			self.cal_mass=calm_read
		#sets MSMS flag for finish_calibrate routine
		self.MSMS_flag=1
		#call finish_MSMScalibrate method to calibrate and plot data in mass domain
		self.finish_calibrate()

	#called when "Start New Calibration" is selected from MS cascade
	def onCalStart(self):
		#sets MSMS flag for finish_calibrate routine
		self.MSMS_flag=0
		#reset calibration points
		self.cal_time=[]
		self.cal_mass=[]
		#sets (0,0) as default
		self.cal_time.append(0)
		self.cal_mass.append(0)
		#plot data in time domain (reset plot)
		self.time_domain()
		#set calibration buttons (add new, finish) to enabled state
		self.calibrateButton.config(state=NORMAL)
		self.finishcalButton.config(state=NORMAL)

	#called when "Start New Calibration" is selected in MSMS mode
	def onMSMSCalStart(self):
		#sets MSMS flag for finish_calibrate routine
		self.MSMS_flag=1
		#reset calibration points
		self.cal_time=[]
		self.cal_mass=[]
		#plot data in time domain (reset plot)
		self.time_domain()
		#set calibration button (ID parent peak, finish) to enabled state
		self.parentButton.config(state=NORMAL)
		self.finishcalButton.config(state=NORMAL)


	#called when click is made in plotting environment during calibration
	def on_click(self, event):	
		temp_len=len(self.cal_time)
		#when the click is made within the plotting window
		if event.inaxes is not None:
			#print 'clicked: ', event.xdata, event.ydata
			self.cal_time.append(event.xdata*1E-6)
			#sets up dialog box for user to enter mass value
			self.MassDialog(self.parent)
		#if click is outside plotting window
		else:
			print 'Clicked ouside axes bounds but inside plot window'		
		#disconnect from calibration click event when a new calibration value is set
		if len(self.cal_time) > temp_len:
			self.canvas.mpl_disconnect(self.cid)

	#called during calibration
	#asks user for mass value associated with time value selected
	def MassDialog(self, parent):
		top = self.top = Toplevel(self.parent)
		Label(top, text="Actual Mass Value:").pack()
		
		self.e=Entry(top)
		self.e.pack(padx=5)
		#calls DialogOK to set mass value to input		
		b=Button(top, text="OK", command=self.DialogOK)
		b.pack(pady=5)
	
	#called when Smooth button is pressed
	#asks user for smooth input data
	def SmoothDialog(self, parent):
		top = self.top = Toplevel(self.parent)
		#window length for smoothing function
		#must be greater than poly value, positive, odd (51)
		Label(top, text="Window Length:").grid(row=0, column=0, sticky=W, padx=5, pady=5)
		self.w=Entry(top)
		self.w.grid(row=0, column=1, padx=5, pady=5)

		#polynomial order
		#must be less than window length (3)
		Label(top, text="Polynomial Order:").grid(row=1, column=0, sticky=W, padx=5, pady=5)
		self.p=Entry(top)
		self.p.grid(row=1, column=1, padx=5, pady=5)
		
		#calls DialogSmoothOK to set these values
		b=Button(top, text="OK", command=self.DialogSmoothOK)
		b.grid(row=2, column=1, padx=5, pady=5)
	
	#called from smooth dialog box within smooth routine
	def DialogSmoothOK(self):
		#sets user-defined window length
		self.window=float(self.w.get())
		#sets user-defined polynomail order
		self.poly=float(self.p.get())
		self.top.destroy()
		
	#called from mass dialog box within calibration routine
	def DialogOK(self):
		#sets user-defined mass calibration value to mass cal list
		self.cal_mass.append(float(self.e.get()))
		#closes dialog box
		self.top.destroy()
	
	#called from calibration routine
	#stores user-selected point in cid	
	def calibrate(self):
		#user selects point
		self.cid=self.canvas.mpl_connect('button_press_event', self.on_click)
		
		
	#called from MSMS calibration routine
	#stores user-selected point in cid	
	def calibrate_parent(self):
		#user selects point
		self.cid=self.canvas.mpl_connect('button_press_event', self.on_click)
		self.parentButton.config(state=DISABLED)
		

	#called from calibration routine after "finish" button is pressed
	def finish_calibrate(self):
		#disables buttons until "start new calibration" is selected
		self.calibrateButton.config(state=DISABLED)
		self.finishcalButton.config(state=DISABLED)
		#allows plotting in mass domain
		self.massButton.config(state=NORMAL)
		#for MSMS calibration
		if self.MSMS_flag==1:
			#add second calibration time point equal to some percentage of parent peak time
			self.cal_time.append(self.cal_time[0]*self.MSMS_zero_time)
			self.cal_mass.append(0)
		#allows user to save calibration file
		self.calMenu.entryconfig("Save Calibration File", state=NORMAL)
		
		#if MS mode (regular)
		if self.MSMS_flag==0:
			#fit quadratic fuction through cal points
			popt, pcov = curve_fit(func_quad, self.cal_time, self.cal_mass)
			#convert time to mass
			self.mass[:] = [popt[0]*(x**2)*(1E10) + popt[1] for x in self.time]

		#if MSMS mode
		elif self.MSMS_flag==1:
			#fit quadratic fuction through cal points
			popt, pcov = curve_fit(func_lin, self.cal_time, self.cal_mass)
			#convert time to mass
			self.mass[:] = [popt[0]*x*(1E10) + popt[1] for x in self.time]
			#discard all data below 0 mass
			mass_temp=self.mass
			int_temp=self.intensity
			time_temp=self.time
			self.mass=[]
			self.intensity=[]
			self.time=[]
			for index, mass in enumerate(mass_temp):
				if mass > 0:
					self.mass.append(mass)
					self.intensity.append(int_temp[index])
					self.time.append(time_temp[index])
			
		#plots figure in mass domain
		self.mass_domain()


	#function for file input
	def readFile(self, filename):
		file=open(filename,'r')
		#there is some extra formatting on the first line - delete this data
		header=file.readline()
		header=file.readline()
		header=file.readline()
		header=file.readline()
		header=file.readline()
		#read each row in the file
		#list for temporary time data
		time=[]
		#list for temporary intensity data
		intensity=[]
		for line in file:
			#check file format:
			if ',' in line:
				#read each row - store data in columns
				temp = line.split(',')
				time.append(float(temp[0]))
				intensity.append(float(temp[1].rstrip('/n')))
			if '\t' in line:
				temp = line.split('\t')
				time.append(float(temp[0]))
				intensity.append(float(temp[1].rstrip('/n')))

		data=[time, intensity]
		return data

	#function to label peaks on figure in order to save figure as an image file with labels
	def label_peaks(self):
		#ask for peak (on_click_label)
		self.cid=self.canvas.mpl_connect('button_press_event', self.on_click_label)
	
	#remove peak labels when button is selected
	def delete_labels(self):
		#deletes peak label arrays
		self.label_time=[]
		self.label_mass=[]
		self.label_intensity=[]
		#if time flag is set
		if self.time_mass_flag==0:
			self.time_domain()
		elif self.time_mass_flag==1:
			self.mass_domain()
		
	#called when click is made to label peak
	def on_click_label(self, event):
		temp_len=len(self.label_intensity)
		#if time flag is set
		if self.time_mass_flag==0:
			#temp_len=len(self.label_time)
			#when the click is made within the plotting window
			if event.inaxes is not None:
				#print 'clicked: ', event.xdata, event.ydata
				self.label_time.append(event.xdata)
				self.label_intensity.append(event.ydata)
				#print 'time: ', self.label_time
				#print 'intensity: ', self.label_intensity
				self.time_domain()
			#if click is outside plotting window
			else:
				print 'Clicked ouside axes bounds but inside plot window'		
		#if the mass flag is set
		elif self.time_mass_flag==1:
			#temp_len=len(self.label_mass)
			#when the click is made within the plotting window
			if event.inaxes is not None:
				#print 'clicked: ', event.xdata, event.ydata
				self.label_mass.append(event.xdata)
				self.label_intensity.append(event.ydata)
				#print 'mass: ', self.label_mass
				#print 'intensity: ', self.label_intensity
				self.mass_domain()
			#if click is outside plotting window
			else:
				print 'Clicked ouside axes bounds but inside plot window'		
		#self.peak_intensity=event.ydata
		#plot label
		
		#disconnect from click event when a new peak label value is set
		if temp_len < len(self.label_intensity):
			self.canvas.mpl_disconnect(self.cid)


	#need to destroy parent before quitting, otherwise python crashes on Windows
	def quit_destroy(self):
		self.parent.destroy()
		self.parent.quit()
Example #17
0
class TaskerCanvas(ttk.Frame):
    """
    Displays the map and plot

    :ivar TaskerGui parent: The parent application
    :ivar int canvas_width: The width of the canvas
    :ivar int canvas_height: The height of the canvas
    :ivar TaskerOrbitPlotter plotter: Manages orbit data and plotting for the canvas
    :ivar FigureCanvasTkAgg canvas: The canvas

    :param int width: The desired width of the canvas
    :param int height: The desired height of the canvas
    """
    def __init__(self, mainframe, width=500, height=500):
        ttk.Frame.__init__(self, master=mainframe)

        self.parent = mainframe
        
        # Vertical and horizontal scrollbars for canvas
        vbar = tk.Scrollbar(self, orient='vertical')
        hbar = tk.Scrollbar(self, orient='horizontal')
        
        # Create canvas and put map on it
        self.canvas_width = width
        self.canvas_height = height

        self.plotter = TaskerOrbitPlotter(self)
        fig = self.plotter.show()
        t = np.arange(0, 3, .01)
        self.canvas = FigureCanvasTkAgg(fig, master = mainframe)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side="top",fill=tk.BOTH,expand=True)

    def enableZoomIn(self):
        """
        Enables zooming in when clicking on the map and changes the cursor.
        """
        self.zoomInID = self.canvas.mpl_connect('button_press_event', self.onZoomIn)
        self.master.config(cursor = "cross")

    def disableZoomIn(self):
        """
        Disables zooming in. Changes cursor back to normal.
        """
        self.canvas.mpl_disconnect(self.zoomInID)
        self.master.config(cursor = "arrow")

    def enableZoomOut(self):
        """
        Enables zooming out when clicking on the map and changes the cursor.
        """
        self.zoomOutID = self.canvas.mpl_connect('button_press_event', self.onZoomOut)
        self.master.config(cursor = "cross")

    def disableZoomOut(self):
        """
        Disables zooming out. Changes cursor back to normal.
        """
        self.canvas.mpl_disconnect(self.zoomOutID)
        self.master.config(cursor = "arrow")

    
    def onZoomIn(self, event):
        """
        Called when the map is clicked. Zooms in on the quadrant clicked on.
        """
        try:
            print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
                ('double' if event.dblclick else 'single', event.button,
                event.x, event.y, event.xdata, event.ydata))
        except:
            return


        self.plotter.zoomIn(event)

    def onZoomOut(self, event):
        """
        Called when the map is clicked. Zooms out by one zoom level.
        """
        self.plotter.zoomOut(event)
            
    def on_resize_parent(self,event):
        """
        Called when app is resized
        """
        #print("parent event size="+str(event.width)+" X "+str(event.height))
        self.canvas_width = event.width
        self.canvas_height = event.height
        self.canvas.get_tk_widget().config(width=self.canvas_width, height=self.canvas_height)
        self.show_image()
        
    def on_resize_parentx(self,event):
        """
        Called only by Panedwindow to resize in x-dir only.
        """
        ##print("parent event size="+str(event.width)+" X "+str(event.height))
        self.canvas_width = event.width
        self.canvas.get_tk_widget().config(width=self.canvas_width)
        self.show_image()
 
    def event_subscribe(self, obj_ref):
        """
        Subscribes obj_ref to the TaskerGui.

        :param obj_ref: object to be subscribed to TaskerGui
        """
        self.subscribers.append(obj_ref)
    
    def event_publish(self, cmd):
        """
        Publishes an event to all subscribers

        :param str cmd: Command to be published
        """
        for sub in self.subscribers:
            sub.event_receive(cmd)
    
    def event_receive(self,event):
        """
        Receives an event from a subscription

        :param event: The event received from a subscription
        """

        pass
Example #18
0
class wishbone_gui(tk.Tk):
    def __init__(self,parent):
        tk.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def initialize(self):
        self.grid()
        self.vals = None
        self.currentPlot = None

        #set up menu bar
        self.menubar = tk.Menu(self)
        self.fileMenu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="File", menu=self.fileMenu)
        self.fileMenu.add_command(label="Load data", command=self.loadData)
        self.fileMenu.add_command(label="Save data", state='disabled', command=self.saveData)
        self.fileMenu.add_command(label="Exit Wishbone", command=self.quitWB)

        self.analysisMenu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Analysis", menu=self.analysisMenu)
        self.analysisMenu.add_command(label="Principal component analysis", state='disabled', command=self.runPCA)
        self.analysisMenu.add_command(label="tSNE", state='disabled', command=self.runTSNE)
        self.analysisMenu.add_command(label="Diffusion map", state='disabled', command=self.runDM)
        self.analysisMenu.add_command(label="GSEA", state='disabled', command=self.runGSEA)
        self.analysisMenu.add_command(label="Wishbone", state='disabled', command=self.runWishbone)

        self.visMenu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="Visualization", menu=self.visMenu)
        self.visMenu.add_command(label="Principal component analysis", state='disabled', command=self.plotPCA)
        self.visMenu.add_command(label="tSNE", state='disabled', command=self.plotTSNE)
        self.visMenu.add_command(label="Diffusion map", state='disabled', command=self.plotDM)
        self.visMenu.add_command(label="GSEA Results", state='disabled', command=self.showGSEAResults)
        self.wishboneMenu = tk.Menu(self)
        self.visMenu.add_cascade(label="Wishbone", menu=self.wishboneMenu)
        self.wishboneMenu.add_command(label="On tSNE", state='disabled', command=self.plotWBOnTsne)
        self.wishboneMenu.add_command(label="Marker trajectory", state='disabled', command=self.plotWBMarkerTrajectory)
        self.wishboneMenu.add_command(label="Heat map", state='disabled', command=self.plotWBHeatMap)
        self.visMenu.add_command(label="Gene expression", state='disabled', command=self.plotGeneExpOntSNE)
        self.visMenu.add_command(label="Set gate", state='disabled', command=self.setGate)
        
        self.config(menu=self.menubar)

        #intro screen
        tk.Label(self, text=u"Wishbone", font=('Helvetica', 48), fg="black", bg="white", padx=100, pady=50).grid(row=0)
        tk.Label(self, text=u"To get started, select a data file by clicking File > Load Data", fg="black", bg="white", padx=100, pady=25).grid(row=1)

        #update
        self.protocol('WM_DELETE_WINDOW', self.quitWB)
        self.grid_columnconfigure(0,weight=1)
        self.resizable(True,True)
        self.update()
        self.geometry(self.geometry())       
        self.focus_force()

    def loadData(self):
        self.dataFileName = filedialog.askopenfilename(title='Load data file', initialdir='~/.wishbone/data')
        if(self.dataFileName != ""):
            #pop up data options menu
            self.fileInfo = tk.Toplevel()
            self.fileInfo.title("Data options")
            tk.Label(self.fileInfo, text=u"File name: ").grid(column=0, row=0)
            tk.Label(self.fileInfo, text=self.dataFileName.split('/')[-1]).grid(column=1, row=0)

            tk.Label(self.fileInfo,text=u"Name:" ,fg="black",bg="white").grid(column=0, row=1)
            self.fileNameEntryVar = tk.StringVar()
            tk.Entry(self.fileInfo, textvariable=self.fileNameEntryVar).grid(column=1,row=1)

            if self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'fcs':
                tk.Label(self.fileInfo,text=u"Cofactor:" ,fg="black",bg="white").grid(column=0, row=2)
                self.cofactorVar = tk.IntVar()
                self.cofactorVar.set(5)
                tk.Entry(self.fileInfo, textvariable=self.cofactorVar).grid(column=1,row=2)
            elif self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'csv':
                self.normalizeVar = tk.BooleanVar()
                tk.Checkbutton(self.fileInfo, text=u"Normalize", variable=self.normalizeVar).grid(column=0, row=2, columnspan=2)
                tk.Label(self.fileInfo, text=u"The normalize parameter is used for correcting for library size among cells.").grid(column=0, row=3, columnspan=2)

            tk.Button(self.fileInfo, text="Cancel", command=self.fileInfo.destroy).grid(column=0, row=4)
            tk.Button(self.fileInfo, text="Load", command=self.processData).grid(column=1, row=4)

            self.wait_window(self.fileInfo)

    def processData(self):
        #clear intro screen
        for item in self.grid_slaves():
            item.grid_forget()

        #display file name
        tk.Label(self,text=u"File name: " + self.fileNameEntryVar.get(), fg="black",bg="white").grid(column=0,row=0)

        #set up canvas for plots
        self.fig, self.ax = wishbone.wb.get_fig()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='NSEW')
        tk.Label(self, text=u"Visualizations:", fg='black', bg='white').grid(column=0, row=1)

        #load data based on input type
        if self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'fcs':    # mass cytometry data
            self.scdata = wishbone.wb.SCData.from_fcs(os.path.expanduser(self.dataFileName), 
                                                      cofactor=self.cofactorVar.get())
            self.wb = None
        elif self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'csv': # sc-seq data
            self.scdata = wishbone.wb.SCData.from_csv(os.path.expanduser(self.dataFileName), data_type='sc-seq', 
                                                      normalize=self.normalizeVar.get())
            self.wb = None
        else:
            self.wb = wishbone.wb.Wishbone.load(self.dataFileName)
            self.scdata = self.wb.scdata

        #set up buttons based on data type
        if self.scdata.data_type == 'sc-seq':
            self.PCAButton = tk.Button(self, text=u"PCA", state='disabled', command=self.plotPCA)
            self.PCAButton.grid(column=0, row=2)
            self.tSNEButton = tk.Button(self, text=u"tSNE", state='disabled', command=self.plotTSNE)
            self.tSNEButton.grid(column=0, row=3)
            self.DMButton = tk.Button(self, text=u"Diffusion map", state='disabled', command=self.plotDM)
            self.DMButton.grid(column=0, row=4)
            self.GSEAButton = tk.Button(self, text=u"GSEA Results", state='disabled', command=self.showGSEAResults)
            self.GSEAButton.grid(column=0, row=5)
            self.WBButton = tk.Button(self, text=u"Wishbone", state='disabled', command=self.plotWBOnTsne)
            self.WBButton.grid(column=0, row=6)
            self.geneExpButton = tk.Button(self, text=u"Gene expression", state='disabled', command=self.plotGeneExpOntSNE)
            self.geneExpButton.grid(column=0, row=7)
            self.setGateButton = tk.Button(self, text=u"Set gate", state='disabled', command=self.setGate)
            self.setGateButton.grid(column=0, row=8)
            self.saveButton = tk.Button(self, text=u"Save plot", state='disabled', command=self.savePlot)
            self.saveButton.grid(column = 4, row=0)
            self.diff_component = tk.StringVar()
            self.diff_component.set('Component 1')
            self.component_menu = tk.OptionMenu(self, self.diff_component,
                                                'Component 1', 'Component 2', 'Component 3',
                                                'Component 4', 'Component 5', 'Component 6', 
                                                'Component 7', 'Component 8', 'Component 9')
            self.component_menu.config(state='disabled')
            self.component_menu.grid(row=0, column=2)
            self.updateButton = tk.Button(self, text=u"Update component", command=self.updateComponent, state='disabled')
            self.updateButton.grid(column=3, row=0)

            #enable buttons based on current state of scdata object
            if self.scdata.pca:
                self.analysisMenu.entryconfig(1, state='normal')
                self.visMenu.entryconfig(0, state='normal')
                self.PCAButton.config(state='normal')
            if isinstance(self.scdata.tsne, pd.DataFrame):
                self.analysisMenu.entryconfig(2, state='normal')
                self.visMenu.entryconfig(1, state='normal')
                self.visMenu.entryconfig(5, state='normal')
                self.tSNEButton.config(state='normal')
                self.geneExpButton.config(state='normal')
            if isinstance(self.scdata.diffusion_eigenvectors, pd.DataFrame):
                self.analysisMenu.entryconfig(3, state='normal')
                self.analysisMenu.entryconfig(4, state='normal')
                self.visMenu.entryconfig(2, state='normal')
                self.DMButton.config(state='normal')
        else:
            self.tSNEButton = tk.Button(self, text=u"tSNE", state='disabled', command=self.plotTSNE)
            self.tSNEButton.grid(column=0, row=2)
            self.DMButton = tk.Button(self, text=u"Diffusion map", state='disabled', command=self.plotDM)
            self.DMButton.grid(column=0, row=3)
            self.WBButton = tk.Button(self, text=u"Wishbone", state='disabled', command=self.plotWBOnTsne)
            self.WBButton.grid(column=0, row=4)
            self.geneExpButton = tk.Button(self, text=u"Gene expression", state='disabled', command=self.plotGeneExpOntSNE)
            self.geneExpButton.grid(column=0, row=5)
            self.setGateButton = tk.Button(self, text=u"Set gate", state='disabled', command=self.setGate)
            self.setGateButton.grid(column=0, row=6)
            self.saveButton = tk.Button(self, text=u"Save plot", state='disabled', command=self.savePlot)
            self.saveButton.grid(column = 4, row=0)

            self.analysisMenu.delete(0)
            self.analysisMenu.delete(2)
            self.visMenu.delete(0)
            self.visMenu.delete(2)
            self.analysisMenu.entryconfig(1, state='normal')

            #enable buttons based on current state of scdata object
            if isinstance(self.scdata.tsne, pd.DataFrame):
                self.visMenu.entryconfig(0, state='normal')
                self.visMenu.entryconfig(3, state='normal')
                self.tSNEButton.config(state='normal')
                self.geneExpButton.config(state='normal')
            if isinstance(self.scdata.diffusion_eigenvectors, pd.DataFrame):
                self.analysisMenu.entryconfig(2, state='normal')
                self.visMenu.entryconfig(1, state='normal')
                self.DMButton.config(state='normal')

        #enable buttons
        self.analysisMenu.entryconfig(0, state='normal')
        self.fileMenu.entryconfig(1, state='normal')
        if self.wb:
                if isinstance(self.wb.trajectory, pd.Series):
                    self.wishboneMenu.entryconfig(0, state='normal')
                    self.wishboneMenu.entryconfig(1, state='normal')
                    self.wishboneMenu.entryconfig(2, state='normal')
                    self.WBButton.config(state='normal')
        #get genes
        self.genes = self.scdata.data.columns.values
        self.gates = {}
        self.geometry('800x550')
        #destroy pop up menu
        self.fileInfo.destroy()

    def saveData(self):
        pickleFileName = filedialog.asksaveasfilename(title='Save Wishbone Data', defaultextension='.p', initialfile=self.fileNameEntryVar.get())
        if pickleFileName != None:
            if self.wb != None:
                self.wb.save(pickleFileName)
            else:
                self.scdata.save_as_wishbone(pickleFileName)

    def runPCA(self):
        self.scdata.run_pca()

        #enable buttons
        self.analysisMenu.entryconfig(1, state='normal')
        self.visMenu.entryconfig(0, state='normal')
        self.PCAButton.config(state='normal')

    def runTSNE(self):
        #pop up for # components
        self.tsneOptions = tk.Toplevel()
        self.tsneOptions.title("tSNE options")
        if self.scdata.data_type == 'sc-seq':
            tk.Label(self.tsneOptions,text=u"Number of components:" ,fg="black",bg="white").grid(column=0, row=0)
            self.nCompVar = tk.IntVar()
            self.nCompVar.set(15)
            tk.Entry(self.tsneOptions, textvariable=self.nCompVar).grid(column=1,row=0)
        tk.Label(self.tsneOptions,text=u"Perplexity:" ,fg="black",bg="white").grid(column=0, row=1)
        self.perplexityVar = tk.IntVar()
        self.perplexityVar.set(30)
        tk.Entry(self.tsneOptions, textvariable=self.perplexityVar).grid(column=1,row=1)
        tk.Button(self.tsneOptions, text="Run", command=self._runTSNE).grid(column=1, row=2)
        tk.Button(self.tsneOptions, text="Cancel", command=self.tsneOptions.destroy).grid(column=0, row=2)
        self.wait_window(self.tsneOptions)

    def _runTSNE(self):
        if self.scdata.data_type == 'sc-seq':
            self.scdata.run_tsne(n_components=self.nCompVar.get(), perplexity=self.perplexityVar.get())
        else:
            self.scdata.run_tsne(n_components=None, perplexity=self.perplexityVar.get())
        self.gates = {}

        #enable buttons
        if self.scdata.data_type == 'sc-seq':
            self.analysisMenu.entryconfig(2, state='normal')
            self.visMenu.entryconfig(1, state='normal')
            self.visMenu.entryconfig(5, state='normal')
        else:
            self.visMenu.entryconfig(0, state='normal')
            self.visMenu.entryconfig(3, state='normal')
        self.tSNEButton.config(state='normal')
        self.geneExpButton.config(state='normal')
        self.tsneOptions.destroy()

    def runDM(self):
        self.scdata.run_diffusion_map()

        #enable buttons
        if self.scdata.data_type == 'sc-seq':
            self.analysisMenu.entryconfig(3, state='normal')
            self.analysisMenu.entryconfig(4, state='normal')
            self.visMenu.entryconfig(2, state='normal')
        else:
            self.analysisMenu.entryconfig(2, state='normal')
            self.visMenu.entryconfig(1, state='normal')
        self.DMButton.config(state='normal')

    def runGSEA(self):
        self.GSEAFileName = filedialog.askopenfilename(title='Select gmt File', initialdir='~/.wishbone/tools')
        if self.GSEAFileName != "":
            self.scdata.run_diffusion_map_correlations()
            self.scdata.data.columns = self.scdata.data.columns.str.upper()
            self.outputPrefix = filedialog.asksaveasfilename(title='Input file prefix for saving output', initialdir='~/.wishbone/gsea')
            if 'mouse' in self.GSEAFileName:
                gmt_file_type = 'mouse'
            else:
                gmt_file_type = 'human'
            self.reports = self.scdata.run_gsea(output_stem= os.path.expanduser(self.outputPrefix), 
                     gmt_file=(gmt_file_type, self.GSEAFileName.split('/')[-1]))
            #enable buttons
            self.visMenu.entryconfig(3, state='normal')
            self.GSEAButton.config(state='normal')

    def runWishbone(self):
        #popup menu for wishbone options
        self.wbOptions = tk.Toplevel()
        self.wbOptions.title("Wishbone Options")

        #s
        tk.Label(self.wbOptions,text=u"Start cell:",fg="black",bg="white").grid(column=0,row=0)
        self.start = tk.StringVar()
        tk.Entry(self.wbOptions, textvariable=self.start).grid(column=1,row=0)
        if(len(self.gates) > 0):
            self.cell_gate = tk.StringVar()
            self.cell_gate.set('Use cell gate')
            self.gate_menu = tk.OptionMenu(self.wbOptions, self.cell_gate,
                                           *list(self.gates.keys()))
            self.gate_menu.grid(row=0, column=2)

        #k
        tk.Label(self.wbOptions,text=u"k:",fg="black",bg="white").grid(column=0,row=1)
        self.k = tk.IntVar()
        tk.Entry(self.wbOptions, textvariable=self.k).grid(column=1,row=1)
        self.k.set(15)
        
        #components list
        tk.Label(self.wbOptions, text=u"Components list:", fg='black', bg='white').grid(column=0, row=2)
        self.compList = tk.StringVar()
        tk.Entry(self.wbOptions, textvariable=self.compList).grid(column=1, row=2)
        self.compList.set("1, 2, 3")

        #num waypoints
        tk.Label(self.wbOptions, text=u"Number of waypoints:", fg='black', bg='white').grid(column=0, row=3)
        self.numWaypoints = tk.IntVar()
        tk.Entry(self.wbOptions, textvariable=self.numWaypoints).grid(column=1, row=3)
        self.numWaypoints.set(250)

        #branch
        self.branch = tk.BooleanVar()
        self.branch.set(True)
        tk.Checkbutton(self.wbOptions, text=u"Branch", variable=self.branch).grid(column=0, row=4, columnspan=2)

        tk.Button(self.wbOptions, text="Run", command=self._runWishbone).grid(column=1, row=5)
        tk.Button(self.wbOptions, text="Cancel", command=self.wbOptions.destroy).grid(column=0, row=5)
        self.wait_window(self.wbOptions)

    def _runWishbone(self):
        self.wb = wishbone.wb.Wishbone(self.scdata)

        if self.cell_gate.get() == 'Use cell gate':
            self.wb.run_wishbone(start_cell=self.start.get(), k=self.k.get(), components_list=[int(comp) for comp in self.compList.get().split(',')], num_waypoints=self.numWaypoints.get())
        else:
            #randomly select start cell in gate
            print('Using cell gate:')
            print(self.cell_gate.get())
            start_cell = random.sample(list(self.gates[self.cell_gate.get()]), 1)[0]
            print(start_cell)
            self.wb.run_wishbone(start_cell=start_cell, k=self.k.get(), components_list=[int(comp) for comp in self.compList.get().split(',')], num_waypoints=self.numWaypoints.get())
        
        #enable buttons
        self.wishboneMenu.entryconfig(0, state='normal')
        self.wishboneMenu.entryconfig(1, state='normal')
        self.wishboneMenu.entryconfig(2, state='normal')
        self.WBButton.config(state='normal')
        self.wbOptions.destroy()

    def plotPCA(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='disabled')
        else:
            self.visMenu.entryconfig(4, state='disabled')

        #pop up for # components
        self.PCAOptions = tk.Toplevel()
        self.PCAOptions.title("PCA Plot Options")
        tk.Label(self.PCAOptions,text=u"Max variance explained (ylim):",fg="black",bg="white").grid(column=0, row=0)
        self.yLimVar = tk.DoubleVar()
        self.yLimVar.set(round(self.scdata.pca['eigenvalues'][0][0], 2))
        tk.Entry(self.PCAOptions, textvariable=self.yLimVar).grid(column=1,row=0)
        tk.Label(self.PCAOptions, text=u"Number of components:", fg='black', bg='white').grid(column=0, row=1)
        self.compVar = tk.IntVar()
        self.compVar.set(15)
        tk.Entry(self.PCAOptions, textvariable=self.compVar).grid(column=1, row=1)
        tk.Button(self.PCAOptions, text="Plot", command=self._plotPCA).grid(column=1, row=2)
        tk.Button(self.PCAOptions, text="Cancel", command=self.PCAOptions.destroy).grid(column=0, row=2)
        self.wait_window(self.PCAOptions)

    def _plotPCA(self):
        self.resetCanvas()
        self.fig, self.ax = self.scdata.plot_pca_variance_explained(ylim=(0, self.yLimVar.get()), n_components=self.compVar.get())
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='NW') 
        self.currentPlot = 'pca'

        #enable buttons
        self.saveButton.config(state='normal')
        self.PCAOptions.destroy()

    def plotTSNE(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='normal')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='normal')
        else:
            self.visMenu.entryconfig(4, state='normal')

        self.resetCanvas()
        self.fig, self.ax = self.scdata.plot_tsne()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='NW') 
        self.currentPlot = 'tsne'

    def plotDM(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='disabled')
        else:
            self.visMenu.entryconfig(4, state='disabled')

        self.geometry('950x550')

        self.resetCanvas()
        self.fig, self.ax = self.scdata.plot_diffusion_components()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='W') 
        self.currentPlot = 'dm_components'

    def showGSEAResults(self):
        self.saveButton.config(state='disabled')
        self.component_menu.config(state='normal')
        self.updateButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        self.visMenu.entryconfig(6, state='disabled')

        self.resetCanvas()
        self.canvas = tk.Canvas(self, width=600, height=300)
        self.canvas.grid(column=1, row=1, rowspan=17, columnspan=4)
        self.outputText(1)
        self.currentPlot = 'GSEA_result_'+self.diff_component.get()

    def updateComponent(self):
        self.resetCanvas()
        self.canvas = tk.Canvas(self, width=600, height=300)
        self.canvas.grid(column=1, row=1, rowspan=17, columnspan=4,sticky='NSEW')
        self.outputText(int(self.diff_component.get().split(' ')[-1]))
        self.currentPlot = 'GSEA_result_'+self.diff_component.get()

    def outputText(self, diff_component):
        pos_text = str(self.reports[diff_component]['pos']).split('\n')
        pos_text = pos_text[1:len(pos_text)-1]
        pos_text = '\n'.join(pos_text)
        neg_text = str(self.reports[diff_component]['neg']).split('\n')
        neg_text = neg_text[1:len(neg_text)-1]
        neg_text = '\n'.join(neg_text)
        self.canvas.create_text(5, 5, anchor='nw', text='Positive correlations:\n\n', font=('Helvetica', 16, 'bold'))
        self.canvas.create_text(5, 50, anchor='nw', text=pos_text)
        self.canvas.create_text(5, 150, anchor='nw', text='Negative correlations:\n\n', font=('Helvetica', 16, 'bold'))
        self.canvas.create_text(5, 200, anchor='nw', text=neg_text)

    def plotWBOnTsne(self):
        self.saveButton.config(state='normal')
        self.setGateButton.config(state='disabled')
        if self.scdata.data_type == 'sc-seq':
            self.component_menu.config(state='disabled')
            self.updateButton.config(state='disabled')
            self.visMenu.entryconfig(6, state='disabled')
        else:
            self.visMenu.entryconfig(4, state='disabled')

        self.resetCanvas()
        self.fig, self.ax = self.wb.plot_wishbone_on_tsne()
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4)
        self.currentPlot = 'wishbone_on_tsne'

    def plotWBMarkerTrajectory(self):
        self.getGeneSelection()
        if len(self.selectedGenes) < 1:
            print('Error: must select at least one gene')

        else:
            self.saveButton.config(state='normal')
            self.setGateButton.config(state='disabled')
            if self.scdata.data_type == 'sc-seq':
                self.component_menu.config(state='disabled')
                self.updateButton.config(state='disabled')
                self.visMenu.entryconfig(6, state='disabled')
            else:
                self.visMenu.entryconfig(4, state='disabled')

            self.resetCanvas()
            self.vals, self.fig, self.ax = self.wb.plot_marker_trajectory(self.selectedGenes)
            self.fig.set_size_inches(10, 4, forward=True)
            self.fig.tight_layout()
            self.fig.subplots_adjust(right=0.8)
            self.canvas = FigureCanvasTkAgg(self.fig, self)
            self.canvas.show()
            self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=5, sticky='W')
            self.currentPlot = 'wishbone_marker_trajectory'
            self.geometry('1050x550')

            #enable buttons
            self.wishboneMenu.entryconfig(2, state='normal')

    def plotWBHeatMap(self):
        self.getGeneSelection()
        if len(self.selectedGenes) < 1:
            print('Error: must select at least one gene')

        else:
            self.saveButton.config(state='normal')
            self.setGateButton.config(state='disabled')
            if self.scdata.data_type == 'sc-seq':
                self.component_menu.config(state='disabled')
                self.updateButton.config(state='disabled')
                self.visMenu.entryconfig(6, state='disabled')
            else:
                self.visMenu.entryconfig(4, state='disabled')

            self.resetCanvas()
            self.vals, self.fig, self.ax = self.wb.plot_marker_trajectory(self.selectedGenes)
            self.fig, self.ax = self.wb.plot_marker_heatmap(self.vals)
            self.fig.set_size_inches(10, 4, forward=True)
            self.fig.tight_layout()
            self.canvas = FigureCanvasTkAgg(self.fig, self)
            self.canvas.show()
            self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=5, sticky='W')
            self.currentPlot = 'wishbone_marker_heatmap'

    def plotGeneExpOntSNE(self):
        self.getGeneSelection()
        if len(self.selectedGenes) < 1:
            print('Error: must select at least one gene')

        else:
            self.saveButton.config(state='normal')
            self.setGateButton.config(state='disabled')
            if self.scdata.data_type == 'sc-seq':
                self.component_menu.config(state='disabled')
                self.updateButton.config(state='disabled')
                self.visMenu.entryconfig(6, state='disabled')
            else:
                self.visMenu.entryconfig(4, state='disabled')

            self.resetCanvas()
            self.fig, self.ax = self.scdata.plot_gene_expression(self.selectedGenes)
            self.canvas = FigureCanvasTkAgg(self.fig, self)
            self.canvas.show()
            self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='W')
            self.currentPlot = 'gene_expression_tsne'
            self.geometry('950x550')

    def getGeneSelection(self):
        #popup menu to get selected genes
        self.geneSelection = tk.Toplevel()
        self.geneSelection.title("Select Genes")
        tk.Label(self.geneSelection,text=u"Genes:",fg="black",bg="white").grid(row=0)

        self.geneInput = wishbone.autocomplete_entry.AutocompleteEntry(self.genes.tolist(), self.geneSelection, listboxLength=6)
        self.geneInput.grid(row=1)
        self.geneInput.bind('<Return>', self.AddToSelected)

        self.geneSelectBox = tk.Listbox(self.geneSelection, selectmode=tk.EXTENDED)
        self.geneSelectBox.grid(row=2, rowspan=10)
        self.geneSelectBox.bind('<BackSpace>', self.DeleteSelected)
        self.selectedGenes = []

        tk.Button(self.geneSelection, text="Use selected genes", command=self.geneSelection.destroy).grid(row=12)
        tk.Button(self.geneSelection, text="Cancel", command=self.cancelGeneSelection).grid(row=13)
        self.wait_window(self.geneSelection)
    
    def cancelGeneSelection(self):
        self.selectedGenes = []
        self.geneSelection.destroy()

    def AddToSelected(self, event):
        self.selectedGenes.append(self.geneInput.get())
        self.geneSelectBox.insert(tk.END, self.selectedGenes[len(self.selectedGenes)-1])

    def DeleteSelected(self, event):
        selected = self.geneSelectBox.curselection()
        pos = 0
        for i in selected:
            idx = int(i) - pos
            self.geneSelectBox.delete( idx,idx )
            self.selectedGenes = self.selectedGenes[:idx] + self.selectedGenes[idx+1:]
            pos = pos + 1  

    def savePlot(self):
        self.plotFileName = filedialog.asksaveasfilename(title='Save Plot', defaultextension='.png', initialfile=self.fileNameEntryVar.get()+"_"+self.currentPlot)
        if self.plotFileName != None:
            self.fig.savefig(self.plotFileName)

    def setGate(self):
        #pop up for gate name
        self.gateOptions = tk.Toplevel()
        self.gateOptions.title("Create gate for start cells")
        tk.Label(self.gateOptions,text=u"Gate name:" ,fg="black",bg="white").grid(column=0, row=0)
        self.gateName = tk.StringVar()
        self.gateName.set('Gate ' + str(len(self.gates) + 1))
        tk.Entry(self.gateOptions, textvariable=self.gateName).grid(column=1,row=0)
        tk.Button(self.gateOptions, text="Select gate", command=self._setGate).grid(column=1, row=1)
        tk.Button(self.gateOptions, text="Cancel", command=self.gateOptions.destroy).grid(column=0, row=1)
        self.wait_window(self.gateOptions)

    def _setGate(self):
        self.gateOptions.destroy()
        self.buttonPress = self.canvas.mpl_connect('button_press_event', self._startGate)
        self.buttonRelease = self.canvas.mpl_connect('button_release_event', self._endGate)
        self.canvas.get_tk_widget().config(cursor='plus')
 
    def _startGate(self, event):
        self.start_x = event.xdata
        self.start_y = event.ydata

    def _endGate(self, event):
        #draw gate rectangle
        start_x = self.start_x if self.start_x < event.xdata else event.xdata
        start_y = self.start_y if self.start_y < event.ydata else event.ydata
        width = np.absolute(event.xdata-self.start_x)
        height = np.absolute(event.ydata-self.start_y)
        rect = Rectangle((start_x, start_y), width, height, 
                         fill=False, ec='black', alpha=1, lw=2)
        self.ax.add_patch(rect)
        self.canvas.draw()

        #disable mouse events
        self.canvas.mpl_disconnect(self.buttonPress)
        self.canvas.mpl_disconnect(self.buttonRelease)
        self.canvas.get_tk_widget().config(cursor='arrow')
 
        #save cell gate
        gate = Path([[start_x, start_y], 
                     [start_x + width, start_y],
                     [start_x + width, start_y + height], 
                     [start_x, start_y + height],
                     [start_x, start_y]])
        gated_cells = self.scdata.tsne.index[gate.contains_points(self.scdata.tsne)]
        self.gates[self.gateName.get()] = gated_cells

        #replot tSNE w gate colored
        self.fig.clf()
        plt.scatter(self.scdata.tsne['x'], self.scdata.tsne['y'], s=10, edgecolors='none', color='lightgrey')
        plt.scatter(self.scdata.tsne.ix[gated_cells, 'x'], self.scdata.tsne.ix[gated_cells, 'y'], s=10, edgecolors='none')
        self.canvas.draw()

        self.setGateButton.config(state='disabled')
        self.visMenu.entryconfig(6, state='disabled')

    def resetCanvas(self):
        self.fig.clf()
        if type(self.canvas) is FigureCanvasTkAgg:
            for item in self.canvas.get_tk_widget().find_all():
                self.canvas.get_tk_widget().delete(item)
        else:
            for item in self.canvas.find_all():
                self.canvas.delete(item)

    def quitWB(self):
        self.quit()
        self.destroy()
Example #19
0
class labTOF(Frame):

    #define parent window
    def __init__(self, parent):
        #from Tkinter frame:
        #Frame.__init__(self, parent, background="white")
        #from ttk frame:
        Frame.__init__(self, parent)

        #save a reference to the parent widget
        self.parent = parent

        #delegate the creation of the user interface to the initUI() method
        #self.parent.title("Lab TOF")
        #self.pack(fill=BOTH, expand=1)
        self.fig = Figure(figsize=(12, 8), dpi=100)
        #fig = Figure(facecolor='white', edgecolor='white')
        self.fig.subplots_adjust(bottom=0.15, left=0.13, right=0.95, top=0.95)

        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self)
        self.toolbar.pack(side=TOP)
        #canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)

        #frame for buttons (at bottom)
        #buttons are arranged on grid, not pack
        self.frame_button = Frame(self)
        self.frame_button.pack(side='bottom', fill=BOTH, expand=1)

        #list containing time domain values
        self.time = []
        #list containing mass domain values
        self.mass = []
        #flag to indicate whether time or mass is displayed
        #time flag=0
        #mass flag=1
        self.time_mass_flag = 0
        #flag to indicate MS or MSMS calibration
        #MS = 0
        #MSMS = 1
        self.MSMS_flag = -99
        #list containing intensity values
        self.intensity = []
        #list containing calibration values
        self.cal_time = []
        self.cal_mass = []
        self.label_mass = []
        self.label_time = []
        self.label_intensity = []
        self.label_size = float(10)
        self.label_format = "%.0f"
        self.digits_after = 0
        self.label_offset = 0.0
        #calibration point id
        self.cid = -99
        self.initUI()
        #zero mass corresponds to ~40% of parent mass time
        self.MSMS_zero_time = 0.40838  #0.4150#0.4082

    #container for other widgets
    def initUI(self):
        #set the title of the window using the title() method
        self.parent.title("Lab TOF")

        #apply a theme to widget
        self.style = Style()
        self.style.theme_use('default')

        #the Frame widget (accessed via the delf attribute) in the root window
        #it is expanded in both directions
        #CHANGE all pack to grid layout
        self.pack(fill=BOTH, expand=1)

        menubar = Menu(self.parent)
        self.parent.config(menu=menubar)

        #contains file menu items
        fileMenu = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=fileMenu)
        fileMenu.add_command(label="Open", command=self.onOpen)
        fileMenu.add_command(label="Export Data (ASCII file)",
                             command=self.onExport)
        fileMenu.add_command(label="Quit", command=self.quit_destroy)

        #contains calibration menu items
        #"self" is needed to access items later (to change state)
        #default state for save calibration is disabled
        #state is enabled once a file is loaded
        self.calMenu = Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Calibration", menu=self.calMenu)
        self.MScalMenu = Menu(menubar, tearoff=0)
        self.calMenu.add_cascade(label="MS Calibration",
                                 menu=self.MScalMenu,
                                 state=DISABLED)
        self.MScalMenu.add_command(
            label="Start New Calibration: include (0,0)",
            command=self.onCalStartInclude)
        self.MScalMenu.add_command(
            label="Start New Calibration: exclude (0,0)",
            command=self.onCalStartExclude)
        self.MScalMenu.add_command(label="Open Calibration File",
                                   command=self.onOpenCal)

        self.MSMScalMenu = Menu(menubar, tearoff=0)
        self.calMenu.add_cascade(label="MSMS Calibration",
                                 menu=self.MSMScalMenu,
                                 state=DISABLED)
        self.MSMScalMenu.add_command(label="Start New Calibration",
                                     command=self.onMSMSCalStart)
        self.MSMScalMenu.add_command(label="Open Calibration File",
                                     command=self.onMSMSOpenCal)

        #default state for save calibration is disabled
        #state is enabled once a calibration is defined
        self.calMenu.add_command(label="Save Calibration File",
                                 command=self.onSaveCal,
                                 state=DISABLED)

        #generate figure (no data at first)
        self.generate_figure([0, 1], [[], []], ' ')

        #calibration
        Label(self.frame_button, text="Calibration").grid(row=0,
                                                          column=0,
                                                          padx=5,
                                                          pady=5,
                                                          sticky=W)
        #create instance of the button widget
        #command specifies the method to be called
        #identify parent peak in MSMS
        self.parentButton = Button(self.frame_button,
                                   text="Identify Parent Peak",
                                   command=self.calibrate_parent,
                                   state=DISABLED)
        #self.parentButton.pack(side=LEFT, padx=5, pady=5)
        self.parentButton.grid(row=0, column=1, padx=5, pady=5, sticky=W)

        #identify half-parent peak in MSMS
        #self.halfparentButton = Button(self.frame_button, text="Identify Half-Parent Peak", command = self.calibrate_halfparent, state=DISABLED)
        #self.parentButton.pack(side=LEFT, padx=5, pady=5)
        #self.halfparentButton.grid(row=0, column=2, padx=5, pady=5, sticky=W)

        #add calibration point
        self.calibrateButton = Button(self.frame_button,
                                      text="Add Calibration Point",
                                      command=self.calibrate,
                                      state=DISABLED)
        #self.calibrateButton.pack(side=LEFT, padx=5, pady=5)
        self.calibrateButton.grid(row=0, column=2, padx=5, pady=5, sticky=W)

        #set MSMS calibration constant MSMS
        self.constantButton = Button(self.frame_button,
                                     text="Set MSMS Constant",
                                     command=self.calibration_constant,
                                     state=DISABLED)
        #self.parentButton.pack(side=LEFT, padx=5, pady=5)
        self.constantButton.grid(row=0, column=3, padx=5, pady=5, sticky=W)

        #finish calibration and convert to mass domain
        self.finishcalButton = Button(self.frame_button,
                                      text="Finish Calibration",
                                      command=self.finish_calibrate,
                                      state=DISABLED)
        #self.finishcalButton.pack(side=LEFT, padx=5, pady=5)
        self.finishcalButton.grid(row=0, column=4, padx=5, pady=5, sticky=W)

        Label(self.frame_button, text="Label Spectrum").grid(row=1,
                                                             column=0,
                                                             padx=5,
                                                             pady=5,
                                                             sticky=W)

        #label peaks in figure
        self.labelButton = Button(self.frame_button,
                                  text="Label Peak",
                                  command=self.label_peaks,
                                  state=DISABLED)
        #self.labelButton.pack(side=RIGHT, padx=5, pady=5)
        self.labelButton.grid(row=1, column=1, padx=5, pady=5, sticky=W)

        self.deletelabelButton = Button(self.frame_button,
                                        text="Remove Labels",
                                        command=self.delete_labels,
                                        state=DISABLED)
        #self.deletelabelButton.pack(side=RIGHT, padx=5, pady=5)
        self.deletelabelButton.grid(row=1, column=2, padx=5, pady=5, sticky=W)

        self.formatelabelButton = Button(self.frame_button,
                                         text="Format Label",
                                         command=self.format_labels)
        self.formatelabelButton.grid(row=1, column=3, padx=5, pady=5, sticky=W)

        Label(self.frame_button, text="Smooth Spectrum").grid(row=2,
                                                              column=0,
                                                              padx=5,
                                                              pady=5,
                                                              sticky=W)

        #smooth spectrum
        self.smoothButton = Button(self.frame_button,
                                   text="Smooth",
                                   command=self.smooth_data,
                                   state=DISABLED)
        #self.smoothButton.pack(side=RIGHT, padx=5, pady=5)
        self.smoothButton.grid(row=2, column=1, padx=5, pady=5, sticky=W)

        Label(self.frame_button, text="Convert Domain").grid(row=3,
                                                             column=0,
                                                             padx=5,
                                                             pady=5,
                                                             sticky=W)

        #convert to time domain
        self.timeButton = Button(self.frame_button,
                                 text="Time Domain",
                                 command=self.time_domain)
        #timeButton.pack(side=RIGHT, padx=5, pady=5)
        self.timeButton.grid(row=3, column=1, padx=5, pady=5, sticky=W)

        #convert to mass domain
        self.massButton = Button(self.frame_button,
                                 text="Mass Domain",
                                 command=self.mass_domain)
        #self.massButton.pack(side=RIGHT, padx=5, pady=5)
        self.massButton.grid(row=3, column=2, padx=5, pady=5, sticky=W)

        self.quitButton = Button(self.frame_button,
                                 text="Quit",
                                 command=self.quit_destroy)
        #quitButton.place(x=50, y=50)
        #quitButton.pack(side=RIGHT, padx=5, pady=5)
        self.quitButton.grid(row=3, column=6, padx=5, pady=5, sticky=E)

    #plot figure
    def generate_figure(self, data, label, xaxis_title):
        #clear figure
        plt.clf()
        ax = self.fig.add_subplot(111)
        #clear axis
        ax.cla()
        spectrum = ax.plot(data[0], data[1], color='k')
        ax.set_xlabel(xaxis_title)  #, fontsize=6)
        ax.set_ylabel('intensity (V)')  #, fontsize=6)
        #ax.tick_params('both', length=4, width=1, which='major')
        #ax.tick_params('both', length=2, width=0.5, which='minor')
        #for tick in ax.xaxis.get_major_ticks():
        #tick.label.set_fontsize(6)
        #for tick in ax.yaxis.get_major_ticks():
        #tick.label.set_fontsize(6)
        #add peak labels
        for index, label_x in enumerate(label[0]):
            #ax.text(0.94*label_x, 1.05*label[1][index], str("%.1f" % label_x))
            #ax.annotate(str("%.1f" % label_x), xy=(label_x, label[1][index]), xytext=(1.1*label_x, 1.1*label[1][index]), arrowprops=dict(facecolor='black', shrink=0.1),)
            #ax.annotate(str("%.1f" % label_x), xy=(label_x, label[1][index]), xytext=(1.0*label_x, 1.2*label[1][index]),)
            #I could separate format, offset, precision into an array for each label
            an1 = ax.annotate(str(
                self.label_format %
                round(label_x + self.label_offset, int(self.digits_after))),
                              xy=(label_x, label[1][index]),
                              xytext=(label_x, label[1][index]),
                              fontsize=self.label_size)
            an1.draggable(state=True)
            #need to retrieve new label position and update position array
            #self.label_mass[index]=(event.xdata)
            #self.label_intensity[index]=(event.ydata)
            #self.label_time[index]=(event.xdata)

        #remove self.label_time values
        #set label_peaks to generate figure again with loop that allows peak labeling (datacursor()) - set flag, reset flag in loop
        ##otherwise label will appear when selecting peaks for calibration
        #have Tim download mpldatacursor package with pip?
        #need to figure out how to remove labels
        ##canvas.delete("all") in function with a redraw function?
        #datacursor(spectrum, display='multiple', draggable=True, formatter='{x:.1f}'.format, bbox=None)

        self.canvas.show()
        #self.canvas.get_tk_widget().pack(side=BOTTOM)
        self.canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)
        #self.can.grid(row=1, column=0, columnspan=6, rowspan=3, padx=5, sticky=E+W+S+N)

        self.toolbar.update()
        #self.canvas._tkcanvas.pack(side=TOP)
        #not sure what this line does, comment out for now
        #it appears to be necessary for matplotlib grid?
        self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=True)

    #def delete_figure(self):
    #Canvas.delete("all")
    #.destroy()

    #open file
    def onOpen(self):
        #displays .txt files in browser window
        #only reads time domain data files
        ftypes = [('txt files', '*.txt'), ('binary files', '*.trc')]
        dlg = tkFileDialog.Open(self, filetypes=ftypes)
        fl = dlg.show()

        if fl != '':
            if fl[-3:] == 'trc':
                self.time, self.intensity = read_lecroy_binary.read_timetrace(
                    fl)
                #plots data in time domain
                if self.time_mass_flag == 0:
                    self.time_domain()
                #plots data in mass domain
                elif self.time_mass_flag == 1:
                    self.mass_domain()

            elif fl[-3:] == 'txt':
                data = self.readFile(fl)
                self.intensity = data[1]
                #self.intensity = [x+0.00075 for x in data[1]]
                if self.time_mass_flag == 0:
                    self.time = data[0]
                    self.time_domain()
                elif self.time_mass_flag == 1:
                    self.mass = data[0]
                    self.mass_domain()
            self.labelButton.config(state=NORMAL)
            self.deletelabelButton.config(state=NORMAL)
            #allows for smoothing of data
            self.smoothButton.config(state=NORMAL)
            #allows for calibration
            self.calMenu.entryconfig("MS Calibration", state=NORMAL)
            self.calMenu.entryconfig("MSMS Calibration", state=NORMAL)

    #export data to txt file
    def onExport(self):
        #save header info (date/time, ask user for instrument)?
        #ask for save file name
        savefile = tkFileDialog.asksaveasfile(mode='wb',
                                              defaultextension=".txt")
        # asksaveasfile return `None` if dialog closed with "cancel".
        if savefile is None:
            return
        #export mass or time domain data depending on flag (what is plotted)
        if self.time_mass_flag == 0:
            x = self.time
        else:
            x = self.mass
        y = self.intensity

        for i in range(len(x)):
            savefile.write(str(x[i]))
            savefile.write(' ')
            savefile.write(str(y[i]))
            savefile.write('\r\n')
        savefile.close()

    #convert to mass domain
    #disabled until calibration is defined
    def mass_domain(self):
        self.time_mass_flag = 1
        self.generate_figure([self.mass, self.intensity],
                             [self.label_mass, self.label_intensity],
                             'mass (Da)')

    #convert to time domain
    def time_domain(self):
        self.time_mass_flag = 0
        #plot in micro seconds
        self.generate_figure([[1E6 * x for x in self.time], self.intensity],
                             [self.label_time, self.label_intensity],
                             'time ($\mu$s)')

    #smooth data
    def smooth_data(self):
        #smooth self.time/mass/int variables - permanant
        #probably not a good idea
        #purpose of smoothing function: to display smoothed plot
        self.SmoothDialog(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        smoothed_signal = scipy.signal.savgol_filter(self.intensity,
                                                     int(self.window),
                                                     int(self.poly))
        #convert from array to list
        self.intensity = smoothed_signal.tolist()
        #print 'intensity: ', len(self.intensity), type(self.intensity)
        if self.time_mass_flag == 1:
            #print 'mass: ', len(self.mass), type(self.mass)
            self.mass_domain()
        else:
            #print 'time: ', len(self.time), type(self.time)
            self.time_domain()

    #format labels
    def format_labels(self):
        self.FormatLabelDialog(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        self.label_size = float(self.label_size)
        self.label_format = "%." + self.digits_after + "f"

    #save calibration file
    def onSaveCal(self):
        #ask for save file name
        savefile = tkFileDialog.asksaveasfile(mode='wb',
                                              defaultextension=".txt")
        if savefile is None:
            return

        #write header information?
        #date/time, file name
        for i in range(len(self.cal_time)):
            savefile.write(str(self.cal_time[i]))
            savefile.write(' ')
            savefile.write(str(self.cal_mass[i]))
            #\r\n is the newline character for windows
            savefile.write('\r\n')
        savefile.close()

    #open previous MS (regular) calibration file
    def onOpenCal(self):
        #display .txt files in browser window
        ftypes = [('txt files', '*.txt')]
        dlg = tkFileDialog.Open(self, filetypes=ftypes)
        filename = dlg.show()

        if filename != '':
            #list with time calibration value
            calt_read = []
            #list with mass calibration value
            calm_read = []
            file = open(filename, 'r')
            #header=file.readline()
            for line in file:
                #read each row - store data in columns
                temp = line.split(' ')
                calt_read.append(float(temp[0]))
                calm_read.append(float(temp[1].rstrip('/n')))
            #store values in calibration lists
            self.cal_time = calt_read
            self.cal_mass = calm_read
        #sets MSMS flag for finish_calibrate routine
        self.MSMS_flag = 0
        #call finish_calibrate method to calibrate and plot data in mass domain
        self.finish_calibrate()

    #open previous MSMS calibration file
    def onMSMSOpenCal(self):
        #display .txt files in browser window
        ftypes = [('txt files', '*.txt')]
        dlg = tkFileDialog.Open(self, filetypes=ftypes)
        filename = dlg.show()

        if filename != '':
            #list with time calibration value
            calt_read = []
            #list with mass calibration value
            calm_read = []
            file = open(filename, 'r')
            #header=file.readline()
            for line in file:
                #read each row - store data in columns
                temp = line.split(' ')
                calt_read.append(float(temp[0]))
                calm_read.append(float(temp[1].rstrip('/n')))
            #store values in calibration lists
            self.cal_time = calt_read
            self.cal_mass = calm_read
        #sets MSMS flag for finish_calibrate routine
        self.MSMS_flag = 1
        #call finish_MSMScalibrate method to calibrate and plot data in mass domain
        self.finish_calibrate()

    #called when "Start New Calibration" is selected from MS cascade
    def onCalStartInclude(self):
        #sets MSMS flag for finish_calibrate routine
        self.MSMS_flag = 0
        #reset calibration points
        self.cal_time = []
        self.cal_mass = []
        #sets (0,0) as default
        self.cal_time.append(0)
        self.cal_mass.append(0)
        #plot data in time domain (reset plot)
        self.time_domain()
        #set calibration buttons (add new, finish) to enabled state
        self.calibrateButton.config(state=NORMAL)
        self.finishcalButton.config(state=DISABLED)
        self.counter = 1

    #called when "Start New Calibration" is selected from MS cascade
    def onCalStartExclude(self):
        #sets MSMS flag for finish_calibrate routine
        self.MSMS_flag = 0
        #reset calibration points
        self.cal_time = []
        self.cal_mass = []
        #sets (0,0) as default
        #self.cal_time.append(0)
        #self.cal_mass.append(0)
        #plot data in time domain (reset plot)
        self.time_domain()
        #set calibration buttons (add new, finish) to enabled state
        self.calibrateButton.config(state=NORMAL)
        self.finishcalButton.config(state=DISABLED)
        self.counter = 0

    #called when "Start New Calibration" is selected in MSMS mode
    def onMSMSCalStart(self):
        #sets MSMS flag for finish_calibrate routine
        self.MSMS_flag = 1
        #reset calibration points
        self.cal_time = []
        self.cal_mass = []
        #plot data in time domain (reset plot)
        self.time_domain()
        #set calibration button (ID parent peak, finish) to enabled state
        self.parentButton.config(state=NORMAL)
        #self.halfparentButton.config(state=DISABLED)
        self.calibrateButton.config(state=DISABLED)
        self.constantButton.config(state=NORMAL)
        self.finishcalButton.config(state=DISABLED)
        self.counter = 1

    #called when click is made in plotting environment during calibration
    def on_click(self, event):
        temp_len = len(self.cal_time)
        #when the click is made within the plotting window
        if event.inaxes is not None:
            #print 'clicked: ', event.xdata, event.ydata
            self.cal_time.append(event.xdata * 1E-6)
            #sets up dialog box for user to enter mass value
            self.MassDialog(self.parent)
        #if click is outside plotting window
        else:
            print 'Clicked ouside axes bounds but inside plot window'
        #disconnect from calibration click event when a new calibration value is set
        if len(self.cal_time) > temp_len:
            self.canvas.mpl_disconnect(self.cid)

    #called during calibration
    #asks user for mass value associated with time value selected
    def MassDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        Label(top, text="Actual Mass Value:").pack()

        self.e = Entry(top)
        self.e.pack(padx=5)
        #calls DialogOK to set mass value to input
        b = Button(top, text="OK", command=self.DialogOK)
        b.pack(pady=5)

    #called when Smooth button is pressed
    #asks user for smooth input data
    def SmoothDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        #window length for smoothing function
        #must be greater than poly value, positive, odd (51)
        Label(top, text="Window Length:").grid(row=0,
                                               column=0,
                                               sticky=W,
                                               padx=5,
                                               pady=5)
        self.w = Entry(top)
        self.w.insert(0, '151')
        self.w.grid(row=0, column=1, padx=5, pady=5)

        #polynomial order
        #must be less than window length (3)
        Label(top, text="Polynomial Order:").grid(row=1,
                                                  column=0,
                                                  sticky=W,
                                                  padx=5,
                                                  pady=5)
        self.p = Entry(top)
        self.p.insert(0, '3')
        self.p.grid(row=1, column=1, padx=5, pady=5)

        #calls DialogSmoothOK to set these values
        b = Button(top, text="OK", command=self.DialogSmoothOK)
        b.grid(row=2, column=1, padx=5, pady=5)

    def FormatLabelDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        #font size
        Label(top, text="Font Size:").grid(row=0,
                                           column=0,
                                           sticky=W,
                                           padx=5,
                                           pady=5)
        self.fs = Entry(top)
        self.fs.insert(0, '10')
        self.fs.grid(row=0, column=1, padx=5, pady=5)

        #Precision
        Label(top, text="Digits After Decimal:").grid(row=1,
                                                      column=0,
                                                      sticky=W,
                                                      padx=5,
                                                      pady=5)
        self.dg = Entry(top)
        self.dg.insert(0, '0')
        self.dg.grid(row=1, column=1, padx=5, pady=5)

        #label offset
        Label(top, text="Label Offset:").grid(row=2,
                                              column=0,
                                              sticky=W,
                                              padx=5,
                                              pady=5)
        self.lo = Entry(top)
        self.lo.insert(0, '0.0')
        self.lo.grid(row=2, column=1, padx=5, pady=5)

        #calls DialogLabelOK to set these values
        b = Button(top, text="OK", command=self.DialogLabelOK)
        b.grid(row=3, column=1, padx=5, pady=5)

    #called from smooth dialog box within smooth routine
    def DialogLabelOK(self):
        #sets user-defined font size
        self.label_size = float(self.fs.get())
        #sets user-defined precision
        self.digits_after = str(self.dg.get())
        #sets user-defined label offset
        self.label_offset = float(self.lo.get())
        self.top.destroy()

    #called from smooth dialog box within smooth routine
    def DialogSmoothOK(self):
        #sets user-defined window length
        self.window = float(self.w.get())
        #sets user-defined polynomail order
        self.poly = float(self.p.get())
        self.top.destroy()

    #called from mass dialog box within calibration routine
    def DialogOK(self):
        #sets user-defined mass calibration value to mass cal list
        self.cal_mass.append(float(self.e.get()))
        #closes dialog box
        self.top.destroy()

    #called from calibration routine
    #stores user-selected point in cid
    def calibrate(self):
        #user selects point
        self.cid = self.canvas.mpl_connect('button_press_event', self.on_click)
        self.counter = self.counter + 1
        if self.counter > 1:
            self.finishcalButton.config(state=NORMAL)

    #called from MSMS calibration routine
    #stores user-selected point in cid
    def calibrate_parent(self):
        #user selects point
        self.cid = self.canvas.mpl_connect('button_press_event', self.on_click)
        self.parentButton.config(state=DISABLED)
        self.finishcalButton.config(state=NORMAL)
        #self.halfparentButton.config(state=NORMAL)
        self.calibrateButton.config(state=NORMAL)

    #called from MSMS calibration routine
    #stores user-selected point in cid
    #def calibrate_halfparent(self):
    #user selects point
    #self.cid=self.canvas.mpl_connect('button_press_event', self.on_click)
    #self.halfparentButton.config(state=NORMAL)
    #self.finishcalButton.config(state=NORMAL)
    #self.calibrateButton.config(state=NORMAL)

    #user defined calibration constant
    def calibration_constant(self):
        self.ConstantDialog(self.parent)
        #wait for dialog to close
        self.top.wait_window(self.top)
        #recompute time-mass conversion
        #if len(self.cal_time) > 0:
        #self.finishcalButton.config(state=NORMAL)

    def ConstantDialog(self, parent):
        top = self.top = Toplevel(self.parent)
        Label(top, text="MSMS Calibration Constant:").grid(row=0,
                                                           column=0,
                                                           sticky=W,
                                                           padx=5,
                                                           pady=5)
        self.c = Entry(top)
        self.c.insert(0, self.MSMS_zero_time)
        self.c.grid(row=0, column=1, padx=5, pady=5)
        #calls DialogConstantOK to set these values
        b = Button(top, text="OK", command=self.DialogConstantOK)
        b.grid(row=2, column=1, padx=5, pady=5)

    def DialogConstantOK(self):
        #sets user-defined calibration constant
        self.MSMS_zero_time = float(self.c.get())
        self.top.destroy()

    #called from calibration routine after "finish" button is pressed
    def finish_calibrate(self):
        #disables buttons until "start new calibration" is selected
        self.calibrateButton.config(state=DISABLED)
        self.finishcalButton.config(state=DISABLED)
        self.parentButton.config(state=DISABLED)
        #self.halfparentButton.config(state=DISABLED)
        self.constantButton.config(state=DISABLED)
        #allows plotting in mass domain
        self.massButton.config(state=NORMAL)
        #for MSMS calibration
        if self.MSMS_flag == 1:
            #add second calibration time point equal to some percentage of parent peak time if necessary
            #if cal_time has only one value:
            if len(self.cal_time) == 1:
                self.cal_time.append(self.cal_time[0] * self.MSMS_zero_time)
                self.cal_mass.append(0)

        #if MS mode (regular)
        if self.MSMS_flag == 0:
            #fit quadratic fuction through cal points
            popt, pcov = curve_fit(func_quad, self.cal_time, self.cal_mass)
            #convert time to mass
            #self.mass[:] = [popt[0]*(x**2)*(1E10) + popt[1] for x in self.time]
            self.mass = []
            for x in self.time:
                if x < 0:
                    self.mass.append(-popt[0] * (x**2) * (1E10) + popt[1])
                else:
                    self.mass.append(popt[0] * (x**2) * (1E10) + popt[1])

        #if MSMS mode
        elif self.MSMS_flag == 1:
            #fit quadratic fuction through cal points
            popt, pcov = curve_fit(func_lin, self.cal_time, self.cal_mass)
            #convert time to mass
            self.mass[:] = [popt[0] * x * (1E10) + popt[1] for x in self.time]
            #discard all data below 0 mass
            mass_temp = self.mass
            int_temp = self.intensity
            time_temp = self.time
            self.mass = []
            self.intensity = []
            self.time = []
            for index, mass in enumerate(mass_temp):
                if mass > 0:
                    self.mass.append(mass)
                    self.intensity.append(int_temp[index])
                    self.time.append(time_temp[index])

        #allows user to save calibration file
        self.calMenu.entryconfig("Save Calibration File", state=NORMAL)
        #plots figure in mass domain
        self.mass_domain()

    #function for file input
    def readFile(self, filename):
        flag_pico = False
        file = open(filename, 'r')
        #there is some extra formatting on the first line - delete this data
        header = file.readline()
        header = file.readline()
        #check if Picoscope:
        if header[1:3] == 'us':
            flag_pico = True
        header = file.readline()
        header = file.readline()
        header = file.readline()
        #read each row in the file
        #list for temporary time data
        time = []
        #list for temporary intensity data
        intensity = []
        for line in file:
            #check file format:
            if ',' in line:
                #read each row - store data in columns
                temp = line.split(',')
                if flag_pico:
                    time.append(float(temp[0]) * 1E-6)
                else:
                    time.append(float(temp[0]))
                intensity.append(float(temp[1].rstrip('/n')))
            if '\t' in line:
                temp = line.split('\t')
                if flag_pico:
                    time.append(float(temp[0]) * 1E-6)
                else:
                    time.append(float(temp[0]))
                intensity.append(float(temp[1].rstrip('/n')))

        data = [time, intensity]
        return data

    #function to label peaks on figure in order to save figure as an image file with labels
    def label_peaks(self):
        #ask for peak (on_click_label)
        self.cid = self.canvas.mpl_connect('button_press_event',
                                           self.on_click_label)

    #remove peak labels when button is selected
    def delete_labels(self):
        #deletes peak label arrays
        self.label_time = []
        self.label_mass = []
        self.label_intensity = []
        #if time flag is set
        if self.time_mass_flag == 0:
            self.time_domain()
        elif self.time_mass_flag == 1:
            self.mass_domain()

    #called when click is made to label peak
    def on_click_label(self, event):
        temp_len = len(self.label_intensity)
        #if time flag is set
        if self.time_mass_flag == 0:
            #temp_len=len(self.label_time)
            #when the click is made within the plotting window
            if event.inaxes is not None:
                #print 'clicked: ', event.xdata, event.ydata
                self.label_time.append(event.xdata)
                self.label_intensity.append(event.ydata)
                #print 'time: ', self.label_time
                #print 'intensity: ', self.label_intensity
                self.time_domain()
            #if click is outside plotting window
            else:
                print 'Clicked ouside axes bounds but inside plot window'
        #if the mass flag is set
        elif self.time_mass_flag == 1:
            #temp_len=len(self.label_mass)
            #when the click is made within the plotting window
            if event.inaxes is not None:
                #print 'clicked: ', event.xdata, event.ydata
                self.label_mass.append(event.xdata)
                self.label_intensity.append(event.ydata)
                #print 'mass: ', self.label_mass
                #print 'intensity: ', self.label_intensity
                self.mass_domain()
            #if click is outside plotting window
            else:
                print 'Clicked ouside axes bounds but inside plot window'
        #self.peak_intensity=event.ydata
        #plot label

        #disconnect from click event when a new peak label value is set
        if temp_len < len(self.label_intensity):
            self.canvas.mpl_disconnect(self.cid)

    #need to destroy parent before quitting, otherwise python crashes on Windows
    def quit_destroy(self):
        self.parent.destroy()
        self.parent.quit()
Example #20
0
class ContTweaker:
	def __init__(self,iwvlngth,ispectrum,espectrum,oldxspline,oldyspline,outfile):
		#Initialize input variables for the class
		self.outfile=outfile
		self.iwvlngth=iwvlngth
		self.ispectrum=ispectrum
		self.espectrum=espectrum
		#intialize CT.XSPLINE/YSPLINE to the old values at first (will be replaced)
		self.xspline=oldxspline
		self.yspline=oldyspline
		self.oldxspline=oldxspline
		self.oldyspline=oldyspline
		#Interpolate cubic spline of the continuum for both "NEW" and old spline
		self.oldspline=scipy.interpolate.interp1d(oldxspline,oldyspline,kind='cubic')
		self.spline=scipy.interpolate.interp1d(oldxspline,oldyspline,kind='cubic')
		#Make the MPL figures appear
		self.MakePlot()
		#Add buttons to the bottom of the main TB_CONTFIT widget menu
		self.popup=Tkinter.Frame()
		self.popup.grid()
		But1=Tkinter.Button(self.popup,text='Refresh Plot',command=self.Refresh)
		But1.grid(column=0,row=0)
		But3=Tkinter.Button(self.popup,text='Remove Point',command=self.RemovePoint)
		But3.grid(column=0,row=1)
		But4=Tkinter.Button(self.popup,text='Add Point',command=self.AddPoint)
		But4.grid(column=0,row=2)
		But5=Tkinter.Button(self.popup,text='Reopen Window',command=self.MakePlot)
		But5.grid(column=0,row=4)		
		But6=Tkinter.Button(self.popup,text='Save Spline',command=self.Save)
		But6.grid(column=0,row=5)
		But7=Tkinter.Button(self.popup,text='Exit',command=self.Exit)
		But7.grid(column=0,row=6)


		
		#Toggle between a Continous-editing  and single click modes
		MODES=[("Single",False),("Continuous",True)]
		self.useContinuous=Tkinter.BooleanVar()
		self.useContinuous.set(False)
		ii=1
		labelMode=Tkinter.StringVar()
		labelmode=Tkinter.Label(self.popup,textvariable=labelMode,anchor="w",fg="black")
		labelmode.grid(column=1, row=0, columnspan=2, sticky='S')
		labelMode.set(u"Point-editing mode")
		for text,mode in MODES:
			b=Tkinter.Radiobutton(self.popup,text=text,variable=self.useContinuous,value=mode)
			b.grid(column=ii,row=1)
			ii+=1
			if ii==1: b.select()

		#Wait until the window is closed (i.e. CT.EXIT() is run by clicking EXIT button)
		self.popup.wait_window()




	def MakePlot(self):
		#This function generates the plot window that will be the vidual interface for how
		#the continuum tweaking is going

		#Make the Spline from the CURRENT spline values
		xcont=self.iwvlngth
		ycont=self.spline(xcont)
		#Make the spline from the OLD spline values
		ospectrum=self.oldspline(xcont)

		#Create a MPL figure
		self.tweakfig=plt.figure(figsize=(8,8))
		#First subplot is for displaying the original fit to the spectrum
		self.ax1=self.tweakfig.add_subplot(3,1,1)
		#Second subplot is for displaying the current fit to the spectrum
		#To help with looking at all regions of the same time, share the X and Y
		#axes to CT.AX1.
		self.ax2=self.tweakfig.add_subplot(3,1,2,sharex=self.ax1,sharey=self.ax1)
		#Third subplot for displaying the continuum-fitted spectrum based on the
		#current spline. Because this is now 0 and 1ish, only share the X axis
		#to CT.AX1
		self.ax3=self.tweakfig.add_subplot(3,1,3,sharex=self.ax1)
		#Create the TK window for embedding the figure, set it up, and draw
		self.TFroot=Tkinter.Tk()
		self.TFroot.wm_title("Continuum Tweaker")
		self.TweakPlot=FigureCanvasTkAgg(self.tweakfig,master=self.TFroot)
		#This toolbar is mainly for zooming. By sharing the x (and y) axes, when zooming in
		#on one axes, all three will zoom appropriately
		NavTweakPlot=NavigationToolbar2TkAgg(self.TweakPlot, self.TFroot)
		self.TweakPlot.get_tk_widget().pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)

		#For CT.AX1, plot the original specturm, the error spectrum, and the original continuum fitted
		self.ax1.plot(self.iwvlngth,self.ispectrum,'k',drawstyle='steps',label='Spectrum')
		self.ax1.plot(self.iwvlngth,self.espectrum,'g',drawstyle='steps',label='Error')
		self.ax1.plot(xcont,ycont,'b',label='Continuum')
		self.ax1.plot(self.oldxspline,self.oldyspline,'or',label='Spline Pts.')
		#Make a legend
		self.ax1.legend(ncol=4,frameon=False, loc=9, bbox_to_anchor=(0.5, 1.3))
		self.ymin,self.ymax=self.ax1.get_ylim()
		self.ax1.set_ylabel('Flux\n(original)')

		#For CT.AX2, plot the spectrum, and the current spline points and the resulting continuum
		self.ax2.plot(self.iwvlngth,self.ispectrum,'k',drawstyle='steps')
		self.ax2.plot(xcont,ycont,'b')
		self.ax2.plot(self.xspline,self.yspline,'or',picker=5)#Picker needed to pick which point
		self.ax2.set_ylabel('Flux\n(tweaked fit)')



		#For CT.AX3, plot the spectrum upon dividing by the continuum. Plot the
		#error spectrum as 1-err and 1+err to reflect how much noise one MIGHT expect
		#As a rule of thumb, one should aim to have the continuum fluctuations within the error
		self.ax3.plot(xcont,self.ispectrum/ospectrum,'k',drawstyle='steps')
		self.ax3.plot(xcont,1.0-self.espectrum/ospectrum,'--g',drawstyle='steps')
		self.ax3.plot(xcont,1.0+self.espectrum/ospectrum,'--g',drawstyle='steps')
		self.xmin,self.xmax=self.ax3.get_xlim()
		self.ax3.plot([self.xmin,self.xmax],[1,1],'--r')
		self.ax3.plot([self.xmin,self.xmax],[0,0],'--r')
		#restrict CT.AX3 to only show the normalized range of values
		self.ax3.set_ylim(-1,2)
		self.ax3.set_ylabel('Relative flux')
		self.ax3.set_xlabel('Wavlength')

		#Draw all the new plotted stuff
		self.TweakPlot.draw()



	def Refresh(self,yrefresh=True):
		#This function takes any modifications that have taken place and updates
		#the plots accordingly. If YREFRESH=TRUE, this sets the y-axis to the
		#original scaling. Otherwise keep the current values.

		#Get the current x values (incase the user has zoomed in using toolbar)
		xmin,xmax=self.ax2.get_xlim()
		ymin,ymax=self.ax2.get_ylim()
		#if YREFRESH=TRUE, set to original values (SELF.YMIN/YMAX)
		if yrefresh:
			ymin=self.ymin
			ymax=self.ymax
		#Clear CT.AX2/AX3 of all previous information
		self.ax2.clear()
		self.ax3.clear()
		#Remake the spline based on the new XSPLINE/YSPLINE points, and save
		self.spline=scipy.interpolate.interp1d(self.xspline,self.yspline,kind='cubic')
		#Generate the continuum based on the new spline
		xcont=self.iwvlngth
		ycont=self.spline(xcont)

		#Update CT.AX1, perserve the x-axis bounds, and return to original y-axis
		self.ax1.set_ylim(ymin,ymax)
		self.ax1.set_xlim(xmin,xmax)

		#Update CT.AX2 by plotting new spline, also perserve the x-axis bounds
		self.ax2.plot(self.iwvlngth,self.ispectrum,'k',drawstyle='steps')
		self.ax2.plot(xcont,ycont,'b')
		self.ax2.plot(self.xspline,self.yspline,'or',picker=5)
		self.ax2.set_ylabel('Flux\n(tweaked fit)')
		self.ax2.set_ylim(ymin,ymax)
		self.ax2.set_xlim(xmin,xmax)

		#in CT.AX2, Divide out the spectrum&errorspectrum by the continuum, and plot
		self.ax3.plot(xcont,self.ispectrum/ycont,'k',drawstyle='steps')
		self.ax3.plot(xcont,1.0-self.espectrum/ycont,'--g',drawstyle='steps')
		self.ax3.plot(xcont,1.0+self.espectrum/ycont,'--g',drawstyle='steps')
		self.ax3.set_ylabel('Relative flux')
		self.ax3.set_xlabel('Wavlength')
		self.ax3.set_ylim(-1,2)
		self.ax3.plot([self.xmin,self.xmax],[1,1],'--r')
		self.ax3.plot([self.xmin,self.xmax],[0,0],'--r')
		self.ax3.set_xlim(xmin,xmax)

		#Update plotting window
		self.TweakPlot.draw()


	#Function for closing the current MPL event by it's ID, and stop the event loop
	#It might seem redundant that I have both things, but I intend to have a continous
	#editing method, which would need the looper.
	def QuitEdit(self,cid):
		#Close event ID
		self.TweakPlot.mpl_disconnect(cid)
		#Stop event loop
		self.TweakPlot.stop_event_loop()
	#Function when "Add Point" button is clicked.
	def AddPoint(self):
		#Show Tutorial message for what to do.
		if usetutorial: tkMessageBox.showinfo("Help Message", "Click where to add point.")
		#Start mouse click event, and run CT.ClickAdd
		self.cidbut=self.TweakPlot.mpl_connect('button_press_event',self.ClickAdd)
		self.TweakPlot.start_event_loop(0)
		#If use continuous button is on, repeat adding points
		while self.useContinuous.get():
			if usetutorial: tkMessageBox.showinfo("Help Message", "Continuous point addition on. Keep adding points.")
			try:
				self.cidbut=self.TweakPlot.mpl_connect('button_press_event',self.ClickAdd)
				self.TweakPlot.start_event_loop(0)
			except: self.useContinuous.set(False)
	#Given a mouse event for adding a point...	
	def ClickAdd(self,event):
		#Grab the x/y coordiantes of the click, and add to spline
		self.xspline.append(event.xdata)
		self.yspline.append(event.ydata)
		#Sort the spline data to be in order by wavelength
		self.xspline,self.yspline=SortList(self.xspline,self.yspline)
		#Refresh the plot with new data, but keep y-axis
		self.Refresh(yrefresh=False)
		#Close the MPL event stuff
		self.QuitEdit(self.cidbut)
	#Function ro remove a point when "Remove Point" button pressed
	def RemovePoint(self):
		#Show tutorial message on what to do
		if usetutorial: tkMessageBox.showinfo("Help Message", "Click point to remove.")
		#Start MPL event for picking an MPL artist, and start the loop. Run CT.ClickRemove
		self.cidpick=self.TweakPlot.mpl_connect('pick_event',self.ClickRemove)
		self.TweakPlot.start_event_loop(0)
		#If Use continuous button is on, repeat removing points
		while self.useContinuous.get():
			if usetutorial: tkMessageBox.showinfo("Help Message", "Continuous point removal on. Keep removing points.")
			try:
				self.cidpick=self.TweakPlot.mpl_connect('pick_event',self.ClickRemove)
				self.TweakPlot.start_event_loop(0)
			except:
				self.useContinuous.set(False)
	#Given a picker event for removing a point...
	def ClickRemove(self,event):
		#Get the spline point that you picked, it's x and y coordinates
		splinepoint = event.artist
		xsplineval=splinepoint.get_xdata()
		ysplineval=splinepoint.get_ydata()
		#Index of the artist
		ind = event.ind
		#Make sure the point is in the spline point lists
		if xsplineval[ind] in self.xspline:
			if ysplineval[ind] in self.yspline:
				#Remove that point from the spline, I think this is where sorting is important...
				self.xspline.pop(ind)
				self.yspline.pop(ind)
		#Refresh the plot with new spline, but keep y-axis
		self.Refresh(yrefresh=False)
		#Close the event and stop the event loop
		self.QuitEdit(self.cidpick)
	#Function saves the spline using SaveSpline function
	def Save(self):
		print "Saving Spline"
		SaveSpline(self.xspline,self.yspline,self.iwvlngth,self.outfile)
	#Destroy CT.POPUP and CT.TFROOT (the masters for the CT buttons and plots) and leave CT.
	def Exit(self):
		self.popup.destroy()
		self.TFroot.destroy()
		return
Example #21
0
class ImageLoadedLayout:
    def __init__(self, root_frame, img_fig, plot_fig):
        print('hi from ImageLoadedLayout')

        self.root_frame = root_frame

        self.root_frame.columnconfigure(0, weight=1)
        self.root_frame.rowconfigure(1, weight=1)

        self.toolbar_frame = ttk.Frame(self.root_frame)
        self.toolbar_frame.grid(column=0, row=0, sticky=('W', 'N', 'E', 'S'))

        self.toolbar_frame.columnconfigure(0, weight=1)
        self.toolbar_frame.rowconfigure(1, weight=1)

        self.back_btn = ttk.Button(self.toolbar_frame, text='Back')
        self.back_btn.grid(column=0, row=0, sticky='W')

        s = ttk.Style()
        s.configure('figures.TFrame', background='#334353')
        self.figure_frame = ttk.Frame(self.root_frame, style='figures.TFrame')
        self.figure_frame.grid(column=0, row=1, sticky=('W', 'N', 'E', 'S'))

        self.figure_frame.columnconfigure(0, weight=1)
        self.figure_frame.columnconfigure(1, weight=1)
        self.figure_frame.rowconfigure(0, weight=1)

        self.img_fig = img_fig
        self.img_canvas = FigureCanvasTkAgg(self.img_fig,
                                            master=self.figure_frame)
        self.img_canvas.get_tk_widget().grid(column=0,
                                             row=0,
                                             sticky=('W', 'N', 'E', 'S'))
        self.img_canvas.draw()

        self.plot_fig = plot_fig
        self.plot_canvas = FigureCanvasTkAgg(self.plot_fig,
                                             master=self.figure_frame)
        self.plot_canvas.get_tk_widget().grid(column=1,
                                              row=0,
                                              sticky=('W', 'N', 'E', 'S'))
        self.plot_canvas.draw()

        self.info_frame = ttk.Frame(self.root_frame)
        self.info_frame.grid(column=0, row=2, sticky=('W', 'N', 'E', 'S'))

        self.info_frame.columnconfigure(0, weight=1)
        #self.info_frame.rowconfigure(0, weight=1)

        ttk.Label(self.info_frame,
                  text='Additional Information May Go Here').grid(column=0,
                                                                  row=0)

    def img_mpl_connect(self, event_type, callback):
        return self.img_canvas.mpl_connect(event_type, callback)

    def img_mpl_disconnect(self, cid):
        self.img_canvas.mpl_disconnect(cid)

    def plot_mpl_connect(self, event_type, callback):
        return self.plot_canvas.mpl_connect(event_type, callback)

    def plot_mpl_disconnect(self, cid):
        self.plot_canvas.mpl_disconnect(cid)

    def redraw_img_fig(self):
        self.img_canvas.draw()

    def redraw_plot_fig(self):
        self.plot_canvas.draw()

    def set_back_callback(self, callback):
        self.back_btn['command'] = callback

    def clean_up(self):
        self.info_frame.grid_forget()
        self.info_frame.destroy()

        self.figure_frame.grid_forget()
        self.figure_frame.destroy()

        self.toolbar_frame.grid_forget()
        self.toolbar_frame.destroy()
Example #22
0
class PyplotEmbed(tk.Frame):
    """
    Class that will make a tkinter frame with a matplotlib plot area embedded in the frame
    """
    def __init__(self, master, data):
        tk.Frame.__init__(self, master=master)
        self.index = 1
        self.lines = []
        self.vert_line = None
        self.data = data
        self.cursor_connect = None

        self.graph_area = tk.Frame(self)
        self.figure_bed = plt.figure(figsize=(6,4))
        self.axis = self.figure_bed.add_subplot(111)

        self.canvas = FigureCanvasTkAgg(self.figure_bed, master=self)
        self.canvas._tkcanvas.config(highlightthickness=0)
        self.toolbar = NavToolbar(self.canvas, self)  # TODO: check this
        # self.toolbar.pack_forget()
        self.toolbar.pack()

        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side='left', fill=tk.BOTH, expand=1)

    def plot(self, data, _label):
        # self.data.plot(ax=self.graph_area.axis, label='channel {0}'.format(self.index))
        # line = self.axis.plot(data.index, data['voltage'], label=_label)[0]
        line = self.axis.plot(data.index, data, label=_label)[0]
        self.lines.append(line)
        self.axis.legend()
        self.index += 1
        self.canvas.show()

    def delete_all(self):
        while self.lines:
            l = self.lines.pop()
            l.remove()
            del l
        self.canvas.draw()
        self.index = 1
        self.axis.legend()

    def time_shift(self, data_index: int, time_to_shift: float):
        adj_time_shift = time_to_shift - self.data.time_start[data_index]

        x_data = self.data.adjusted_data[data_index].index - adj_time_shift
        self.lines[data_index].set_xdata(x_data)
        self.canvas.draw()

    def get_fit_start(self):
        print('make cursor')
        # cursor = self.axis.axvline(color='r')
        self.cursor_connect = self.canvas.mpl_connect('motion_notify_event', self.onMouseMove)
        self.canvas.mpl_connect('button_press_event', self.onclick)
        self.canvas.show()


    def onMouseMove(self, event):
        if not event.xdata:  # mouse is not over the plot area
            return
        if self.vert_line:
            self.vert_line.remove()
            del self.vert_line
            self.vert_line = None
        self.vert_line = self.axis.axvline(x=event.xdata, color='r', linewidth=2)
        self.canvas.show()

    def onclick(self, event):
        if event.dblclick == 1:
            full_data_set = self.data.adjusted_data[-1]
            start_index = full_data_set.index.get_loc(event.xdata, 'nearest')
            # start_index = pd.Index(self.data.adjusted_data[-1]).get_loc(event.xdata, 'nearest')
            start_num = full_data_set.index[start_index]
            data_to_fit = self.data.adjusted_data[-1][start_num:start_num+20]

            self.fit_data(data_to_fit, start_num)

    def fit_data(self, _data, starting_place):
        print('fitting')
        self.canvas.mpl_disconnect(self.cursor_connect)
        t = _data.index - starting_place # change the time so t=0 at the start of the recording
        amplitude_guess = -_data.voltage.min()
        time_shift = 0
        bounds = (
        0.0, [1.2*amplitude_guess, 1.2*amplitude_guess, 1.2*amplitude_guess, 1.2*amplitude_guess, 0.2, 2, 100, 100])
        initial_guess = (
        2. * amplitude_guess / 3, amplitude_guess / 3., amplitude_guess / 2., amplitude_guess / 2., 0.2, 2, 2, 15)

        fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp, t, _data.voltage,
                                         p0=initial_guess, bounds=bounds,
                                         ftol=0.0000005, xtol=0.0000005)
        # fitted_parameters, _ = curve_fit(fitting_func_2a_2i_exp, t, _data.voltage, p0=initial_guess)
        print('fitting params: {0}'.format(fitted_parameters))

        # make a new line with the fitted parameters and draw it
        y_fitted = fitting_func_2a_2i_exp(t, *fitted_parameters)
        # plt.plot(t + _data.index, y_fitted, linewidth=2, label="Check")
        fitted_line = self.axis.plot(_data.index,  y_fitted, linewidth=2, label='fitted')[0]
class Interface(object):
    """Test"""
    def __init__(self):
        self.kymogen = KymoGen()
        self.image_index = 1
        self.len_img_stack = 0
        self.overlay = False
        self.images_loaded = False

        self.store_datapoints = []

        self.cid = None

        self.gui = tk.Tk()
        self.gui.wm_title("KymoGen")

        self.top_frame = tk.Frame(self.gui, width=1200, height=10)
        self.top_frame.pack(fill="x")

        self.load_stack_button = tk.Button(self.top_frame,
                                           command=self.load_stack,
                                           text="Load Stack",
                                           width=10)
        self.load_stack_button.pack(side="left")

        self.draw_button = tk.Button(self.top_frame,
                                     command=self.draw_region_of_interest,
                                     text="Draw ROI",
                                     width=10)
        self.draw_button.pack(side="left")
        self.draw_button.config(state="disabled")

        self.next_image_button = tk.Button(self.top_frame,
                                           command=self.next_image,
                                           text="Next Image",
                                           width=10)
        self.next_image_button.pack(side="right")
        self.next_image_button.config(state="disabled")

        self.previous_image_button = tk.Button(self.top_frame,
                                               command=self.previous_image,
                                               text="Previous Image",
                                               width=10)
        self.previous_image_button.pack(side="right")
        self.previous_image_button.config(state="disabled")

        self.image_index_status = tk.StringVar()
        self.image_index_status.set("No Image Loaded")

        self.image_index_label = tk.Label(self.top_frame,
                                          textvariable=self.image_index_status)
        self.image_index_label.pack(side="right")

        self.show_overlay_button = tk.Button(self.top_frame,
                                             command=self.show_overlay,
                                             text="Show Overlay",
                                             width=10)
        self.show_overlay_button.pack(side="left")
        self.show_overlay_button.config(state="disabled")

        self.hide_overlay_button = tk.Button(self.top_frame,
                                             command=self.hide_overlay,
                                             text="Hide Overlay",
                                             width=10)
        self.hide_overlay_button.pack(side="left")
        self.hide_overlay_button.config(state="disabled")

        self.gen_kymo_button = tk.Button(self.top_frame,
                                         command=self.gen_kymo,
                                         text="Generate Kymograph")
        self.gen_kymo_button.pack(side="left")
        self.gen_kymo_button.config(state="disabled")

        self.gen_kymo_button_3px_av = tk.Button(
            self.top_frame,
            command=self.gen_kymo_3px_average,
            text="Generate Kymograph 3px Average")
        self.gen_kymo_button_3px_av.pack(side="left")
        self.gen_kymo_button_3px_av.config(state="disabled")

        self.rescaling_label = tk.Label(self.top_frame, text="Use Rescaling: ")
        self.rescaling_label.pack(side="left")

        self.rescaling_value = tk.BooleanVar()
        self.rescaling_label_checkbox = tk.Checkbutton(
            self.top_frame,
            variable=self.rescaling_value,
            onvalue=True,
            offvalue=False)
        self.rescaling_label_checkbox.pack(side="left")
        self.rescaling_value.set(False)

        self.middle_frame = tk.Frame(self.gui)
        self.middle_frame.pack(fill="x")

        self.fig = plt.figure(figsize=(22, 11), frameon=True)
        self.canvas = FigureCanvasTkAgg(self.fig, self.middle_frame)
        self.canvas.show()
        self.canvas.get_tk_widget().pack(side="top")

        self.ax = plt.subplot(111)
        plt.subplots_adjust(left=0, bottom=0, right=1, top=1)
        self.ax.axis("off")
        plt.autoscale(True)
        self.ax.format_coord = self.remove_coord

        self.canvas.show()
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.middle_frame)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(fill="both")

    def show_overlay(self):
        self.overlay = True

        self.show_image()

    def hide_overlay(self):
        self.overlay = False

        self.show_image()

    def gen_kymo(self):
        self.kymogen.rescaling = self.rescaling_value.get()
        self.kymogen.generate_kymograph()

    def gen_kymo_3px_average(self):
        self.kymogen.rescaling = self.rescaling_value.get()
        self.kymogen.generate_kymograph_3px_average()

    def load_stack(self):
        self.kymogen.img_stack = imread_collection(askopenfilename())
        self.len_img_stack = len(self.kymogen.img_stack)
        self.draw_button.config(state="active")
        self.next_image_button.config(state="active")
        self.image_index_status.set(
            str(self.image_index) + " of " + str(self.len_img_stack))

        self.show_image()

    def next_image(self):
        self.image_index += 1
        self.previous_image_button.config(state="active")

        if self.image_index == self.len_img_stack:
            self.next_image_button.config(state="disabled")

        self.image_index_status.set(
            str(self.image_index) + " of " + str(self.len_img_stack))
        self.show_image()

    def previous_image(self):
        self.image_index -= 1
        self.next_image_button.config(state="active")

        if self.image_index == 1:
            self.previous_image_button.config(state="disabled")

        self.image_index_status.set(
            str(self.image_index) + " of " + str(self.len_img_stack))
        self.show_image()

    def show_image(self):
        if self.images_loaded is True:
            xlim = self.ax.get_xlim()
            ylim = self.ax.get_ylim()

            self.ax.cla()
            self.ax.axis("off")

            self.ax.set_xlim(xlim)
            self.ax.set_ylim(ylim)
        else:
            self.images_loaded = True
            self.ax.cla()
            self.ax.axis("off")

        if self.overlay is False:
            image = self.kymogen.img_stack[self.image_index - 1]
        else:
            image = self.kymogen.img_stack_w_roi[self.image_index - 1]

        image = img_as_float(image)
        #image = rescale_intensity(image)

        self.ax.imshow(image)

        self.canvas.draw()
        self.canvas.show()

    def overlay_roi(self):
        self.kymogen.img_stack_w_roi = []
        for img in self.kymogen.img_stack:
            img = gray2rgb(img)

            for coords in self.kymogen.roi:
                img[coords[0], coords[1]] = (255, 0, 255)

            self.kymogen.img_stack_w_roi.append(img)
        self.overlay = True

        self.show_overlay_button.config(state="active")
        self.hide_overlay_button.config(state="active")
        self.gen_kymo_button.config(state="active")
        self.gen_kymo_button_3px_av.config(state="active")
        self.show_image()

    def stop_points(self, event):
        if event.button == 3:
            self.canvas.mpl_disconnect(self.cid_press)
            self.canvas.mpl_disconnect(self.cid_motion)
            self.canvas.mpl_disconnect(self.cid_release)

            self.kymogen.roi = np.array(
                list(OrderedDict.fromkeys(self.store_datapoints)))
            x0, y0 = np.amin(self.kymogen.roi, axis=0)
            x1, y1 = np.amax(self.kymogen.roi, axis=0)
            self.kymogen.box = x0, y0, x1, y1
            self.store_datapoints = []

            self.overlay_roi()

    def start_points(self, event):

        if event.button == 3:
            self.cid_motion = self.canvas.mpl_connect("motion_notify_event",
                                                      self.get_points_of_roi)

    def get_points_of_roi(self, event):
        self.store_datapoints.append((int(event.ydata), int(event.xdata)))

    def draw_region_of_interest(self):
        self.cid_press = self.canvas.mpl_connect("button_press_event",
                                                 self.start_points)
        self.cid_release = self.canvas.mpl_connect("button_release_event",
                                                   self.stop_points)

    def remove_coord(self, x, y):
        """"Hack" to remove the mpl coordinates"""
        return str(x) + " , " + str(y)
Example #24
0
class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.f = Figure(figsize=(8, 6), dpi=100)
        self.mainPlot = self.f.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.f, self.master)
        self.cid = self.canvas.mpl_connect("button_press_event",
                                           self.canvasClick)
        self.canvas.draw()
        self.canvas_tk = self.canvas.get_tk_widget().pack(side=tk.BOTTOM,
                                                          fill=tk.BOTH,
                                                          expand=True)

    def canvasClick(self, event):
        global CONFIG_VRANGE, CONFIG_SAMPLERATE, CONFIG_SAMPLECOUNT, CONFIG_FPREFIX, CONFIG_THRESHOLD, CONFIG_CAPTURES, CONFIG_BACKOFF, CONFIG_DONOTSAVE, CONFIG_SPECGRAM, CONFIG_DISPLAY_SAMPLES
        try:
            ps = ps2000a.PS2000a()
            self.canvas.mpl_disconnect(self.cid)
            print("Committing capture...")
        except:
            print("Failed to commit scope")
            return
        ps.setChannel('A',
                      'DC',
                      VRange=CONFIG_VRANGE,
                      VOffset=0.0,
                      enabled=True,
                      BWLimited=False,
                      probeAttenuation=10.0)
        (freq, maxSamples) = ps.setSamplingFrequency(CONFIG_SAMPLERATE,
                                                     CONFIG_SAMPLECOUNT)
        print(" > Asked for %d Hz, got %d Hz" % (CONFIG_SAMPLERATE, freq))
        if CONFIG_FPREFIX is not None:
            print(" > Configured in training mode with prefix %s" %
                  CONFIG_FPREFIX)
        ps.setSimpleTrigger('A', CONFIG_THRESHOLD, 'Rising', enabled=True)
        i = 0
        nCount = 0
        nMax = CONFIG_CAPTURES
        print("Capture is committed...")
        while True:
            if nMax == nCount:
                break
            ps.runBlock(pretrig=0.2)
            ps.waitReady()
            dataA = ps.getDataV("A", CONFIG_SAMPLECOUNT, returnOverflow=False)
            # print(len(dataA))
            SLICE_START = int(CONFIG_SAMPLECOUNT * 0.2)
            SLICE_END = SLICE_START + 500
            if float(max(
                    dataA[SLICE_START:SLICE_END])) < float(CONFIG_THRESHOLD):
                # print("failed capture")
                continue
            if CONFIG_DONOTSAVE is False:
                if CONFIG_FPREFIX is None:
                    print("Saving training capture...")
                    np.save("floss/%d.npy" % nCount, dataA)
                else:
                    print("Saving real capture...")
                    np.save("toothpicks/%s-%d.npy" % (CONFIG_FPREFIX, nCount),
                            dataA)
            else:
                print("No save mode specified, discarding save")
            self.mainPlot.clear()
            data_DISPLAY = dataA[SLICE_START - 5000:SLICE_START + 5000]
            if CONFIG_SPECGRAM:
                self.mainPlot.specgram(data_DISPLAY,
                                       NFFT=1024,
                                       Fs=CONFIG_SAMPLERATE,
                                       noverlap=900)
            else:
                self.mainPlot.plot(
                    support.block_preprocess_function(data_DISPLAY))
            self.canvas.draw()
            self.canvas.flush_events()
            time.sleep(CONFIG_BACKOFF)
            nCount += 1
        print("Captured %d slices" % nCount)
Example #25
0
class LocalizationPlot:
    def __init__(self, frame, tag_filter, tag_var,ran):

        self.frame = frame
        self.tag_filter = tag_filter
        self.tag_var = tag_var
        self.ran = ran

        self.fig = plt.figure(figsize=(20,10))

        self.ax = self.fig.add_subplot(111)



        # Hollow out
        self.canvas = FigureCanvasTkAgg(self.fig, master=frame)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=False)
        self.canvas.mpl_connect("button_press_event", self.input_Motionx_y)
        self.canvas.mpl_connect("button_release_event", self.output_Motionx_y)
        self.canvas.mpl_connect("scroll_event", self.zoom)



    # We only want the latest 80 plot
    # update and cancel the previous one
    def update_plot(self, data, p_num):

        xs = []
        ys = []
        try:
            for i in range(self.tag_filter.counter):
                xs.append(data[self.tag_var.get()]['pos'][0])
                ys.append(data[self.tag_var.get()]['pos'][1])
        except:
            self.tag_var.set(list(data.keys())[0])
            for i in range(self.tag_filter.counter):
                xs.append(data[self.tag_var.get()]['pos'][0])
                ys.append(data[self.tag_var.get()]['pos'][1])

        self.ax.cla()
        self.ax.set(xlabel='x Axis (m)', ylabel='y Axis (m)', title = "Number: %d" % p_num)

        # # Update the right label
        for i in range(len(xs)):
            self.ax.plot(xs[i], ys[i], '.',   color='#00BFFF',
                              visible=self.tag_var.get())

        self.ax.set_xlim(self.ran[0], self.ran[1])
        self.ax.set_ylim(self.ran[2], self.ran[3])
        self.canvas.draw()

    def input_Motionx_y(self,event):
        self.c_list_x = []
        self.c_list_y = []
        self.c_list_x.append(event.x)
        self.c_list_y.append(event.y)
        self.move_f = self.canvas.mpl_connect("motion_notify_event", self.moveon)

    def output_Motionx_y(self,event):
        self.canvas.mpl_disconnect(self.move_f)

    def zoom(self,event):
        if event.button == "up":
            self.ran[0] += 0.05
            self.ran[1] -= 0.05
            self.ran[2] += 0.05
            self.ran[3] -= 0.05
            self.ax.set_xlim(self.ran[0], self.ran[1])
            self.ax.set_ylim(self.ran[2], self.ran[3])
        else:
            self.ran[0] -= 0.05
            self.ran[1] += 0.05
            self.ran[2] -= 0.05
            self.ran[3] += 0.05
            self.ax.set_xlim(self.ran[0], self.ran[1])
            self.ax.set_ylim(self.ran[2], self.ran[3])
    def getrange(self):
        return self.ran

    def moveon(self,event):
        self.c_list_x.append(event.x)
        self.c_list_y.append(event.y)
        try:
            if self.c_list_x[-1]-self.c_list_x[-2] >0:
                res_x = event.xdata
                x_c = eval(str(self.ran[1]) + "-" + str(self.ran[0])) / 50
                self.ran[0] -= (res_x) * x_c
                self.ran[1] -= (res_x) * x_c
            else:
                res_x = event.xdata
                x_c = eval(str(self.ran[1]) + "-" + str(self.ran[0])) / 50
                self.ran[0] -= (res_x) * x_c
                self.ran[1] -= (res_x) * x_c

            if self.c_list_y[-1]-self.c_list_y[-2] >0:
                res_y = event.ydata
                y_c = eval(str(self.ran[3]) + "-" + str(self.ran[2]))/5
                self.ran[2] -= (res_y) * y_c
                self.ran[3] -= (res_y) * y_c
                self.ax.set_xlim(self.ran[0], self.ran[1])
                self.ax.set_ylim(self.ran[2], self.ran[3])

            elif self.c_list_y[-1]-self.c_list_y[-2] == 0:
                pass
            else:
                res_y = event.ydata
                y_c = eval(str(self.ran[3]) + "-" + str(self.ran[2]))/10
                self.ran[2] -= (res_y) * y_c
                self.ran[3] -= (res_y) * y_c
                self.ax.set_xlim(self.ran[0], self.ran[1])
                self.ax.set_ylim(self.ran[2], self.ran[3])
        except:
            pass
Example #26
0
class data_interpreter(tk.Frame):
    #single instrument
    def __init__(self, master, root, name, file, plot_index):
        tk.Frame.__init__(self, master)
        self.config(border = 2)
        self.master = master
        self.root = root
        self.plot_frame_row = -1
        self.plot_frame_column = -1

        self.grid_rowconfigure(0,weight = 1)
        self.grid_columnconfigure(0, weight = 1)

        self.name = name #this will be plot title
        self.file = file #open file not file path
        self.plot_index = plot_index #where to plot the data
        self.time = []
        self.data = []
        self.units = []

        #read data
        self.read_data()

        #plot_data
        self.fig = plt.Figure()#figsize=(10,10))
        self.ax = self.fig.add_subplot(1,1,1)
        self.line, = self.ax.plot(self.time, self.data)
        self.ax.set_title(self.name)
        self.canvas = FigureCanvasTkAgg(self.fig,self)
        self.canvas.show()
        self.canvas_widget = self.canvas.get_tk_widget()
        self.canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        self.canvas._tkcanvas.grid(row = 0, column = 0, sticky = 'nsew')

        self.selected = False

        self.selected_intervals = [] #times for the beginning and end of each interval
        self.selected_vlines = [] #lines to place at selected intervals
                
        self.selected_time = [] #times within interval to plot
        self.selected_data = [] #cooresponding data to plot
        self.mean_time = []
        self.mean_data = []
        self.std_dev = []

        self.getting_coordinates = False
        self.connectid = None

        #select button
        self.select_btn = ttk.Button(self, text = 'Select Graph', command = lambda: self.select_graph())
        self.select_btn.grid(row = 1, column = 0, sticky = 'nsew')

    def reinit_toselectframe(self, master):
        self.master = master #overwrite previous master frame
        tk.Frame.__init__(self, self.master)
        self.grid_rowconfigure(0, weight = 1)
        self.grid_columnconfigure(0, weight = 1)
        self.config(border = 2, relief = tk.GROOVE)
        self.fig = plt.Figure()
        self.ax = self.fig.add_subplot(1,1,1)
        self.line, = self.ax.plot(self.time, self.data)
        self.ax.set_title(self.name)
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas_widget = self.canvas.get_tk_widget()
        self.canvas_widget.grid(row = 0, column = 0, sticky = 'nsew')#pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        self.canvas._tkcanvas.grid(row = 0, column = 0, sticky = 'nsew')

        self.navigator_frame = tk.Frame(self)
        self.navigator_frame.grid(row = 1, column = 0, sticky = 'nsew')
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.navigator_frame)
        self.toolbar.update()

        self.get_coordinates_btn = ttk.Button(self, text = 'Select Intervals', command = lambda: self.get_coordinates())
        self.get_coordinates_btn.grid(row = 2, column = 0, sticky = 'nsew')

    def reinit_toplotframe(self, master):
        self.master = master #overwrite previous master frame
        tk.Frame.__init__(self, self.master)
        self.grid_rowconfigure(0, weight = 1)
        self.grid_columnconfigure(0, weight = 1)
        self.config(border = 2, relief = tk.GROOVE)
        self.fig = plt.Figure()
        self.ax = self.fig.add_subplot(1,1,1)
        self.line, = self.ax.plot(self.time, self.data)
        self.ax.set_title(self.name)
        self.canvas = FigureCanvasTkAgg(self.fig, self)
        self.canvas.show()
        self.canvas_widget = self.canvas.get_tk_widget()
        self.canvas_widget.grid(row = 0, column = 0, sticky = 'nsew')#pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        self.canvas._tkcanvas.grid(row = 0, column = 0, sticky = 'nsew')

        self.select_btn = ttk.Button(self, text = 'Select Graph', command = lambda: self.select_graph())
        self.select_btn.grid(row = 1, column = 0, sticky = 'nsew')


    def read_data(self):
        for line in self.file:
            datalist = line.split(',')
            if len(datalist) > 1:
                try:
                    self.time.append(float((datetime.datetime.strptime(datalist[0], '%Y-%m-%d %H:%M:%S.%f') - datetime.datetime(1970,1,1)).total_seconds()))
                    self.data.append(float(datalist[1]))
                except ValueError:
                    try:
                        self.time.append(float((datetime.datetime.strptime(datalist[0], '%Y-%m-%d %H:%M:%S') - datetime.datetime(1970,1,1)).total_seconds()))
                        self.data.append(float(datalist[1]))
                    except ValueError:
                        pass
            if len(datalist) > 2:
                self.units.append(datalist[2])
            else:
                self.units.append(None)

    def select_graph(self):
        if self.selected:
            self.select_btn.config(text = 'Select Graph')
            self.config(relief = tk.FLAT)
        else:
            self.select_btn.config(text = 'Unselect Graph')
            self.config(relief = tk.GROOVE)
        self.selected = not self.selected

    def remove_plot(self):
        self.ax.lines.remove(self.line)

    def get_coordinates(self):
        if self.getting_coordinates is None: #then button has been pressed just after initilization and need to start getting interals
            self.get_coordinates_btn.config(text = 'Stop Selecting Intervals... ')
            self.connectid = self.canvas.mpl_connect('button_press_event', self.on_click)
            self.getting_coordinates = True
        else:
            if self.getting_coordinates:
                #then stop getting coordinates
                self.get_coordinates_btn.config(text = 'Updating Curves...')
                #send selected coordinates to root
                self.root.selected_intervals = self.selected_intervals
                try:
                    self.canvas.mpl_disconnect(self.connectid)
                    self.root.use_intervals()
                    self.get_coordinates_btn.config(text = 'Select Intervals')
                except SystemError:
                    pass
            else:
                #then something went wrong.  Logic shouldn't allow this code to run 
                self.get_coordinates_btn.config(text = 'Stop Selecting Intervals... ')
                self.connectid = self.canvas.mpl_connect('button_press_event', self.on_click)
            self.getting_coordinates = not self.getting_coordinates

    def on_click(self, event):
        #get the x and y coords, flip y from top to bottom
        x, y = event.x, event.y
        if event.button == 1:
            if event.inaxes is not None:
                print('data coords %f %f' % (event.xdata, event.ydata))
                #self.root.selected_times.append(event.xdata)
                self.selected_intervals.append(event.xdata)
                #plot vertical lines on this interpreter
                line = self.ax.axvline(x = event.xdata, color = 'r')
                self.selected_vlines.append(line)

                #plot vertical lines on other selected interpreters
                for interpreter in self.root.selected_interpreter_list:
                    if interpreter.name != self.name: #only do this for other selected interpreters
                        other_line = interpreter.ax.axvline(x = event.xdata, color = 'r')
                        interpreter.selected_vlines.append(other_line)
                        interpreter.canvas.draw()
        if event.button == 3:
            if event.inaxes is not None:
                self.selected_intervals = self.selected_intervals[:-1]
                self.ax.lines.remove(self.selected_vlines[-1])
                #remove vertical lines from other selected interpreters
                for interpreter in self.root.selected_interpreter_list:
                    if interpreter.name != self.name: #only do this for other selected interpreters
                        interpreter.ax.lines.remove(interpreter.selected_vlines[-1])
                        interpreter.canvas.draw()

        self.canvas.draw()