Example #1
0
def plot_line_graph(data_length):
    lists = sorted(data_length.items())
    line_graphs = []
    protocols, data_lengths = zip(*lists)
    i = 0
    while i < len(data_lengths):
        r = random.random()
        b = random.random()
        g = random.random()
        color = (r, g, b)
        figure = plt.Figure(figsize=(4, 5), dpi=100)
        ax = figure.add_subplot(111)
        ax.set_title("Lengths of packets in " + protocols[i] + " protocol")
        line = FigureCanvasTkAgg(figure, root)
        line = line.get_tk_widget()
        line.grid(row=5, column=i)
        line_graphs.append(line)
        data = {
            'Indices': range(0, len(data_lengths[i])),
            'Data lengths': data_lengths[i]
        }
        data_frame = DataFrame(data, columns=['Indices', 'Data lengths'])
        data_frame = data_frame[['Indices',
                                 'Data lengths']].groupby('Indices').sum()
        data_frame.plot(kind='line', legend=True, ax=ax, color=color)
        i += 1
    return line_graphs
Example #2
0
 def __init__(self, *args, **kwargs):
     tk.Tk.__init__(self, *args, **kwargs)
     global window
     window = self
     for button in buttons:
         row, column, text, press, release = button
         b = ttk.Button(self, text=text)
         b.bind("<ButtonPress-1>",
                (lambda press: (lambda event: press()))(press))
         b.bind("<ButtonRelease-1>",
                (lambda release: (lambda event: release()))(release))
         b.grid(row=row, column=column)
     for checkbox in checkboxes:
         row, column, text, command = checkbox
         variable = tk.IntVar()
         checkbox_variables.append(variable)
         ttk.Checkbutton(self,
                         text=text,
                         variable=variable,
                         command=command).grid(row=row, column=column)
     for radio_button_group in radio_button_groups:
         radio_buttons, command = radio_button_group
         variable = tk.IntVar()
         radio_button_variables.append(variable)
         for radio_button in radio_buttons:
             row, column, text, value = radio_button
             ttk.Radiobutton(self,
                             text=text,
                             variable=variable,
                             value=value,
                             command=command).grid(row=row, column=column)
     for message in messages:
         row, column, columnspan = message
         variable = tk.StringVar()
         message_variables.append(variable)
         m = tk.Label(self)
         m.config(font=("Verdana", 14), textvariable=variable)
         m.grid(row=row, column=column, columnspan=columnspan)
     global canvas
     if use_matplotlib:
         canvas = FigureCanvasTkAgg(figure, self)
         if fixed_size:
             axes.set_xlim(0, 1)
             axes.set_ylim(0, 1)
         canvas.show()
         if click_command:
             canvas.mpl_connect('button_press_event',
                                lambda event: click_command(event.xdata,
                                                            event.ydata))
         canvas.get_tk_widget().grid(row=button_rows,
                                     columnspan=button_columns)
     else:
         canvas = tk.Canvas(self, width=window_width, height=window_height)
         canvas.grid(row=button_rows, columnspan=button_columns)
     self.bind("<Control-c>", lambda event: done())
     self.bind("<Escape>", lambda event: done())
Example #3
0
def plot_bar_graph(dictionary, key_title, value_title, title):
    lists = sorted(dictionary.items())
    x, y = zip(*lists)
    data = {key_title: x, value_title: y}
    data_frame = DataFrame(data, columns=[key_title, value_title])
    figure = plt.Figure(figsize=(5, 4), dpi=100)
    ax = figure.add_subplot(111)
    ax.set_title(title)
    bar = FigureCanvasTkAgg(figure, root)
    bar = bar.get_tk_widget()
    bar.grid(row=4, column=1)
    df = data_frame[[key_title, value_title]].groupby(key_title).sum()
    df.plot(kind='bar', legend=True, ax=ax)
    return bar
