def line_plot(self): #Todo: Fix line plot to map only a few not whole years self.clear_screen() self.file_exists() #The following indexes are assuming that the X numpy array contains #values in the following order: date (year-month-day), names, #expenditure, and income. I.e. 0,1,2,3 # fields = self.find_fields() pdb.set_trace() fields = {'date': 0, 'name':1, 'expend':2, 'income':3} fig = Figure (figsize=(5, 5), dpi=100) f = fig.add_subplot(111) #These two statements get rid of 'NaN' values in the array self.X[pd.isnull(self.X[:, fields['income']]),fields['income']]=0 self.X[pd.isnull(self.X[:, fields['expend']]),fields['expend']]=0 net = self.X[:, fields['income']] - self.X[:, fields['expend']] #Get the year value ex. 2019 as a y-axis marker years = [i[0:4] for i in self.X[:, fields['date']]] f.plot(years, net, scalex=True) f.set_xlabel('Years') f.set_ylabel('Net Worth') canvas = FigureCanvasTkAgg (fig, self.show_frame) canvas.show() canvas.get_tk_widget().pack(side=tk.TOP, fill = tk.BOTH, expand=True) canvas._tkcanvas.pack(side=tk.TOP, fill = tk.BOTH, expand=True) canvas.delete("all")
class OIdisplay(): def init_canvas(self): try: plt.close(self._f_oimg) except AttributeError: pass try: self._oi_canvas.delete(ALL) except AttributeError: pass self._f_oimg = Figure(facecolor=[0.95, 0.95, 0.96]) self._f_oimg.subplots_adjust(left=0.0, bottom=0.0, right=1.0, top=1.0, wspace=0, hspace=0) self._a_oimg = self._f_oimg.add_subplot(111) self._a_oimg.axis('off') self._oi_canvas = FigureCanvasTkAgg(self._f_oimg, master=self.iot_frameMain) self._oi_frame_canvas = self._oi_canvas.get_tk_widget() self._oi_frame_canvas.grid(row=1, column=0, sticky='nsew') self._oi_frame_itoolbar = ttk.Frame(self.iot_frameMain) self._oi_frame_itoolbar.grid(row=0, column=0, sticky='nsew') self._t_oimg = NavigationToolbar2Tk(self._oi_canvas, self._oi_frame_itoolbar) def show_image(self): colormap = self._colormap_options.get('Source') self._s_oimg = self._a_oimg.imshow(self._source_img, cmap=colormap) try: x1 = self._img_info['xmin'].get() x2 = self._img_info['xmax'].get() y1 = self._img_info['ymin'].get() y2 = self._img_info['ymax'].get() width = np.abs(x2 - x1) height = np.abs(y2 - y1) citem = Rectangle((x1, y1), width, height, fc='none', ec='green') self._a_oimg.add_artist(citem) except ValueError: pass self._canvas.draw() def hide_delete(self): try: plt.close(self._f_oimg) except AttributeError: pass try: self._oi_canvas.delete(ALL) except AttributeError: pass
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()
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)
class ClockTreeGUI(): def __init__(self, root): self.root = root self.root.title( "Drexel University VANDAL Lab: Clock Tree Synthesis, Version 0.4") root.minsize(width=1280, height=750) root.maxsize(width=1280, height=750) #Place widgets below here menubar = Menu(root) filemenu = Menu(menubar, tearoff=0) filemenu.add_command(label="Close", command=self.close) menubar.add_cascade(label="File", menu=filemenu) helpmenu = Menu(menubar, tearoff=0) helpmenu.add_command(label="How to Use", command=self.showHelp) menubar.add_cascade(label="Help", menu=helpmenu) f = Figure(figsize=(7, 4), dpi=100) a = f.add_subplot(111) a.plot(LocationX, LocationY, '.') a.set_title('Clock Tree') a.set_xlabel('X-Location') a.set_ylabel('Y-Location') self.v = IntVar() self.v.set(0) self.frame2 = LabelFrame(root, text="List of Nodes", width=640, height=300, bd=5) self.frame3 = LabelFrame(root, text="Detailed Node Information", width=640, height=350, bd=5) self.frame4 = LabelFrame(root, text="Search", width=200, height=100, bd=5) self.canvasTree = FigureCanvasTkAgg(f, master=root) toolbarFrame = Frame(root) self.scrollBar = Scrollbar(self.frame2, orient=VERTICAL, jump=1) self.scrollBarText = Scrollbar(self.frame3, orient=VERTICAL) self.ListBox1 = Listbox(self.frame2, width=18, height=15, yscrollcommand=self.scrollBar.set) self.SearchEntry = Entry(self.frame4, width=25) self.NodeInfoTextBox = Text(self.frame3, height=15, width=85, yscrollcommand=self.scrollBarText.set) self.SearchButton = Button(text="Search", width=25, command=self.searchNode) self.DisplayButton = Button(text="Display", width=25, command=self.displayNodeInfo) self.ClearButton = Button(text="Clear", width=25, command=self.clearText) self.RadioButton = Radiobutton(root, text="Display Children with Parent", variable=self.v) canvas = FigureCanvasTkAgg(f, master=root) canvas.show() canvas.get_tk_widget().grid(row=1, column=1, columnspan=5) canvas._tkcanvas.grid(row=0, column=1) def getClosestNode(self, XCoord, YCoord): xIndex = 0 while (xIndex < len(LocationX)): if (LocationX[xIndex] == XCoord): break else: xIndex = xIndex + 1 yIndex = 0 while (yIndex < len(LocationY)): if (LocationY[yIndex] == YCoord): break else: yIndex = yIndex + 1 if (yIndex == xIndex): self.NodeInfoTextBox.insert(END, List.PrintNodeDetails(xIndex)) def callback(event): global XCoord, YCoord tempx = float(event.xdata) tempy = float(event.ydata) XCoord = float(round(tempx, 2)) YCoord = float(round(tempy, 2)) getClosestNode(self, XCoord, YCoord) canvas.mpl_connect('button_press_event', callback) toolbarFrame.grid(row=0, column=0, columnspan=3) toolbar = NavigationToolbar2TkAgg(canvas, toolbarFrame) #Set up the grid of the GUI here self.scrollBar.grid(row=2, column=1, sticky='NW') self.ListBox1.grid(row=2, column=0) self.NodeInfoTextBox.grid(row=2, column=0) self.SearchEntry.grid(row=2, column=1) self.frame2.grid(row=2, column=0) self.frame3.grid(row=2, column=3, sticky='NW') self.frame4.grid(row=2, column=1, sticky='NW') self.SearchButton.grid(row=2, column=1, sticky='W') self.DisplayButton.grid(row=2, column=2) self.ClearButton.grid(row=2, column=2, sticky='NW') self.RadioButton.grid(row=3, column=1, sticky='NW') #Print the Nodes into the list box here for i in range(0, len(NodeNumbers)): self.ListBox1.insert(END, "Node Number: " + str(i)) #Configure the widgets here root.config(menu=menubar) self.scrollBar.config(command=self.ListBox1.yview) self.scrollBarText.config(command=self.NodeInfoTextBox.yview) ####### Utility functions to display node information ########## def searchNode(self): node = self.SearchEntry.get() if (node == ''): error = "Please make a valid search!" print(error) else: int(node) self.ListBox1.selection_set(node) self.ListBox1.see(node) #ADD ERROR CHEKCING AT SOME POINT def displayNodeInfo(self): line = self.ListBox1.curselection() value = self.ListBox1.get(line[0]) number = value.strip("Node Number: ") numberFloat = float(number) self.NodeInfoTextBox.insert(END, List.PrintNodeDetails(numberFloat)) if (choice == 1): self.showChildren(target) def clearText(self): self.NodeInfoTextBox.delete('1.0', END) for i in range(0, len(displayList)): self.canvasTree.delete(displayList[i]) for j in range(0, len(parentChildList)): self.canvasTree.delete(parentChildList[j]) def showHelp(self): print("This is a work in progress\n") def close(self): exit(-1) def showChildren(self, parent): leftChildNum = parent.LeftChild rightChildNum = parent.RightChild if (leftChildNum != "None"): self.leftChild = Toplevel(width=85, height=16) self.textBoxLeft = Text(self.leftChild, height=25, width=85, yscrollcommand=self.scrollBarText.set) self.textBoxLeft.pack() self.textBoxLeft.insert(END, List.PrintNodeDetails(leftChildNum)) if (rightChildNum != "None"): self.rightChild = Toplevel(width=85, height=16) self.textBoxRight = Text(self.rightChild, height=25, width=85, yscrollcommand=self.scrollBarText.set) self.textBoxRight.pack() self.textBoxRight.insert(END, List.PrintNodeDetails(rightChildNum))
class wishbone_gui(tk.Tk): def __init__(self,parent): tk.Tk.__init__(self,parent) self.parent = parent self.initialize() def initialize(self): self.grid() self.vals = None self.currentPlot = None #set up menu bar self.menubar = tk.Menu(self) self.fileMenu = tk.Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="File", menu=self.fileMenu) self.fileMenu.add_command(label="Load data", command=self.loadData) self.fileMenu.add_command(label="Save data", state='disabled', command=self.saveData) self.fileMenu.add_command(label="Exit Wishbone", command=self.quitWB) self.analysisMenu = tk.Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Analysis", menu=self.analysisMenu) self.analysisMenu.add_command(label="Principal component analysis", state='disabled', command=self.runPCA) self.analysisMenu.add_command(label="tSNE", state='disabled', command=self.runTSNE) self.analysisMenu.add_command(label="Diffusion map", state='disabled', command=self.runDM) self.analysisMenu.add_command(label="GSEA", state='disabled', command=self.runGSEA) self.analysisMenu.add_command(label="Wishbone", state='disabled', command=self.runWishbone) self.visMenu = tk.Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label="Visualization", menu=self.visMenu) self.visMenu.add_command(label="Principal component analysis", state='disabled', command=self.plotPCA) self.visMenu.add_command(label="tSNE", state='disabled', command=self.plotTSNE) self.visMenu.add_command(label="Diffusion map", state='disabled', command=self.plotDM) self.visMenu.add_command(label="GSEA Results", state='disabled', command=self.showGSEAResults) self.wishboneMenu = tk.Menu(self) self.visMenu.add_cascade(label="Wishbone", menu=self.wishboneMenu) self.wishboneMenu.add_command(label="On tSNE", state='disabled', command=self.plotWBOnTsne) self.wishboneMenu.add_command(label="Marker trajectory", state='disabled', command=self.plotWBMarkerTrajectory) self.wishboneMenu.add_command(label="Heat map", state='disabled', command=self.plotWBHeatMap) self.visMenu.add_command(label="Gene expression", state='disabled', command=self.plotGeneExpOntSNE) self.visMenu.add_command(label="Set gate", state='disabled', command=self.setGate) self.config(menu=self.menubar) #intro screen tk.Label(self, text=u"Wishbone", font=('Helvetica', 48), fg="black", bg="white", padx=100, pady=50).grid(row=0) tk.Label(self, text=u"To get started, select a data file by clicking File > Load Data", fg="black", bg="white", padx=100, pady=25).grid(row=1) #update self.protocol('WM_DELETE_WINDOW', self.quitWB) self.grid_columnconfigure(0,weight=1) self.resizable(True,True) self.update() self.geometry(self.geometry()) self.focus_force() def loadData(self): self.dataFileName = filedialog.askopenfilename(title='Load data file', initialdir='~/.wishbone/data') if(self.dataFileName != ""): #pop up data options menu self.fileInfo = tk.Toplevel() self.fileInfo.title("Data options") tk.Label(self.fileInfo, text=u"File name: ").grid(column=0, row=0) tk.Label(self.fileInfo, text=self.dataFileName.split('/')[-1]).grid(column=1, row=0) tk.Label(self.fileInfo,text=u"Name:" ,fg="black",bg="white").grid(column=0, row=1) self.fileNameEntryVar = tk.StringVar() tk.Entry(self.fileInfo, textvariable=self.fileNameEntryVar).grid(column=1,row=1) if self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'fcs': tk.Label(self.fileInfo,text=u"Cofactor:" ,fg="black",bg="white").grid(column=0, row=2) self.cofactorVar = tk.IntVar() self.cofactorVar.set(5) tk.Entry(self.fileInfo, textvariable=self.cofactorVar).grid(column=1,row=2) elif self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'csv': self.normalizeVar = tk.BooleanVar() tk.Checkbutton(self.fileInfo, text=u"Normalize", variable=self.normalizeVar).grid(column=0, row=2, columnspan=2) tk.Label(self.fileInfo, text=u"The normalize parameter is used for correcting for library size among cells.").grid(column=0, row=3, columnspan=2) tk.Button(self.fileInfo, text="Cancel", command=self.fileInfo.destroy).grid(column=0, row=4) tk.Button(self.fileInfo, text="Load", command=self.processData).grid(column=1, row=4) self.wait_window(self.fileInfo) def processData(self): #clear intro screen for item in self.grid_slaves(): item.grid_forget() #display file name tk.Label(self,text=u"File name: " + self.fileNameEntryVar.get(), fg="black",bg="white").grid(column=0,row=0) #set up canvas for plots self.fig, self.ax = wishbone.wb.get_fig() self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='NSEW') tk.Label(self, text=u"Visualizations:", fg='black', bg='white').grid(column=0, row=1) #load data based on input type if self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'fcs': # mass cytometry data self.scdata = wishbone.wb.SCData.from_fcs(os.path.expanduser(self.dataFileName), cofactor=self.cofactorVar.get()) self.wb = None elif self.dataFileName.split('.')[len(self.dataFileName.split('.'))-1] == 'csv': # sc-seq data self.scdata = wishbone.wb.SCData.from_csv(os.path.expanduser(self.dataFileName), data_type='sc-seq', normalize=self.normalizeVar.get()) self.wb = None else: self.wb = wishbone.wb.Wishbone.load(self.dataFileName) self.scdata = self.wb.scdata #set up buttons based on data type if self.scdata.data_type == 'sc-seq': self.PCAButton = tk.Button(self, text=u"PCA", state='disabled', command=self.plotPCA) self.PCAButton.grid(column=0, row=2) self.tSNEButton = tk.Button(self, text=u"tSNE", state='disabled', command=self.plotTSNE) self.tSNEButton.grid(column=0, row=3) self.DMButton = tk.Button(self, text=u"Diffusion map", state='disabled', command=self.plotDM) self.DMButton.grid(column=0, row=4) self.GSEAButton = tk.Button(self, text=u"GSEA Results", state='disabled', command=self.showGSEAResults) self.GSEAButton.grid(column=0, row=5) self.WBButton = tk.Button(self, text=u"Wishbone", state='disabled', command=self.plotWBOnTsne) self.WBButton.grid(column=0, row=6) self.geneExpButton = tk.Button(self, text=u"Gene expression", state='disabled', command=self.plotGeneExpOntSNE) self.geneExpButton.grid(column=0, row=7) self.setGateButton = tk.Button(self, text=u"Set gate", state='disabled', command=self.setGate) self.setGateButton.grid(column=0, row=8) self.saveButton = tk.Button(self, text=u"Save plot", state='disabled', command=self.savePlot) self.saveButton.grid(column = 4, row=0) self.diff_component = tk.StringVar() self.diff_component.set('Component 1') self.component_menu = tk.OptionMenu(self, self.diff_component, 'Component 1', 'Component 2', 'Component 3', 'Component 4', 'Component 5', 'Component 6', 'Component 7', 'Component 8', 'Component 9') self.component_menu.config(state='disabled') self.component_menu.grid(row=0, column=2) self.updateButton = tk.Button(self, text=u"Update component", command=self.updateComponent, state='disabled') self.updateButton.grid(column=3, row=0) #enable buttons based on current state of scdata object if self.scdata.pca: self.analysisMenu.entryconfig(1, state='normal') self.visMenu.entryconfig(0, state='normal') self.PCAButton.config(state='normal') if isinstance(self.scdata.tsne, pd.DataFrame): self.analysisMenu.entryconfig(2, state='normal') self.visMenu.entryconfig(1, state='normal') self.visMenu.entryconfig(5, state='normal') self.tSNEButton.config(state='normal') self.geneExpButton.config(state='normal') if isinstance(self.scdata.diffusion_eigenvectors, pd.DataFrame): self.analysisMenu.entryconfig(3, state='normal') self.analysisMenu.entryconfig(4, state='normal') self.visMenu.entryconfig(2, state='normal') self.DMButton.config(state='normal') else: self.tSNEButton = tk.Button(self, text=u"tSNE", state='disabled', command=self.plotTSNE) self.tSNEButton.grid(column=0, row=2) self.DMButton = tk.Button(self, text=u"Diffusion map", state='disabled', command=self.plotDM) self.DMButton.grid(column=0, row=3) self.WBButton = tk.Button(self, text=u"Wishbone", state='disabled', command=self.plotWBOnTsne) self.WBButton.grid(column=0, row=4) self.geneExpButton = tk.Button(self, text=u"Gene expression", state='disabled', command=self.plotGeneExpOntSNE) self.geneExpButton.grid(column=0, row=5) self.setGateButton = tk.Button(self, text=u"Set gate", state='disabled', command=self.setGate) self.setGateButton.grid(column=0, row=6) self.saveButton = tk.Button(self, text=u"Save plot", state='disabled', command=self.savePlot) self.saveButton.grid(column = 4, row=0) self.analysisMenu.delete(0) self.analysisMenu.delete(2) self.visMenu.delete(0) self.visMenu.delete(2) self.analysisMenu.entryconfig(1, state='normal') #enable buttons based on current state of scdata object if isinstance(self.scdata.tsne, pd.DataFrame): self.visMenu.entryconfig(0, state='normal') self.visMenu.entryconfig(3, state='normal') self.tSNEButton.config(state='normal') self.geneExpButton.config(state='normal') if isinstance(self.scdata.diffusion_eigenvectors, pd.DataFrame): self.analysisMenu.entryconfig(2, state='normal') self.visMenu.entryconfig(1, state='normal') self.DMButton.config(state='normal') #enable buttons self.analysisMenu.entryconfig(0, state='normal') self.fileMenu.entryconfig(1, state='normal') if self.wb: if isinstance(self.wb.trajectory, pd.Series): self.wishboneMenu.entryconfig(0, state='normal') self.wishboneMenu.entryconfig(1, state='normal') self.wishboneMenu.entryconfig(2, state='normal') self.WBButton.config(state='normal') #get genes self.genes = self.scdata.data.columns.values self.gates = {} self.geometry('800x550') #destroy pop up menu self.fileInfo.destroy() def saveData(self): pickleFileName = filedialog.asksaveasfilename(title='Save Wishbone Data', defaultextension='.p', initialfile=self.fileNameEntryVar.get()) if pickleFileName != None: if self.wb != None: self.wb.save(pickleFileName) else: self.scdata.save_as_wishbone(pickleFileName) def runPCA(self): self.scdata.run_pca() #enable buttons self.analysisMenu.entryconfig(1, state='normal') self.visMenu.entryconfig(0, state='normal') self.PCAButton.config(state='normal') def runTSNE(self): #pop up for # components self.tsneOptions = tk.Toplevel() self.tsneOptions.title("tSNE options") if self.scdata.data_type == 'sc-seq': tk.Label(self.tsneOptions,text=u"Number of components:" ,fg="black",bg="white").grid(column=0, row=0) self.nCompVar = tk.IntVar() self.nCompVar.set(15) tk.Entry(self.tsneOptions, textvariable=self.nCompVar).grid(column=1,row=0) tk.Label(self.tsneOptions,text=u"Perplexity:" ,fg="black",bg="white").grid(column=0, row=1) self.perplexityVar = tk.IntVar() self.perplexityVar.set(30) tk.Entry(self.tsneOptions, textvariable=self.perplexityVar).grid(column=1,row=1) tk.Button(self.tsneOptions, text="Run", command=self._runTSNE).grid(column=1, row=2) tk.Button(self.tsneOptions, text="Cancel", command=self.tsneOptions.destroy).grid(column=0, row=2) self.wait_window(self.tsneOptions) def _runTSNE(self): if self.scdata.data_type == 'sc-seq': self.scdata.run_tsne(n_components=self.nCompVar.get(), perplexity=self.perplexityVar.get()) else: self.scdata.run_tsne(n_components=None, perplexity=self.perplexityVar.get()) self.gates = {} #enable buttons if self.scdata.data_type == 'sc-seq': self.analysisMenu.entryconfig(2, state='normal') self.visMenu.entryconfig(1, state='normal') self.visMenu.entryconfig(5, state='normal') else: self.visMenu.entryconfig(0, state='normal') self.visMenu.entryconfig(3, state='normal') self.tSNEButton.config(state='normal') self.geneExpButton.config(state='normal') self.tsneOptions.destroy() def runDM(self): self.scdata.run_diffusion_map() #enable buttons if self.scdata.data_type == 'sc-seq': self.analysisMenu.entryconfig(3, state='normal') self.analysisMenu.entryconfig(4, state='normal') self.visMenu.entryconfig(2, state='normal') else: self.analysisMenu.entryconfig(2, state='normal') self.visMenu.entryconfig(1, state='normal') self.DMButton.config(state='normal') def runGSEA(self): self.GSEAFileName = filedialog.askopenfilename(title='Select gmt File', initialdir='~/.wishbone/tools') if self.GSEAFileName != "": self.scdata.run_diffusion_map_correlations() self.scdata.data.columns = self.scdata.data.columns.str.upper() self.outputPrefix = filedialog.asksaveasfilename(title='Input file prefix for saving output', initialdir='~/.wishbone/gsea') if 'mouse' in self.GSEAFileName: gmt_file_type = 'mouse' else: gmt_file_type = 'human' self.reports = self.scdata.run_gsea(output_stem= os.path.expanduser(self.outputPrefix), gmt_file=(gmt_file_type, self.GSEAFileName.split('/')[-1])) #enable buttons self.visMenu.entryconfig(3, state='normal') self.GSEAButton.config(state='normal') def runWishbone(self): #popup menu for wishbone options self.wbOptions = tk.Toplevel() self.wbOptions.title("Wishbone Options") #s tk.Label(self.wbOptions,text=u"Start cell:",fg="black",bg="white").grid(column=0,row=0) self.start = tk.StringVar() tk.Entry(self.wbOptions, textvariable=self.start).grid(column=1,row=0) if(len(self.gates) > 0): self.cell_gate = tk.StringVar() self.cell_gate.set('Use cell gate') self.gate_menu = tk.OptionMenu(self.wbOptions, self.cell_gate, *list(self.gates.keys())) self.gate_menu.grid(row=0, column=2) #k tk.Label(self.wbOptions,text=u"k:",fg="black",bg="white").grid(column=0,row=1) self.k = tk.IntVar() tk.Entry(self.wbOptions, textvariable=self.k).grid(column=1,row=1) self.k.set(15) #components list tk.Label(self.wbOptions, text=u"Components list:", fg='black', bg='white').grid(column=0, row=2) self.compList = tk.StringVar() tk.Entry(self.wbOptions, textvariable=self.compList).grid(column=1, row=2) self.compList.set("1, 2, 3") #num waypoints tk.Label(self.wbOptions, text=u"Number of waypoints:", fg='black', bg='white').grid(column=0, row=3) self.numWaypoints = tk.IntVar() tk.Entry(self.wbOptions, textvariable=self.numWaypoints).grid(column=1, row=3) self.numWaypoints.set(250) #branch self.branch = tk.BooleanVar() self.branch.set(True) tk.Checkbutton(self.wbOptions, text=u"Branch", variable=self.branch).grid(column=0, row=4, columnspan=2) tk.Button(self.wbOptions, text="Run", command=self._runWishbone).grid(column=1, row=5) tk.Button(self.wbOptions, text="Cancel", command=self.wbOptions.destroy).grid(column=0, row=5) self.wait_window(self.wbOptions) def _runWishbone(self): self.wb = wishbone.wb.Wishbone(self.scdata) if self.cell_gate.get() == 'Use cell gate': self.wb.run_wishbone(start_cell=self.start.get(), k=self.k.get(), components_list=[int(comp) for comp in self.compList.get().split(',')], num_waypoints=self.numWaypoints.get()) else: #randomly select start cell in gate print('Using cell gate:') print(self.cell_gate.get()) start_cell = random.sample(list(self.gates[self.cell_gate.get()]), 1)[0] print(start_cell) self.wb.run_wishbone(start_cell=start_cell, k=self.k.get(), components_list=[int(comp) for comp in self.compList.get().split(',')], num_waypoints=self.numWaypoints.get()) #enable buttons self.wishboneMenu.entryconfig(0, state='normal') self.wishboneMenu.entryconfig(1, state='normal') self.wishboneMenu.entryconfig(2, state='normal') self.WBButton.config(state='normal') self.wbOptions.destroy() def plotPCA(self): self.saveButton.config(state='normal') self.setGateButton.config(state='disabled') if self.scdata.data_type == 'sc-seq': self.component_menu.config(state='disabled') self.updateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') else: self.visMenu.entryconfig(4, state='disabled') #pop up for # components self.PCAOptions = tk.Toplevel() self.PCAOptions.title("PCA Plot Options") tk.Label(self.PCAOptions,text=u"Max variance explained (ylim):",fg="black",bg="white").grid(column=0, row=0) self.yLimVar = tk.DoubleVar() self.yLimVar.set(round(self.scdata.pca['eigenvalues'][0][0], 2)) tk.Entry(self.PCAOptions, textvariable=self.yLimVar).grid(column=1,row=0) tk.Label(self.PCAOptions, text=u"Number of components:", fg='black', bg='white').grid(column=0, row=1) self.compVar = tk.IntVar() self.compVar.set(15) tk.Entry(self.PCAOptions, textvariable=self.compVar).grid(column=1, row=1) tk.Button(self.PCAOptions, text="Plot", command=self._plotPCA).grid(column=1, row=2) tk.Button(self.PCAOptions, text="Cancel", command=self.PCAOptions.destroy).grid(column=0, row=2) self.wait_window(self.PCAOptions) def _plotPCA(self): self.resetCanvas() self.fig, self.ax = self.scdata.plot_pca_variance_explained(ylim=(0, self.yLimVar.get()), n_components=self.compVar.get()) self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='NW') self.currentPlot = 'pca' #enable buttons self.saveButton.config(state='normal') self.PCAOptions.destroy() def plotTSNE(self): self.saveButton.config(state='normal') self.setGateButton.config(state='normal') if self.scdata.data_type == 'sc-seq': self.component_menu.config(state='disabled') self.updateButton.config(state='disabled') self.visMenu.entryconfig(6, state='normal') else: self.visMenu.entryconfig(4, state='normal') self.resetCanvas() self.fig, self.ax = self.scdata.plot_tsne() self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='NW') self.currentPlot = 'tsne' def plotDM(self): self.saveButton.config(state='normal') self.setGateButton.config(state='disabled') if self.scdata.data_type == 'sc-seq': self.component_menu.config(state='disabled') self.updateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') else: self.visMenu.entryconfig(4, state='disabled') self.geometry('950x550') self.resetCanvas() self.fig, self.ax = self.scdata.plot_diffusion_components() self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='W') self.currentPlot = 'dm_components' def showGSEAResults(self): self.saveButton.config(state='disabled') self.component_menu.config(state='normal') self.updateButton.config(state='normal') self.setGateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') self.resetCanvas() self.canvas = tk.Canvas(self, width=600, height=300) self.canvas.grid(column=1, row=1, rowspan=17, columnspan=4) self.outputText(1) self.currentPlot = 'GSEA_result_'+self.diff_component.get() def updateComponent(self): self.resetCanvas() self.canvas = tk.Canvas(self, width=600, height=300) self.canvas.grid(column=1, row=1, rowspan=17, columnspan=4,sticky='NSEW') self.outputText(int(self.diff_component.get().split(' ')[-1])) self.currentPlot = 'GSEA_result_'+self.diff_component.get() def outputText(self, diff_component): pos_text = str(self.reports[diff_component]['pos']).split('\n') pos_text = pos_text[1:len(pos_text)-1] pos_text = '\n'.join(pos_text) neg_text = str(self.reports[diff_component]['neg']).split('\n') neg_text = neg_text[1:len(neg_text)-1] neg_text = '\n'.join(neg_text) self.canvas.create_text(5, 5, anchor='nw', text='Positive correlations:\n\n', font=('Helvetica', 16, 'bold')) self.canvas.create_text(5, 50, anchor='nw', text=pos_text) self.canvas.create_text(5, 150, anchor='nw', text='Negative correlations:\n\n', font=('Helvetica', 16, 'bold')) self.canvas.create_text(5, 200, anchor='nw', text=neg_text) def plotWBOnTsne(self): self.saveButton.config(state='normal') self.setGateButton.config(state='disabled') if self.scdata.data_type == 'sc-seq': self.component_menu.config(state='disabled') self.updateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') else: self.visMenu.entryconfig(4, state='disabled') self.resetCanvas() self.fig, self.ax = self.wb.plot_wishbone_on_tsne() self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4) self.currentPlot = 'wishbone_on_tsne' def plotWBMarkerTrajectory(self): self.getGeneSelection() if len(self.selectedGenes) < 1: print('Error: must select at least one gene') else: self.saveButton.config(state='normal') self.setGateButton.config(state='disabled') if self.scdata.data_type == 'sc-seq': self.component_menu.config(state='disabled') self.updateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') else: self.visMenu.entryconfig(4, state='disabled') self.resetCanvas() self.vals, self.fig, self.ax = self.wb.plot_marker_trajectory(self.selectedGenes) self.fig.set_size_inches(10, 4, forward=True) self.fig.tight_layout() self.fig.subplots_adjust(right=0.8) self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=5, sticky='W') self.currentPlot = 'wishbone_marker_trajectory' self.geometry('1050x550') #enable buttons self.wishboneMenu.entryconfig(2, state='normal') def plotWBHeatMap(self): self.getGeneSelection() if len(self.selectedGenes) < 1: print('Error: must select at least one gene') else: self.saveButton.config(state='normal') self.setGateButton.config(state='disabled') if self.scdata.data_type == 'sc-seq': self.component_menu.config(state='disabled') self.updateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') else: self.visMenu.entryconfig(4, state='disabled') self.resetCanvas() self.vals, self.fig, self.ax = self.wb.plot_marker_trajectory(self.selectedGenes) self.fig, self.ax = self.wb.plot_marker_heatmap(self.vals) self.fig.set_size_inches(10, 4, forward=True) self.fig.tight_layout() self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=5, sticky='W') self.currentPlot = 'wishbone_marker_heatmap' def plotGeneExpOntSNE(self): self.getGeneSelection() if len(self.selectedGenes) < 1: print('Error: must select at least one gene') else: self.saveButton.config(state='normal') self.setGateButton.config(state='disabled') if self.scdata.data_type == 'sc-seq': self.component_menu.config(state='disabled') self.updateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') else: self.visMenu.entryconfig(4, state='disabled') self.resetCanvas() self.fig, self.ax = self.scdata.plot_gene_expression(self.selectedGenes) self.canvas = FigureCanvasTkAgg(self.fig, self) self.canvas.show() self.canvas.get_tk_widget().grid(column=1, row=1, rowspan=10, columnspan=4,sticky='W') self.currentPlot = 'gene_expression_tsne' self.geometry('950x550') def getGeneSelection(self): #popup menu to get selected genes self.geneSelection = tk.Toplevel() self.geneSelection.title("Select Genes") tk.Label(self.geneSelection,text=u"Genes:",fg="black",bg="white").grid(row=0) self.geneInput = wishbone.autocomplete_entry.AutocompleteEntry(self.genes.tolist(), self.geneSelection, listboxLength=6) self.geneInput.grid(row=1) self.geneInput.bind('<Return>', self.AddToSelected) self.geneSelectBox = tk.Listbox(self.geneSelection, selectmode=tk.EXTENDED) self.geneSelectBox.grid(row=2, rowspan=10) self.geneSelectBox.bind('<BackSpace>', self.DeleteSelected) self.selectedGenes = [] tk.Button(self.geneSelection, text="Use selected genes", command=self.geneSelection.destroy).grid(row=12) tk.Button(self.geneSelection, text="Cancel", command=self.cancelGeneSelection).grid(row=13) self.wait_window(self.geneSelection) def cancelGeneSelection(self): self.selectedGenes = [] self.geneSelection.destroy() def AddToSelected(self, event): self.selectedGenes.append(self.geneInput.get()) self.geneSelectBox.insert(tk.END, self.selectedGenes[len(self.selectedGenes)-1]) def DeleteSelected(self, event): selected = self.geneSelectBox.curselection() pos = 0 for i in selected: idx = int(i) - pos self.geneSelectBox.delete( idx,idx ) self.selectedGenes = self.selectedGenes[:idx] + self.selectedGenes[idx+1:] pos = pos + 1 def savePlot(self): self.plotFileName = filedialog.asksaveasfilename(title='Save Plot', defaultextension='.png', initialfile=self.fileNameEntryVar.get()+"_"+self.currentPlot) if self.plotFileName != None: self.fig.savefig(self.plotFileName) def setGate(self): #pop up for gate name self.gateOptions = tk.Toplevel() self.gateOptions.title("Create gate for start cells") tk.Label(self.gateOptions,text=u"Gate name:" ,fg="black",bg="white").grid(column=0, row=0) self.gateName = tk.StringVar() self.gateName.set('Gate ' + str(len(self.gates) + 1)) tk.Entry(self.gateOptions, textvariable=self.gateName).grid(column=1,row=0) tk.Button(self.gateOptions, text="Select gate", command=self._setGate).grid(column=1, row=1) tk.Button(self.gateOptions, text="Cancel", command=self.gateOptions.destroy).grid(column=0, row=1) self.wait_window(self.gateOptions) def _setGate(self): self.gateOptions.destroy() self.buttonPress = self.canvas.mpl_connect('button_press_event', self._startGate) self.buttonRelease = self.canvas.mpl_connect('button_release_event', self._endGate) self.canvas.get_tk_widget().config(cursor='plus') def _startGate(self, event): self.start_x = event.xdata self.start_y = event.ydata def _endGate(self, event): #draw gate rectangle start_x = self.start_x if self.start_x < event.xdata else event.xdata start_y = self.start_y if self.start_y < event.ydata else event.ydata width = np.absolute(event.xdata-self.start_x) height = np.absolute(event.ydata-self.start_y) rect = Rectangle((start_x, start_y), width, height, fill=False, ec='black', alpha=1, lw=2) self.ax.add_patch(rect) self.canvas.draw() #disable mouse events self.canvas.mpl_disconnect(self.buttonPress) self.canvas.mpl_disconnect(self.buttonRelease) self.canvas.get_tk_widget().config(cursor='arrow') #save cell gate gate = Path([[start_x, start_y], [start_x + width, start_y], [start_x + width, start_y + height], [start_x, start_y + height], [start_x, start_y]]) gated_cells = self.scdata.tsne.index[gate.contains_points(self.scdata.tsne)] self.gates[self.gateName.get()] = gated_cells #replot tSNE w gate colored self.fig.clf() plt.scatter(self.scdata.tsne['x'], self.scdata.tsne['y'], s=10, edgecolors='none', color='lightgrey') plt.scatter(self.scdata.tsne.ix[gated_cells, 'x'], self.scdata.tsne.ix[gated_cells, 'y'], s=10, edgecolors='none') self.canvas.draw() self.setGateButton.config(state='disabled') self.visMenu.entryconfig(6, state='disabled') def resetCanvas(self): self.fig.clf() if type(self.canvas) is FigureCanvasTkAgg: for item in self.canvas.get_tk_widget().find_all(): self.canvas.get_tk_widget().delete(item) else: for item in self.canvas.find_all(): self.canvas.delete(item) def quitWB(self): self.quit() self.destroy()
class 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()