Example #4
0
    class Main(MainFrame):
        def content(self, master):
            # self.button = tk.Button(
            #     master,
            #     text = "Run attack (running run.sh)",
            #     command = self.on_click_hello
            # )
            # self.button.pack(padx=2, pady=2, fill=tk.X)
            '''Initializing the console inside a scrollbar area'''
            self.console = 
            
            '''Initializing and displaying graph inside a canvas'''
            self.canvas = FigureCanvasTkAgg(calc_and_parse_graph(), master=self.parent)  # A tk.DrawingArea.
            self.canvas.draw()
            self.canvas.grid(column=0, row=0, colspan=2, rowspan=2)
            self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
            #self.canvas.toolbar = NavigationToolbar2Tk(self.canvas, self.parent)
            #self.canvas.toolbar.update()

        def on_click_hello(self):
            print("hello world!")
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        name = self.controller.currentResultFolder

        if name != "abc":

            cur_dir_path = os.path.dirname(os.path.realpath(__file__))
            path = Path(cur_dir_path)
            path = path.parent.parent
            reference = os.path.join(
                path,
                os.path.join('ZZoutput',
                             os.path.join(name, 'results_' + name + '.txt')))

            if controller.justEnteredViewParameter == 1:
                with open(reference) as ff:
                    dataRef = json.load(ff)
                controller.dataRef = dataRef
                controller.justEnteredViewParameter = 0
            else:
                dataRef = controller.dataRef

            nbWellsRef = len(dataRef["wellPoissMouv"])

            numWell = self.controller.numWell
            numPoiss = self.controller.numPoiss
            numMouv = self.controller.numMouv

            nbWells = len(dataRef["wellPoissMouv"])
            if numWell >= nbWells:
                if nbWells == 0:
                    numWell = 0
                else:
                    numWell = nbWells - 1
            nbPoiss = len(dataRef["wellPoissMouv"][numWell])

            if numPoiss >= nbPoiss:
                if nbPoiss == 0:
                    numPoiss = 0
                else:
                    numPoiss = nbPoiss - 1
            nbMouv = len(dataRef["wellPoissMouv"][numWell][numPoiss])

            if numMouv >= nbMouv:
                if nbMouv == 0:
                    numMouv = 0
                else:
                    numMouv = nbMouv - 1

            label = tk.Label(self, text="    ", font=LARGE_FONT)
            label.grid(row=1, column=6)

            ttk.Button(self,
                       text="View video for all wells together",
                       command=lambda: controller.showValidationVideo(
                           -1, 0, -1)).grid(row=1, column=1)

            # ttk.Button(self, text="Verify wells detection", command=lambda: controller.showValidationVideo(-1,0,-1)).grid(row=1,column=2, columnspan=2)

            label = tk.Label(self,
                             text=name,
                             font="bold",
                             justify=LEFT,
                             pady=10)
            label.grid(sticky=W, row=0, column=0, columnspan=8)

            label = tk.Label(self, text="Well number:")
            label.grid(row=2, column=1)
            e1 = tk.Entry(self)
            e1.insert(0, numWell)
            e1.grid(row=2, column=2)
            tk.Button(self,
                      text="-",
                      command=lambda: controller.printSomeResults(
                          int(e1.get()) - 1, e2.get(), e3.get())).grid(
                              row=2, column=3)
            tk.Button(self,
                      text="+",
                      command=lambda: controller.printSomeResults(
                          int(e1.get()) + 1, e2.get(), e3.get())).grid(
                              row=2, column=4)

            ttk.Button(self,
                       text="View zoomed video for well " + str(numWell),
                       command=lambda: controller.showValidationVideo(
                           e1.get(), 1, -1)).grid(row=3, column=2)

            def callback(url):
                webbrowser.open_new(url)

            link1 = tk.Button(self,
                              text="Video viewing tips",
                              cursor="hand2",
                              bg='red')
            link1.grid(row=3, column=4)
            link1.bind(
                "<Button-1>", lambda e: callback(
                    "https://zebrazoom.org/validationVideoReading.html"))

            label = tk.Label(self, text="Fish number:")
            label.grid(row=4, column=1)
            e2 = tk.Entry(self)
            e2.insert(0, numPoiss)
            e2.grid(row=4, column=2)
            tk.Button(self,
                      text="-",
                      command=lambda: controller.printSomeResults(
                          e1.get(),
                          int(e2.get()) - 1, e3.get())).grid(row=4, column=3)
            tk.Button(self,
                      text="+",
                      command=lambda: controller.printSomeResults(
                          e1.get(),
                          int(e2.get()) + 1, e3.get())).grid(row=4, column=4)

            label = tk.Label(self, text="Bout number:")
            label.grid(row=5, column=1)
            e3 = tk.Entry(self)
            e3.insert(0, numMouv)
            e3.grid(row=5, column=2)
            tk.Button(self,
                      text="-",
                      command=lambda: controller.printSomeResults(
                          e1.get(), e2.get(),
                          int(e3.get()) - 1)).grid(row=5, column=3)
            tk.Button(self,
                      text="+",
                      command=lambda: controller.printSomeResults(
                          e1.get(), e2.get(),
                          int(e3.get()) + 1)).grid(row=5, column=4)

            button1 = ttk.Button(self,
                                 text="View bout's angle",
                                 command=lambda: controller.printSomeResults(
                                     e1.get(), e2.get(), e3.get()))
            button1.grid(row=6, column=2)

            if (len(dataRef["wellPoissMouv"][numWell][numPoiss]) > 0):

                if ("flag" in dataRef["wellPoissMouv"][numWell][numPoiss]
                    [numMouv]):
                    if (dataRef["wellPoissMouv"][numWell][numPoiss][numMouv]
                        ["flag"]):
                        flagTxt = "UnFlag Movement"
                    else:
                        flagTxt = "Flag Movement"
                else:
                    flagTxt = "Flag Movement"

                button3 = tk.Button(self,
                                    text=flagTxt,
                                    command=lambda: controller.flagMove(
                                        e1.get(), e2.get(), e3.get()))
                if flagTxt == "UnFlag Movement":
                    button3.configure(bg='red')
                button3.grid(row=6, column=4)

            prev = ttk.Button(
                self,
                text="Previous Bout",
                command=lambda: controller.printPreviousResults(
                    e1.get(), e2.get(), e3.get(), nbWells, nbPoiss, nbMouv))
            prev.grid(row=7, column=1)

            next = ttk.Button(
                self,
                text="Next Bout",
                command=lambda: controller.printNextResults(
                    e1.get(), e2.get(), e3.get(), nbWells, nbPoiss, nbMouv))
            next.grid(row=7, column=2)

            tk.Button(self,
                      text="Go to the previous page",
                      command=lambda: controller.show_frame(
                          "ResultsVisualization")).grid(row=8, column=1)

            tk.Button(self,
                      text="Change Right Side Plot",
                      command=lambda: controller.printSomeResults(
                          e1.get(), e2.get(), e3.get(), True),
                      bg="light green").grid(row=8, column=2, columnspan=2)

            if (controller.superstructmodified == 1):
                button1 = tk.Button(self,
                                    text="Save SuperStruct",
                                    command=lambda: controller.saveSuperStruct(
                                        e1.get(), e2.get(), e3.get()))
                button1.configure(bg='orange')
                button1.grid(row=7, column=4)

            if nbMouv > 0:

                begMove = dataRef["wellPoissMouv"][numWell][numPoiss][numMouv][
                    "BoutStart"]
                endMove = dataRef["wellPoissMouv"][numWell][numPoiss][numMouv][
                    "BoutEnd"]

                ttk.Button(self,
                           text="View video for well " + str(numWell),
                           command=lambda: controller.showValidationVideo(
                               e1.get(), 0, begMove)).grid(row=3, column=1)

                ttk.Button(self,
                           text="View bout's video",
                           command=lambda: controller.showValidationVideo(
                               e1.get(), 1, begMove)).grid(row=6, column=1)

                if controller.visualization == 0 and not (
                        "TailAngle_smoothed" in dataRef["wellPoissMouv"]
                    [numWell][numPoiss][numMouv]):
                    controller.visualization = 1

                if controller.visualization == 1 and not (
                        "TailAngle_Raw" in dataRef["wellPoissMouv"][numWell]
                    [numPoiss][numMouv]):
                    controller.visualization = 2

                if controller.visualization == 2 and not (
                    (len(
                        np.unique(dataRef["wellPoissMouv"][numWell][numPoiss]
                                  [numMouv]["HeadX"])) > 1) and
                    (len(
                        np.unique(dataRef["wellPoissMouv"][numWell][numPoiss]
                                  [numMouv]["HeadY"])) > 1)):
                    controller.visualization = 0

                if controller.visualization == 0:
                    label = tk.Label(
                        self,
                        text="Tail Angle Smoothed and amplitudes for well " +
                        str(numWell) + ", fish " + str(numPoiss) + ", bout " +
                        str(numMouv),
                        font=LARGE_FONT)
                elif controller.visualization == 1:
                    label = tk.Label(self,
                                     text="Tail Angle Raw for well " +
                                     str(numWell) + ", fish " + str(numPoiss) +
                                     ", bout " + str(numMouv) +
                                     "                             ",
                                     font=LARGE_FONT)
                else:
                    label = tk.Label(self,
                                     text="Body Coordinates for well " +
                                     str(numWell) + " , fish " +
                                     str(numPoiss) + " , bout " + str(numMouv),
                                     font=LARGE_FONT)
                label.grid(row=1, column=7)

                if controller.visualization == 0:

                    tailAngleSmoothed = dataRef["wellPoissMouv"][numWell][
                        numPoiss][numMouv]["TailAngle_smoothed"].copy()

                    for ind, val in enumerate(tailAngleSmoothed):
                        tailAngleSmoothed[ind] = tailAngleSmoothed[ind] * (
                            180 / (math.pi))

                    if "Bend_Timing" in dataRef["wellPoissMouv"][numWell][
                            numPoiss][numMouv]:
                        freqX = dataRef["wellPoissMouv"][numWell][numPoiss][
                            numMouv]["Bend_Timing"]
                        freqY = dataRef["wellPoissMouv"][numWell][numPoiss][
                            numMouv]["Bend_Amplitude"]
                    else:
                        freqX = []
                        freqY = []
                    if type(freqY) == int or type(freqY) == float:
                        freqY = freqY * (180 / (math.pi))
                    else:
                        if "Bend_Timing" in dataRef["wellPoissMouv"][numWell][
                                numPoiss][numMouv]:
                            freqX = dataRef["wellPoissMouv"][numWell][
                                numPoiss][numMouv]["Bend_Timing"].copy()
                            freqY = dataRef["wellPoissMouv"][numWell][
                                numPoiss][numMouv]["Bend_Amplitude"].copy()
                        else:
                            freqX = []
                            freqY = []
                        for ind, val in enumerate(freqY):
                            freqY[ind] = freqY[ind] * (180 / (math.pi))
                    fx = [begMove]
                    fy = [0]
                    if (type(freqX) is int) or (type(freqX) is float):
                        freqX = [freqX]
                        freqY = [freqY]
                    for idx, x in enumerate(freqX):
                        idx2 = idx - 1
                        fx.append(freqX[idx2] - 1 + begMove)
                        fx.append(freqX[idx2] - 1 + begMove)
                        fx.append(freqX[idx2] - 1 + begMove)
                        fy.append(0)
                        fy.append(freqY[idx2])
                        fy.append(0)

                    f = Figure(figsize=(5, 5), dpi=100)
                    a = f.add_subplot(111)

                    if len(tailAngleSmoothed):
                        a.plot([i for i in range(begMove, endMove + 1)],
                               tailAngleSmoothed)
                        a.plot(fx, fy)
                        a.plot([i for i in range(begMove, endMove + 1)],
                               [0 for i in range(0, len(tailAngleSmoothed))])

                elif controller.visualization == 1:

                    tailAngleSmoothed = dataRef["wellPoissMouv"][numWell][
                        numPoiss][numMouv]["TailAngle_Raw"].copy()
                    for ind, val in enumerate(tailAngleSmoothed):
                        tailAngleSmoothed[ind] = tailAngleSmoothed[ind] * (
                            180 / (math.pi))

                    f = Figure(figsize=(5, 5), dpi=100)
                    a = f.add_subplot(111)

                    a.plot([i for i in range(begMove, endMove + 1)],
                           tailAngleSmoothed)
                    a.plot([i for i in range(begMove, endMove + 1)],
                           [0 for i in range(0, len(tailAngleSmoothed))])

                else:

                    headX = dataRef["wellPoissMouv"][numWell][numPoiss][
                        numMouv]["HeadX"].copy()
                    headY = dataRef["wellPoissMouv"][numWell][numPoiss][
                        numMouv]["HeadY"].copy()

                    f = Figure(figsize=(5, 5), dpi=100)
                    a = f.add_subplot(111)

                    a.plot(headX, headY)

                canvas = FigureCanvasTkAgg(f, self)
                canvas.draw()
                canvas.get_tk_widget().grid(row=2, column=7, rowspan=7)

            else:

                tailAngleSmoothed = [i for i in range(0, 1)]

                f = Figure(figsize=(5, 5), dpi=100)
                a = f.add_subplot(111)

                a.plot([i for i in range(0, len(tailAngleSmoothed))],
                       tailAngleSmoothed)

                canvas = FigureCanvasTkAgg(f, self)
                canvas.draw()
                canvas.get_tk_widget().grid(row=2, column=7, rowspan=7)

                canvas = Canvas(self)
                canvas.create_text(100,
                                   10,
                                   text="No bout detected for well " +
                                   str(numWell))
                canvas.grid(row=2, column=7, rowspan=7)
Example #6
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="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.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)

            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()

        #load data
        self.scdata = wishbone.wb.SCData.from_csv(os.path.expanduser(self.dataFileName), 
                data_type='sc-seq', normalize=self.normalizeVar.get())
        #get genes
        self.genes = self.scdata.data.columns.values

        #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')

        #set up visualization buttons
        tk.Label(self, text=u"Visualizations:", fg='black', bg='white').grid(column=0, row=1)
        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.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
        self.analysisMenu.entryconfig(0, state='normal')
        self.geometry('800x550')
        #destroy pop up menu
        self.fileInfo.destroy()

    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")
        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(5)
        tk.Entry(self.tsneOptions, textvariable=self.nCompVar).grid(column=1,row=0)
        tk.Button(self.tsneOptions, text="Run", command=self._runTSNE).grid(column=1, row=1)
        tk.Button(self.tsneOptions, text="Cancel", command=self.tsneOptions.destroy).grid(column=0, row=1)
        self.wait_window(self.tsneOptions)

    def _runTSNE(self):
        self.scdata.run_tsne(n_components=self.nCompVar.get())

        #enable buttons
        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')
        self.tsneOptions.destroy()

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

        #enable buttons
        self.analysisMenu.entryconfig(3, state='normal')
        self.analysisMenu.entryconfig(4, state='normal')
        self.visMenu.entryconfig(2, 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)

        #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)
        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())

        #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.component_menu.config(state='disabled')
        self.updateButton.config(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.component_menu.config(state='disabled')
        self.updateButton.config(state='disabled')
        
        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.component_menu.config(state='disabled')
        self.updateButton.config(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.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.component_menu.config(state='disabled')
        self.updateButton.config(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.component_menu.config(state='disabled')
            self.updateButton.config(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.component_menu.config(state='disabled')
            self.updateButton.config(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.component_menu.config(state='disabled')
            self.updateButton.config(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 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 #7
0
class BaseTab(ttk.Frame, ABC):
    def __init__(self, master=None, **kw):
        super().__init__(master=master, **kw)

        self.graph = None

    @abstractmethod
    def add_menu(self):
        pass

    def add_vertical_separator(self, column):
        ttk.Separator(self, orient='vertical')\
            .grid(row=0, column=column, pady=5, sticky='NS')

    def add_text_frame(self, row, column):
        frame = ScrollableFrame(self)
        frame.grid(row=row, column=column, sticky='NSWE')
        frame.grid_propagate(False)

        self.result = InfoLabel(frame.scrollable_frame, font=("Helvetica", 16))
        self.result.grid(row=1, column=0)

        frame.bind_vertical_scroll('<MouseWheel>', self)
        frame.bind_horizontal_scroll('<MouseWheel>', frame.scrollbar_x)

    def add_canvas(self, row, column, for_networkX=False):
        frame = ttk.Frame(self)
        frame.grid(row=row, column=column, sticky='NSWE')
        frame.grid_propagate(False)

        if not for_networkX:
            self.canvas = ResizingSquareCanvas(frame, width=1, height=1)
            self.canvas.grid(row=0, column=0)
        else:

            class CustomToolbar(NavigationToolbar2Tk):
                # only display the buttons we need
                toolitems = [
                    t for t in NavigationToolbar2Tk.toolitems
                    if t[0] in ('Home', 'Pan', 'Zoom', 'Save')
                ]

            figure = Figure(figsize=(5, 4),
                            constrained_layout=True,
                            frameon=False)
            self.axis = figure.add_subplot(111)
            self.axis.axis(False)
            self.canvas = FigureCanvasTkAgg(figure, master=frame)

            self.toolbar = CustomToolbar(self.canvas, frame)
            self.toolbar.update()

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

        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

    def draw_graph(self):
        pass

    def clear_graph(self):
        self.graph = None
        self.canvas.delete('all')

    def print_graph(self):
        if self.graph is not None:
            self.result.show_normal(str(self.graph))

    def clear_text(self):
        self.result.clear()

    def append_text(self, text):
        self.result.append(text)
Example #8
0
class ImageSession:
    def __init__(self, master, filename, hdu=0):
        # filename should be a string!
        self.filename = filename
        self.hdu = hdu
        
        # The master window?
        self.master = master
        
        if not os.path.exists(self.filename):
            tkMessageBox.showerror("File not found", "File {0} doesn't exist!".format(file))
            return
        
        self.openFile()
        self.createWindow()
    
    def openFile(self):
        # Try to open the file and read in the data from HDU
        try:
            hdulist = pf.open(self.filename)
            try:
                if hdulist[self.hdu].header['XTENSION'] == 'BINTABLE':
                    tkMessageBox.showerror("HDU Error", "The HDU {0} is not an ImageHDU!".format(self.hdu))
                    raise util.NotAnImageHDUError("The HDU {0} is not an ImageHDU!".format(self.hdu))
                # HDU is a table -- throw an error!
            except KeyError:
                # HDU is an image, carry on!
                pass
            
            self.rawData = hdulist[self.hdu].data
            self.rawData.shape
        except IOError:
            tkMessageBox.showerror("FITS file error ", "File {0} does not appear to be a valid FITS file!".format(self.filename))
            raise util.ImageSessionError("File {0} does not appear to be a valid FITS file!".format(self.filename))
        except AttributeError:
            tkMessageBox.showerror("FITS file error ", "File {0} does not appear to have data in HDU 0.".format(self.filename))
            raise util.ImageSessionError("File {0} does not appear to have data in HDU 0.".format(self.filename))
    
    def createWindow(self):
        # Create the actual window to draw the image and scale controls
        self.ImageWindow = Tk.Toplevel(self.master)
        self.ImageWindow.title(self.filename)
        #self.ImageWindow.protocol("WM_DELETE_WINDOW", self.closeImage)
        
        # TODO: THIS SHOULD DETECT SCREEN RESOLUTION
        screenSize = (1050/1.5, 1680/1.5)
        if self.rawData.shape[0] > screenSize[0] and self.rawData.shape[1] > screenSize[1]:
            factor1 = screenSize[0] / self.rawData.shape[0]
            factor2 = screenSize[1] / self.rawData.shape[1]
            self.zoomFactor = min([factor1, factor2])
        elif self.rawData.shape[1] > screenSize[0]:
            self.zoomFactor = screenSize[0]/ self.rawData.shape[1]
        elif self.rawData.shape[0] > screenSize[1]:
            self.zoomFactor = screenSize[1] / self.rawData.shape[0]
        else:
            self.zoomFactor = 1.
        
        # Create the image tools
        scaleTypeLabel = Tk.Label(self.ImageWindow, text="Scaling: ")
        scaleTypeLabel.grid(row=0, column=0)
        self.scalingName = Tk.StringVar()
        self.scalingName.set("arcsinh")
        self.scalingOption = Tk.OptionMenu(self.ImageWindow, self.scalingName, "arcsinh","linear","sqrt", command=self.setRescaler)
        self.scalingOption.grid(row=0, column=1)
        
        rescaleLabel = Tk.Label(self.ImageWindow, text="Rescale: ")
        rescaleLabel.grid(row=1, column=0)
        self.scaleValue = Tk.Scale(self.ImageWindow, from_=-4, to=6, resolution=0.05, orient=Tk.HORIZONTAL, showvalue=1, length=300)
        self.scaleValue.set(1.0)
        self.scaleValue.grid(row=1, column=1)
        
        minLabel = Tk.Label(self.ImageWindow, text="Min Pixel Value: ")
        minLabel.grid(row=2, column=0)
        self.minValue = Tk.Scale(self.ImageWindow, resolution=0.05, orient=Tk.HORIZONTAL, showvalue=1, length=300)
        self.minValue.set(1.0)
        self.minValue.grid(row=2, column=1)
        
        maxLabel = Tk.Label(self.ImageWindow, text="Max Pixel Value: ")
        maxLabel.grid(row=3, column=0)
        self.maxValue = Tk.Scale(self.ImageWindow, resolution=0.05, orient=Tk.HORIZONTAL, showvalue=1, length=300)
        self.maxValue.set(1.0)
        self.maxValue.grid(row=3, column=1)
        
        # Set the min/max slider boundaries
        self.minValue.config(from_=self.rawData.min(), to=self.rawData.max())
        self.minValue.set(self.rawData.min())
        self.maxValue.config(from_=self.rawData.min(), to=self.rawData.max())
        self.maxValue.set(self.rawData.max())
        
        # Set the default rescaler
        self.rescaler = util.arcsinhStretch
        
        self.scaleImage()
        self.drawImage()
        
        # Bind the sliders to the scaleImage() method
        self.scaleValue.bind("<ButtonRelease-1>", self.redraw)
        self.minValue.bind("<ButtonRelease-1>", self.redraw)
        self.maxValue.bind("<ButtonRelease-1>", self.redraw)
        self.scalingOption.bind("<ButtonRelease-1>", self.redraw)
        
    def setRescaler(self, event):
        self.rescaler = scalingTypes[self.scalingName.get()]
    
    def redraw(self, event=None):
        """ This rescales and redraws the image using the current values for scaling """
        self.scaleImage()
        self.drawImage()
    
    def updateThumbnail(self, event):
        """ """
        self.lastMousePosition = (event.x, event.y)
        self.pilThumbnail = self.pilImage.transform(self.pilImage.size, Image.EXTENT, (event.x-25,event.y-25,event.x+25,event.y+25))
        self.thumbnailImage = ImageTk.PhotoImage(self.pilThumbnail.resize((200,200)))
        self.thumbnailImageLabel.configure(image=self.thumbnailImage)
        
    def scaleImage(self):
        """ This method re-scales the image data """
        self.scaledData = 255.0*self.rescaler(self.rawData, beta=10.**self.scaleValue.get(), min=self.minValue.get(), max=self.maxValue.get(), clip=True)
    
    def plotContour(self, event):
        """ If the 'c' key is pressed, generate a contour plot of whatever is in the thumbnail zoom box """
        self.contourPlot = Tk.Toplevel(self.master)
        self.contourPlot.title("Contour plot for: {0}".format(self.filename))
        
        rawShape = self.rawData.shape
        
        lastx, lasty = self.lastMousePosition
        lastx = round(lastx/self.zoomFactor)
        lasty = round(lasty/self.zoomFactor)
        boxHalfSize = 25/self.zoomFactor
        x1,y1,x2,y2 = [x for x in map(round, (lastx-boxHalfSize,lasty-boxHalfSize,lastx+boxHalfSize,lasty+boxHalfSize))]
        
        if x1 < 0:
            x1 = 0
            x2 = boxHalfSize*2
        if x2 > rawShape[1]:
            x2 = rawShape[1]
            x1 = x2 - boxHalfSize*2
        if y1 < 0:
            y1 = 0
            y2 = boxHalfSize*2
        if y2 > rawShape[0]:
            y2 = rawShape[0]
            y1 = y2 - boxHalfSize*2
        
        thumbData = self.rawData[y1:y2, x1:x2]
        shp = thumbData.shape
        x,y = np.meshgrid(range(shp[0]), range(shp[1]))

        self.fig = Figure(figsize=(5,5))
        ax = self.fig.add_subplot(111)
        ax.contour(x, y, thumbData)
        ax.set_ylim(ax.get_ylim()[::-1])
        ax.get_xaxis().set_ticks([])
        ax.get_yaxis().set_ticks([])
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.contourPlot)
        self.canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
        
    def drawImage(self):
        """ This method will draw the image into a PhotoImage object in the new image window """
        
        self.pilImage = Image.fromarray(self.scaledData.astype(np.uint8))
        newSize = (int(self.pilImage.size[0]*self.zoomFactor), int(self.pilImage.size[1]*self.zoomFactor))
        self.pilImage = self.pilImage.resize(newSize)
        self.tkImage = ImageTk.PhotoImage(self.pilImage)
        self.canvas = Tk.Canvas(self.ImageWindow, width=newSize[0], height=newSize[1], bd=0)
        self.canvas.create_image(0, 0, image=self.tkImage, anchor="nw")
        self.canvas.grid(row=0, column=2, rowspan=5, sticky="nswe")
        self.canvas.bind("<Motion>", self.updateThumbnail)
        self.canvas.bind("c", self.plotContour)
        self.canvas.focus_set()
        
        """ # Code for source detection:
        numSigma = 2.
        labels, num = snd.label(self.rawData > (numSigma*np.std(self.rawData)), np.ones((3,3)))
        coords = snd.center_of_mass(self.rawData, labels, range(1,num+1))
        rad = 5.
        for coord in coords:
            y,x = coord
            x = x*self.zoomFactor
            y = y*self.zoomFactor
            circ1 = self.canvas.create_oval(x-rad,y-rad,x+rad,y+rad, outline='red')
        """
        
        self.pilThumbnail = self.pilImage.transform(self.pilImage.size, Image.EXTENT, (0,0,50,50))
        self.pilThumbnail = self.pilThumbnail.resize((200,200))
        self.thumbnailImage = ImageTk.PhotoImage(self.pilThumbnail)
        self.thumbnailImageLabel = Tk.Label(self.ImageWindow, image=self.thumbnailImage, command=None)
        self.thumbnailImageLabel.grid(row=4, column=0, columnspan=2, rowspan=5)
Example #9
0
def start(m_text_initial, p_text_initial, nfd_text_initial, pfd_text_initial,
	S_text_initial, explain_initial, options, solver_name,
	time_limit):

	matplotlib.use("TkAgg")

	root = tk.Tk()
	actions_lookup = []

	def quit():
		# Close matplotlib figure so program is not left hanging
		plt.close('all')
		root.quit()

	def random_problem():
		# Generate random problem
		m_text, p_text, nfd_text, pfd_text = interface.random_problem()

		# Set textboxes
		spinbox_set(m_spinbox, m_text)
		textbox_set(p_textbox, p_text)
		textbox_set(nfd_textbox, nfd_text)
		textbox_set(pfd_textbox, pfd_text)

	def load_problem():
		# Locate file
		filename = tk.filedialog.askopenfilename(title='Open problem',
			filetypes=[('Problem files', '*.problem'), ('Any files', '*')])

		# Handle closed dialog
		if not filename:
			return

		# Read file
		success, texts = interface.load_problem(filename)

		if success:
			[m_text, p_text, nfd_text, pfd_text] = texts

			spinbox_set(m_spinbox, m_text)
			textbox_set(p_textbox, p_text)
			textbox_set(nfd_textbox, nfd_text)
			textbox_set(pfd_textbox, pfd_text)
		else:
			E_listbox_set(texts)

	def save_problem():
		# Locate file
		filename = tk.filedialog.asksaveasfilename(title='Save problem as',
			filetypes=[('Problem files', '*.problem'), ('Any files', '*')])

		# Handle closed dialog
		if not filename:
			return

		# Write file
		success, error = interface.save_problem(
			filename,
			m_spinbox.get(),
			textbox_get(p_textbox),
			textbox_get(nfd_textbox),
			textbox_get(pfd_textbox))

		if not success:
			E_listbox_set(error)

	def optimal_schedule():
		# Generate schedule
		success, text = interface.optimal_schedule(
			m_spinbox.get(),
			textbox_get(p_textbox),
			textbox_get(nfd_textbox),
			textbox_get(pfd_textbox),
			solver_name,
			time_limit)

		if success:
			textbox_set(S_textbox, text)
		else:
			E_listbox_set(text)

	def random_schedule():
		# Generate schedule
		success, text = interface.random_schedule(
			m_spinbox.get(),
			textbox_get(p_textbox),
			textbox_get(nfd_textbox),
			textbox_get(pfd_textbox))

		if success:
			textbox_set(S_textbox, text)
		else:
			E_listbox_set(text)

	def load_schedule():
		# Locate file
		filename = tk.filedialog.askopenfilename(title='Open schedule',
			filetypes=[('Schedule files', '*.schedule'), ('Any files', '*')])

		# Handle closed dialog
		if not filename:
			return

		# Read file
		success, text = interface.load_text(filename)

		if success:
			textbox_set(S_textbox, text)
		else:
			E_listbox_set(text)

	def save_file(text, title, filetypes):
		# Locate file
		filename = tk.filedialog.asksaveasfilename(title=title,
			filetypes=filetypes)

		# Handle closed dialog
		if not filename:
			return

		# Write file
		success, error = interface.save_text(filename, text)

		if not success:
			E_listbox_set(error)

	def save_schedule():
		save_file(textbox_get(S_textbox), 'Save schedule as',
			[('Schedule files', '*.schedule'), ('Any files', '*')])

	def explain(options=options):
		success, result = interface.explain(
			m_spinbox.get(),
			textbox_get(p_textbox),
			textbox_get(nfd_textbox),
			textbox_get(pfd_textbox),
			textbox_get(S_textbox),
			options)

		if success:
			# Setup reasons
			E_listbox_set([reason for reason, _ in result])
			# Updates actions
			nonlocal actions_lookup
			actions_lookup = [actions for _, actions in result]
			# Select first appliable reason
			for index, (_, actions) in enumerate(result):
				if actions:
					E_listbox.select_set(index)
					on_select_reason()
					break

			fig.canvas.draw()
		else:
			E_listbox_set(result)

	def save_explanation():
		save_file(listbox_get(E_listbox), 'Save output as',
			[('Text files', '*.txt'), ('Any files', '*')])

	# Set E_listbox's items while clearing actions
	def E_listbox_set(lines):
		actions_lookup = []
		listbox_set(E_listbox, lines)
		listbox_set(action_listbox, [])

	# Shows suggested actions for a selected reason
	def on_select_reason(_=None):
		# If anything has been explained
		if actions_lookup:
			# Show suggested actions
			readable_actions = actions_lookup[E_listbox.curselection()[0]]
			actions = [action for action, _ in readable_actions]
			listbox_set(action_listbox, actions)
			# Select if possible
			if actions:
				action_listbox.select_set(0)

	# Apply selected action to schedule
	def apply(_=None):
		# If action is selected
		indices = list(action_listbox.curselection())
		if indices:
			# Find internal representation of action
			action_index = indices[0]
			reason_index = E_listbox.curselection()[0]
			_, action = actions_lookup[reason_index][action_index]

			# Apply action
			success, result = interface.apply(
				m_spinbox.get(),
				textbox_get(p_textbox),
				textbox_get(nfd_textbox),
				textbox_get(pfd_textbox),
				textbox_get(S_textbox),
				action,
				options)

			if success:
				# Unpack results
				nfd_text, pfd_text, S_text = result

				# Update textboxes
				textbox_set(nfd_textbox, nfd_text)
				textbox_set(pfd_textbox, pfd_text)
				textbox_set(S_textbox, S_text)

				# Automate next step, but do not draw again for explanation
				draw_options = dict(options)
				draw_options['graphical'] = False
				explain(draw_options)
			else:
				E_listbox_set([result])

	# When tab is pressed
	def focus_next_window(event):
	    event.widget.tk_focusNext().focus()
	    return('break')

	root.protocol('WM_DELETE_WINDOW', quit)
	root.title('Schedule Explainer')
	input_textbox_width = 30

	# Create widgets
	left_frame = tk.Frame(root)

	problem_frame = tk.LabelFrame(left_frame, text='Problem')
	problem_command_frame = tk.Frame(problem_frame)
	random_problem_button = tk.Button(problem_command_frame, text='Randomise', command=random_problem)
	load_problem_button = tk.Button(problem_command_frame, text='Load', command=load_problem)
	save_problem_button = tk.Button(problem_command_frame, text='Save', command=save_problem)
	m_label = tk.Label(problem_frame, text='Number of machines', anchor=tk.E)
	m_spinbox = tk.Spinbox(problem_frame, from_=0, to_=tk.sys.maxsize)
	p_label = tk.Label(problem_frame, text='Processing times', anchor=tk.E)
	p_textbox = tk.Text(problem_frame, height=3, width=input_textbox_width)
	p_scrollbar = attach_scrollbar(problem_frame, p_textbox)
	p_textbox.bind('<Tab>', focus_next_window)
	nfd_label = tk.Label(problem_frame, text='Negative fixed decisions', anchor=tk.E)
	nfd_textbox = tk.Text(problem_frame, height=3, width=input_textbox_width)
	nfd_scrollbar = attach_scrollbar(problem_frame, nfd_textbox)
	nfd_textbox.bind('<Tab>', focus_next_window)
	pfd_label = tk.Label(problem_frame, text='Positive fixed decisions', anchor=tk.E)
	pfd_textbox = tk.Text(problem_frame, height=3, width=input_textbox_width)
	pfd_scrollbar = attach_scrollbar(problem_frame, pfd_textbox)
	pfd_textbox.bind('<Tab>', focus_next_window)

	S_frame = tk.LabelFrame(left_frame, text='Schedule')
	S_command_frame = tk.Frame(S_frame)
	S_optimal_schedule_button = tk.Button(S_command_frame, text='Optimise', command=optimal_schedule)
	S_random_button = tk.Button(S_command_frame, text='Randomise', command=random_schedule)
	load_S_button = tk.Button(S_command_frame, text='Load', command=load_schedule)
	save_S_button = tk.Button(S_command_frame, text='Save', command=save_schedule)
	S_textbox = tk.Text(S_frame, height=3, width=input_textbox_width)
	S_textbox.bind('<Tab>', focus_next_window)
	S_scrollbar = attach_scrollbar(S_frame, S_textbox)
	explain_button = tk.Button(S_frame, text='Explain', command=explain)

	right_frame = tk.Frame(root)
	fig = plt.figure(0)
	S_figure = FigureCanvasTkAgg(fig, master=right_frame).get_tk_widget()
	E_frame = tk.LabelFrame(right_frame, text='Explanation')
	E_listbox = tk.Listbox(E_frame, exportselection=False)
	E_listbox.bind('<<ListboxSelect>>', on_select_reason)
	E_listbox.bind('<Return>', apply)
	E_scrollbar = attach_scrollbar(E_frame, E_listbox)
	save_E_button = tk.Button(E_frame, text='Save', command=save_explanation)
	action_frame = tk.LabelFrame(right_frame, text='Actions')
	action_listbox = tk.Listbox(action_frame)
	action_listbox.bind('<Return>', apply)
	action_scrollbar = attach_scrollbar(action_frame, action_listbox)
	apply_action_button = tk.Button(action_frame, text='Apply', command=apply)

	# Geometry
	padding = 8
	h_fill = tk.W + tk.E
	v_fill = tk.N + tk.S
	fill = h_fill + v_fill

	root.geometry("1280x720")
	root.rowconfigure(0, weight=1)
	root.columnconfigure(1, weight=1)

	left_frame.grid(row=0, column=0, sticky=v_fill)
	left_frame.rowconfigure(0, weight=1)
	left_frame.rowconfigure(1, weight=1)

	problem_frame.grid(row=0, column=0, padx=padding, pady=padding, sticky=v_fill)
	problem_command_frame.grid(row=0, column=0, columnspan=3, padx=padding, pady=padding, sticky=h_fill)

	problem_command_frame.columnconfigure(0, weight=1)
	problem_command_frame.columnconfigure(1, weight=1)
	problem_command_frame.columnconfigure(2, weight=1)
	random_problem_button.grid(row=0, column=0, sticky=h_fill)
	load_problem_button.grid(row=0, column=1, padx=padding, sticky=h_fill)
	save_problem_button.grid(row=0, column=2, sticky=h_fill)
	problem_frame.rowconfigure(2, weight=1)
	problem_frame.rowconfigure(3, weight=1)
	problem_frame.rowconfigure(4, weight=1)

	m_label.grid(row=1, column=0, padx=padding, sticky=h_fill)
	m_spinbox.grid(row=1, column=1, columnspan=2, padx=(0, padding), sticky=h_fill)
	p_label.grid(row=2, column=0, padx=padding, pady=padding, sticky=h_fill)
	p_textbox.grid(row=2, column=1, pady=padding, sticky=v_fill)
	p_scrollbar.grid(row=2, column=2, padx=(0, padding), pady=padding, sticky=v_fill)
	nfd_label.grid(row=3, column=0, padx=padding, sticky=h_fill)
	nfd_textbox.grid(row=3, column=1, sticky=v_fill)
	nfd_scrollbar.grid(row=3, column=2, padx=(0, padding), sticky=v_fill)
	pfd_label.grid(row=4, column=0, padx=padding, pady=padding, sticky=h_fill)
	pfd_textbox.grid(row=4, column=1, pady=padding, sticky=v_fill)
	pfd_scrollbar.grid(row=4, column=2, padx=(0, padding), pady=padding, sticky=v_fill)

	S_frame.grid(row=1, column=0, padx=padding, pady=(0, padding), ipadx=50, sticky=fill)
	S_frame.rowconfigure(1, weight=1)
	S_frame.columnconfigure(0, weight=1)
	S_command_frame.grid(row=0, column=0, columnspan=2, padx=padding, pady=padding, sticky=h_fill)
	S_command_frame.columnconfigure(0, weight=1)
	S_command_frame.columnconfigure(1, weight=1)
	S_command_frame.columnconfigure(2, weight=1)
	S_command_frame.columnconfigure(3, weight=1)
	S_optimal_schedule_button.grid(row=0, column=0, padx=(0, padding), sticky=h_fill)
	S_random_button.grid(row=0, column=1, padx=(0, padding), sticky=h_fill)
	load_S_button.grid(row=0, column=2, padx=(0, padding), sticky=h_fill)
	save_S_button.grid(row=0, column=3, sticky=h_fill)
	S_textbox.grid(row=1, column=0, padx=(padding, 0), sticky=fill)
	S_scrollbar.grid(row=1, column=1, padx=(0, padding), sticky=v_fill)
	explain_button.grid(row=2, column=0, columnspan=2, padx=padding, pady=padding, sticky=h_fill)

	right_frame.grid(row=0, column=1, sticky=fill)
	right_frame.rowconfigure(1, weight=1)
	right_frame.columnconfigure(0, weight=1)
	right_frame.columnconfigure(1, weight=1)
	S_figure.grid(row=0, column=0, columnspan=2, sticky=h_fill, padx=padding, pady=padding)
	E_frame.grid(row=1, column=0, sticky=fill, padx=padding, pady=(0, padding))
	E_frame.rowconfigure(0, weight=1)
	E_frame.columnconfigure(0, weight=1)
	E_listbox.grid(row=0, column=0, sticky=fill, padx=(padding, 0), pady=(padding, 0))
	E_scrollbar.grid(row=0, column=1, sticky=v_fill, padx=(0, padding), pady=(padding, 0))
	save_E_button.grid(row=1, column=0, columnspan=2, padx=padding, pady=padding, sticky=h_fill)
	action_frame.grid(row=1, column=1, sticky=fill, padx=padding, pady=(0, padding))
	action_frame.rowconfigure(0, weight=1)
	action_frame.columnconfigure(0, weight=1)
	action_frame.rowconfigure(0, weight=1)
	action_listbox.grid(row=0, column=0, sticky=fill, padx=(padding, 0), pady=(padding, 0))
	action_scrollbar.grid(row=0, column=1, sticky=v_fill, padx=(0, padding), pady=(padding, 0))
	apply_action_button.grid(row=1, column=0, columnspan=2, padx=padding, pady=padding, sticky=h_fill)

	# Initial state from command line
	spinbox_set(m_spinbox, m_text_initial)
	textbox_set(p_textbox, p_text_initial)
	textbox_set(nfd_textbox, nfd_text_initial)
	textbox_set(pfd_textbox, pfd_text_initial)
	textbox_set(S_textbox, S_text_initial)

	if explain_initial:
		explain()

	root.mainloop()
Example #10
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 #11
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 "
                         u"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.draw()
        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(),
                branch=self.branch.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(),
                branch=self.branch.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.draw()
        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.draw()
        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.draw()
        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.draw()
        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.draw()
            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.draw()
            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.draw()
            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 #12
0
    def intial(self):

        self.note.add(self.tab1,
                      text="SPI graph")  #,image=scheduledimage, compound=TOP)

        #self.note.pack()

        label = tk.Label(self.tab1, text="Graph Page!")
        label.grid(row=1)  #,pady=3,padx=3)
        exit_btn = tk.Button(self.tab1,
                             text='Go back to main page',
                             command=self.close,
                             activebackground='grey',
                             activeforeground='#AB78F1',
                             bg='#58F0AB',
                             highlightcolor='red',
                             padx='10px',
                             pady='3px')
        exit_btn.grid(row=2, column=2)
        import matplotlib.pyplot as plt
        from matplotlib.figure import Figure
        from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg

        ##        fig = Figure(figsize=(7,5), dpi=200)
        fig = plt.figure()
        num = int("%i11" % len(self.df.columns))
        i = 0
        ax = []
        for col in self.df.columns:
            ax1 = fig.add_subplot(num + i)
            ax.append(ax1)

            spi_pos = self.df[col].clip(lower=0).to_frame(col)
            spi_neg = self.df[col].clip(upper=0).to_frame(col)
            ##            print(spi)
            self.df[col].plot(ax=ax[i], color="black")
            plt.fill_between(spi_neg.index, spi_neg[col].values, color="r")
            plt.fill_between(spi_pos.index, spi_pos[col].values, color="b")
            ax1.legend(loc='right',
                       bbox_to_anchor=(1.15, 0.9),
                       shadow=True,
                       fontsize=10)

            i += 1


#plt.show()
        self.frame = ttk.Frame(self.tab1)
        self.frame.grid(row=2, sticky=tk.W + tk.E)

        canvas = FigureCanvasTkAgg(fig, self.frame)
        canvas.draw()
        canvas = canvas.get_tk_widget()
        canvas.grid(row=1,
                    column=0,
                    rowspan=10,
                    columnspan=4,
                    sticky=tk.W + tk.E + tk.N + tk.S)

        f = []

        for col in self.df.columns:
            tab = ttk.Frame(self.note)
            f.append(tab)
            self.note.add(tab, text=col)
            df2 = self.df[col].to_frame(col)
            df2.dropna(inplace=True)
            #print (df2.head())
            import statsmodels.api as sm
            decomposition = sm.tsa.seasonal_decompose(df2, model='additive')
            fig2 = decomposition.plot()
            plt.figure(figsize=(15, 5))
            self.frame = ttk.Frame(tab)
            self.frame.grid(row=2, sticky=tk.W + tk.E)
            canvas = FigureCanvasTkAgg(fig2, self.frame)
            canvas.draw()
            canvas = canvas.get_tk_widget()
            canvas.grid(row=1,
                        column=0,
                        rowspan=10,
                        columnspan=4,
                        sticky=tk.W + tk.E + tk.N + tk.S)
        self.tab2 = ttk.Frame(self.note)
        self.note.add(self.tab2, text="Frequency")
        fig2 = plt.figure()
        num = int("%i11" % len(self.df.columns))
        i = 0
        ax = []
        for col in self.df.columns:
            ax2 = fig2.add_subplot(num + i)
            ax.append(ax2)
            SPI = self.df[col].to_frame(col)
            SPI.dropna(inplace=True)
            print(SPI.head())
            SPI["Class"] = SPI[col].apply(reclass)
            SPIgroup = SPI.groupby(by="Class")
            count = SPIgroup.count()
            d = SPIclasses.join(count)
            print(d.head())
            plt.style.use('ggplot')
            color_palette_list = [
                '#009ACD', '#ADD8E6', '#63D1F4', '#0EBFE9', '#C1F0F6',
                '#0099CC', '#909090'
            ]
            d.plot(kind='barh',
                   figsize=(12, 7),
                   color=color_palette_list,
                   fontsize=6,
                   ax=ax[i])
            #plt.set_title('Amount Frequency of %s'%col)
            ax2.set_xlabel('Frequency')
            ax2.set_ylabel('Classes')
            ##            rects = fig2.patches
            autolabel(ax2, "left")
            i += 1
        self.frame1 = ttk.Frame(self.tab2)
        self.frame1.grid(row=2, sticky=tk.W + tk.E)

        canvas = FigureCanvasTkAgg(fig2, self.frame1)
        canvas.draw()
        canvas = canvas.get_tk_widget()
        canvas.grid(row=1,
                    column=0,
                    rowspan=10,
                    columnspan=4,
                    sticky=tk.W + tk.E + tk.N + tk.S)

        ##
        #print(self.note[col])
        ##        tab_names = []
        ##        for i in self.note.tabs():
        ##            print (i)
        ##            tab_names.append(self.note.tab(i, "text"))
        ##        print (tab_names)
        ##
        ####
        ####            plt.show()
        ##
        ##
        ##
        #fig.savefig(out[:-3]+"png")

        ##        a = f.add_subplot(111)
        ##        a.plot([1,2,3,4,5,6,7,8],[5,6,1,3,8,9,3,5])

        self.note.pack()
Example #13
0
y2 = [i**2 for i in x]
plt.xlabel("x") 
plt.ylabel("y") 
graf=plt.plot(x,y,x,y2)
#fig=plt.figure()
lbl=FigureCanvasTkAgg(fig,root)
#lbl.get_tk_widget().grid(row=11,column=2,columnspan=10)
lbl.get_tk_widget().grid(column=0,row=9,columnspan=10)
lbl.draw()


FileName=Entry(root,width=30,textvariable=name)
FileName.grid(row=0, column=1, columnspan=3,pady=10)
FileName.insert(0,'img_1.jpg')
lbl = Label(root, text="       X1      ")  
lbl.grid(column=0, row=5,pady=10)  
txt11 = Entry(root,width=10)  
txt11.grid(column=1, row=5,pady=10)
lbl = Label(root, text="       X2      ")  
lbl.grid(column=2, row=5,pady=10)  
txt12 = Entry(root,width=10)  
txt12.grid(column=3, row=5,pady=10) 
lbl = Label(root, text="       Y1      ")  
lbl.grid(column=0, row=7,pady=10)  
txt21 = Entry(root,width=10)  
txt21.grid(column=1, row=7,pady=10)
lbl = Label(root, text="       Y2      ")  
lbl.grid(column=2, row=7,pady=10)  
txt22 = Entry(root,width=10)  
txt22.grid(column=3, row=7,pady=10)
render=((img_rows, img_cols))
Example #14
0
class GUI():
    def __init__(self, tempDir):
        self.tempDir = tempDir
        self.done = False
        self.bg = "#f0f0f0"
        self.btnCol = "light grey"
        self.files = []
        self.scales = [1 for x in range(10)]
        self.empty = [True for x in range(10)]
        self.data = [0 for x in range(10)]
        self.figures = [0 for x in range(10)]
        self.views = [-1 for x in range(10)]
        self.addresses = [0 for x in range(10)]
        self.resultTypes = [0 for x in range(10)]
        self.current = 0

    def main_menu(self):
        #Displays the main menu page
        #========== Setup
        root = tk.Tk()
        root.configure(bg=self.bg)
        root.state("zoomed")
        h = root.winfo_screenheight()
        #========== Weighting
        root.rowconfigure(1, weight=1)
        root.rowconfigure(3, weight=1)
        root.rowconfigure(5, weight=1)
        root.rowconfigure(7, weight=1)
        root.rowconfigure(9, weight=1)
        root.columnconfigure(0, weight=1)
        #========== Widgets
        #===== Row 0, 1, 2
        tk.Frame(root, bg=self.bg, height=round(h * 0.1)).grid(row=0, column=0)
        tk.Label(root,
                 bg=self.bg,
                 text="Microscope image analyser",
                 justify="center",
                 font=("Arial", round(h * 0.06))).grid(row=1, column=0)
        tk.Frame(root, bg=self.bg, height=round(h * 0.1)).grid(row=2, column=0)
        #===== Row 3, 4
        tk.Button(root,
                  bg=self.btnCol,
                  text="Image analysis",
                  justify="center",
                  font=("Calibri", round(h * 0.03)),
                  width=30,
                  command=partial(self.select_file, root,
                                  "Select image to analyse",
                                  ("Png files", "*.png"), 0)).grid(row=3,
                                                                   column=0)
        tk.Frame(root, bg=self.bg).grid(row=4, column=0)
        #===== Row 5, 6
        tk.Button(root,
                  bg=self.btnCol,
                  text="Load saved data",
                  justify="center",
                  font=("Calibri", round(h * 0.03)),
                  width=30,
                  command=partial(self.select_file, root,
                                  "Select results file",
                                  ("Text files", "*.txt"), 1)).grid(row=5,
                                                                    column=0)
        tk.Frame(root, bg=self.bg).grid(row=6, column=0)
        #===== Row 7, 8
        tk.Button(
            root,
            bg=self.btnCol,
            text="View results",
            justify="center",
            font=("Calibri", round(h * 0.03)),
            width=30,
            command=lambda: [root.destroy(), self.results()]).grid(row=7,
                                                                   column=0)
        tk.Frame(root, bg=self.bg).grid(row=8, column=0)
        #===== Row 9
        tk.Button(root,
                  bg=self.btnCol,
                  text="Quit",
                  justify="center",
                  font=("Calibri", round(h * 0.03)),
                  width=30,
                  command=root.destroy).grid(row=9, column=0)
        #===== Row 10
        tk.Frame(root, height=round(h * 0.2)).grid(row=10, column=0)
        #========== Mainloop
        root.mainloop()

    def plot_histogram(self):
        #Creates a figure containing a histogram
        fig = Figure()
        fig.patch.set_facecolor(self.bg)
        plot = fig.gca()  #Creates plot for histogram to be on
        plot.hist(self.data[self.current], 30)  #Plot histogram with 30 bins
        plot.yaxis.set_major_locator(
            MaxNLocator(integer=True))  #Make ticks integers
        plot.set_xlabel("Diameter", fontsize=20)  #Set label size
        plot.set_ylabel("Frequency", fontsize=20)
        plot.tick_params(labelsize=15)  #Set tick label size
        self.figures[self.current] = fig  #Record new figure

    def remove_entry(self, index, refresh, root=None):
        #Removes an item from the stored results, given the index
        def remove(array, index):
            #Removes 1 item from a list given its index
            return [array[x] for x in range(len(array)) if x != index]

        self.files = remove(self.files, index)
        self.scales = remove(self.scales, index)
        self.scales.append(1)
        self.empty = remove(self.empty, index)
        self.empty.append(True)
        self.data = remove(self.data, index)
        self.data.append(0)
        self.figures = remove(self.figures, index)
        self.figures.append(0)
        self.views = remove(self.views, index)
        self.views.append(-1)
        self.addresses = remove(self.addresses, index)
        self.addresses.append(0)
        self.resultTypes = remove(self.resultTypes, index)
        self.resultTypes.append(0)
        if refresh:
            if self.current > index:
                self.current -= 1
            if self.current >= len(self.files) and len(self.files) > 0:
                self.current = len(self.files) - 1
            root.destroy()
            self.results()

    def results(self):
        #Displays analysis results page
        #========== Setup
        root = tk.Tk()
        root.configure(bg=self.bg)
        root.state("zoomed")
        w = root.winfo_screenwidth()
        h = root.winfo_screenheight()
        #========== Weighting / padding
        root.rowconfigure(0, pad=h * 0.05)
        root.rowconfigure(12, pad=h * 0.05)
        root.columnconfigure(1, weight=1)
        root.columnconfigure(2, weight=1)
        root.columnconfigure(3, weight=1)
        root.columnconfigure(4, weight=1)
        #========== Widgets
        #===== Row 0
        tk.Button(
            root,
            bg=self.btnCol,
            text="Main menu",
            justify="center",
            font=("Calibri", round(h * 0.02)),
            command=lambda: [root.destroy(), self.main_menu()]).grid(
                row=0, column=0, sticky="NW")
        self.resultsTitle = tk.StringVar()
        tk.Label(root,
                 bg=self.bg,
                 textvariable=self.resultsTitle,
                 justify="center",
                 font=("Arial", round(h * 0.04))).grid(row=0,
                                                       column=0,
                                                       columnspan=6)
        #===== Other results
        tk.Label(root,
                 bg=self.bg,
                 text="Other results:",
                 justify="left",
                 font=("Calibri", round(h * 0.03))).grid(row=1, column=5)
        self.others = []
        for x in range(10):
            try:
                self.others.append(
                    tk.Button(root,
                              bg=self.btnCol,
                              text=self.files[x],
                              justify="left",
                              font=("Calibri", round(h * 0.02)),
                              width=20,
                              command=partial(self.set_results, x, root)))
            except IndexError:
                self.others.append(
                    tk.Button(root,
                              bg=self.btnCol,
                              text="",
                              justify="left",
                              font=("Calibri", round(h * 0.02)),
                              width=20,
                              command=partial(self.set_results, x, root)))
            self.others[x].grid(row=x + 2, column=5)
            tk.Button(root,
                      bg=self.btnCol,
                      text="X",
                      justify="center",
                      font=("Arial", round(h * 0.02)),
                      width=2,
                      command=partial(self.remove_entry, x, True,
                                      root)).grid(row=x + 2, column=6)
        #===== Row 12
        tk.Label(root,
                 bg=self.bg,
                 text="Scale:",
                 font=("Calibri", round(h * 0.03))).grid(row=12,
                                                         column=0,
                                                         sticky="E")
        root.bind("<Return>", partial(self.update_scale, root))
        self.scaleEntry = tk.StringVar()
        tk.Entry(root,
                 textvariable=self.scaleEntry,
                 font=("Calibri", round(h * 0.03)),
                 width=10).grid(row=12, column=1, sticky="W")
        tk.Button(root,
                  bg=self.btnCol,
                  text="Original image",
                  width=15,
                  font=("Calibri", round(h * 0.03)),
                  command=partial(self.set_view, root, 1)).grid(row=12,
                                                                column=2)
        tk.Button(root,
                  bg=self.btnCol,
                  text="Analysed image",
                  width=15,
                  font=("Calibri", round(h * 0.03)),
                  command=partial(self.set_view, root, 2)).grid(row=12,
                                                                column=3)
        tk.Button(root,
                  bg=self.btnCol,
                  text="Histogram",
                  width=15,
                  font=("Calibri", round(h * 0.03)),
                  command=partial(self.set_view, root, 0)).grid(row=12,
                                                                column=4)
        tk.Button(root,
                  bg=self.btnCol,
                  text="Save",
                  width=10,
                  font=("Calibri", round(h * 0.03)),
                  command=self.save).grid(row=12, column=5)
        self.set_results(self.current, root)
        self.set_view(root, 0)
        root.mainloop()

    def save(self):
        #Writes the scale adjusted diameters to txt file in csv format
        name = self.files[self.current]  #Get shorter identifier
        name = name[:name.rindex(".")] + "-results.txt"
        address = filedialog.asksaveasfilename(title="Save results file",
                                               initialfile=name,
                                               filetype=(("Text files",
                                                          "*.txt"),
                                                         ("All files", "*.*")))
        file = open(address, "w+")
        file.write(','.join([str(X) for X in self.data[self.current]]))
        file.close(
        )  #Store diameters including scale adjustment, fstring used so it is 1 argument

    def select_file(self, root, title, filetype, resultType):
        #Allows the user to select an image file from a directory
        file = filedialog.askopenfilename(title=title,
                                          filetypes=(filetype, ("All files",
                                                                "*.*")))
        if file != "":  #If operation not cancelled
            self.files.append(file[file.rindex("/") + 1:])  #Get filename only
            if len(self.files) > 10:  #If list full, replace oldest item
                self.remove_entry(0, False)
                self.current = 9
            self.current = len(self.files) - 1
            self.addresses[self.current] = file
            self.resultTypes[self.current] = resultType
            root.destroy()
            if resultType == 0:  #Image analysis
                pic = image(file, self.tempDir)  #Do overall analysis
                particles = pic.create_objects()  #Do particle analysis
                self.data[self.current] = [P.diameter for P in particles]
            elif resultType == 1:  #Reading results file
                text = open(file, "r").read()
                self.data[self.current] = text.split(",")
                self.data[self.current] = [
                    float(X) for X in self.data[self.current]
                ]
            self.plot_histogram()  #Create histogram figure
            self.results()

    def set_results(self, new, root):
        #Changes to a new set of analysis results
        if len(self.files) > new:  #If results exist
            self.others[self.current].config(
                relief="raised")  #Deselect previous
            self.current = new
            self.others[self.current].config(relief="sunken")  #select current
            self.resultsTitle.set(
                f"Results - {self.files[self.current]}")  #Change title
            if self.empty[self.current]:
                self.scaleEntry.set("")  #If no scale set don't display scale
            else:
                self.scaleEntry.set(str(float(self.scales[self.current] *
                                              127)))  #Else do display scale
            self.set_view(root)

    def set_view(self, root, view=None):
        #Changes to viewing histogram, original image, or analysed image
        w = root.winfo_screenwidth()
        h = root.winfo_screenheight()
        if self.views[self.current] == 0:
            try:
                self.histogram.destroy()  #Destroy histogram
            except Exception:
                pass
        elif self.views[self.current] == 1 or self.views[
                self.current] == 2:  #If previous was image
            try:
                self.picWidget.destroy()  #Destroy image
            except Exception:
                pass
        if view != None:
            self.views[self.current] = view  #Update to new view
        if self.views[self.current] == 0:
            self.histogram = FigureCanvasTkAgg(
                self.figures[self.current],
                master=root).get_tk_widget()  #Get widget
            self.histogram.config(width=round(w * 0.75),
                                  height=round(h * 0.7))  #Resize cavas
            self.histogram.grid(row=1, column=0, rowspan=11,
                                columnspan=5)  #Place canvas
        elif self.views[self.current] == 1 or self.views[self.current] == 2:
            if self.resultTypes[self.current] == 0:
                if self.views[self.current] == 1:
                    file = self.addresses[
                        self.current]  #Get shorter version of file name
                    pic = ImageTk.PhotoImage(
                        Image.open(file))  #Get original image
                else:
                    file = self.files[self.current]
                    file = self.tempDir + "\\" + file[:file.rindex(
                        '.')] + "-analysed" + file[file.rindex('.'):]
                    pic = ImageTk.PhotoImage(
                        Image.open(file))  #Get analysed image
                self.picWidget = tk.Label(root,
                                          image=pic,
                                          width=round(w * 0.75),
                                          height=round(h * 0.7))  #Image label
                self.picWidget.image = pic  #Stops the image being discarded by memory manager
                self.picWidget.grid(row=1, column=0, rowspan=11, columnspan=5)
            else:
                self.views[self.current] = 0
                self.set_view(root, 0)

    def update_scale(self, root, key):
        #Records the scale if it is valid
        old = self.scales[self.current]
        try:
            self.scales[self.current] = float(
                self.scaleEntry.get()) / 127  #Get scale
            if self.scales[self.current] > 0:
                for x in range(len(self.data[
                        self.current])):  #Adjust each item to new scale
                    self.data[
                        self.current][x] *= self.scales[self.current] / old
                self.plot_histogram()  #Replot histogram
                self.empty[
                    self.current] = False  #Record that scale has been set
                self.set_results(self.current, root)  #Redraw canvas
            else:
                self.scales[self.current] = old
        except ValueError:
            pass  #Unless not valid
Example #15
0
class DataAquisitionUI(UserInterface):
    def __init__(
                self, 
                layout_path, 
                data_src=[DummyDataSource()],
                vis_data=100
            ):
        super().__init__(layout_path)
        self.plt_config = self.ui_config['plot config']
        self.running=True
        self.collect = False
        self.vis_data = vis_data
        self.data_src = data_src
        self.protocol("WM_DELETE_WINDOW", self.quit_app)

        self.init_plot()
        self.cleanup()


    def init_plot(self):
        """
        Sets up plot with colors and formats. Turns on
        interactive mode and places the plot in the 
        grid of the parent.
        """
        pltconf = self.plt_config["global config"]
        bg_color, fg_color = pltconf['bg'], pltconf['fg']

        self.figure, self.ax1 = subplots(facecolor=bg_color)
        self.ax2 = self.ax1.twinx()
        self.ax1.set_xlabel(pltconf['x label'])
        self.ax1.set_ylabel(pltconf['y1 label'])
        self.ax2.set_ylabel(pltconf['y2 label'])

        self.lines = [self.ax1.add_line(
                mlplines.Line2D([], [], label=label, **vals)
            ) for label, vals in self.plt_config['lines axis 1'].items()
        ]
        self.lines += [self.ax2.add_line(
                mlplines.Line2D([], [], label=label, **vals)
            ) for label, vals in self.plt_config['lines axis 2'].items()
        ]

        for line in self.lines:
            line.xdata, line.ydata = [], []
        
        labels = [l.get_label() for l in self.lines]
        legend = self.ax2.legend(
                self.lines, labels, 
                loc='upper left',
                facecolor=bg_color,
                edgecolor=bg_color,
                framealpha=1.0
            )
        for text in legend.get_texts():
            text.set_color(fg_color)
        
        for axis in [self.ax1, self.ax2]:
            axis.set_facecolor(bg_color)
            for side in ['bottom', 'top', 'right', 'left']:
                axis.spines[side].set_color(fg_color)
            
            axis.tick_params(axis='x', colors=fg_color)
            axis.tick_params(axis='y', colors=fg_color)
            axis.yaxis.label.set_color(fg_color)
            axis.xaxis.label.set_color(fg_color)
            axis.grid(color=fg_color)
            axis.set_autoscaley_on(True)
            axis.set_autoscalex_on(True)

        tight_layout()
        ion()
        self.data_plot = PltCanvas(self.figure, master=self).get_tk_widget()
        self.data_plot.grid(**pltconf['grid'])


    def cleanup(self):
        """ 
        Re-initializes the parameters for data collection and clears the 
        console screen.
        """
        for line in self.lines:
            line.xdata = []
            line.ydata = []
        self.data = []
    
    
    def daq_loop(self):
        """ 
        Part of the mainloop. This function will run every 0.5 seconds. If
        the "collect" parameter is set to True it will append the data it 
        collects to an array to be saved to the output file.
        
        The loop functions with these instructions:
            - Get data as a list from some source
            - Save the data to an array if self.collect == True
            - Update the graph with the latest data point
            - Loop
        This will execute on startup and continue doing while mainloop is 
        still running.
        """
        data_point = []
        for src in self.data_src:
            data_point += src.get_data()

        if not self.valid_data(data_point): 
            self.after(0, self.daq_loop)
            return

        self.process_data(data_point)
        
        if self.collect: self.data_collect(data_point)

        self.graph_data(data_point)
        if self.running: self.after(0, self.daq_loop)


    def graph_data(self, data1):
        """ Update the data to be graphed and then update the graph """
        for i, line in enumerate(self.lines):
            assert len(line.xdata) == len(line.ydata)
            if len(line.xdata) > self.vis_data:
                line.xdata.pop(0)
                line.ydata.pop(0)
                
            line.xdata.append(data1[0])
            line.ydata.append(data1[i+1])
            line.set_xdata(line.xdata)
            line.set_ydata(line.ydata)
            
        self.ax1.relim()
        self.ax2.relim()
        self.ax1.autoscale_view()
        self.ax2.autoscale_view()
        self.figure.canvas.draw()
        self.figure.canvas.flush_events()


    def valid_data(self, data_point):
        """
        Check that data is valid and do any preprocessing on the data.
        Must return True or False.
        """
        print(data_point)
        return True 

    
    def process_data(self, data_point):
        """
        Do any processing needed before data collection and graphing.
        """
        pass


    def data_collect(data_point):
        """
        Processing for data collection.
        """
        pass


    def quit_app(self, event=None):
        """Safely exits the program."""
        if self.collect:
            if not askyesno(
                    "Quit Warning",
                    "DAQ is still running!\nAre you sure you want to quit?"
                ):
                return
        self.running = False
        self.destroy()
        raise SystemExit