class VisualizerWindow: root = [] dataMgr = [] #graphs fig = [] ax1 = [] ax2 = [] ax3 = [] ax4 = [] ylim_ax1 = [] ylim_ax2 = [] ylim_ax3 = [] #data x = [] usage_manual = [] #debug show_debug_msg = False #autosave (-1 for disable) autosave_period = 30 load_autosave_file = False def __init__(self, filename): self.root = Tk.Tk() self.root.wm_title("EMG-Visualization-Tool") self.root.protocol("WM_DELETE_WINDOW", self._quit) if not filename: filename = askopenfilename() if not filename: sys.exit(0) while not os.path.isfile(filename): showerror("File not found", "Sorry, file '{}' was not found, try again".format(filename)) filename = askopenfilename() if not filename: sys.exit(0) if filename[-19:] == '_usage_autosave.pkl': self.autosave_file = filename print('Input file is an Auto-Save file "{}"'.format(self.autosave_file)) filename = filename[:-19] + '.csv' if not os.path.isfile(filename): showerror('Could not find file "{}" (matching to provided auto-save file "{}")'.format(filename, self.autosave_file)) print('Error: matching file not found (expected "{}")'.format(filename)) print('EXIT') sys.exit(0) else: self.load_autosave_file = True else: self.autosave_file = filename.rsplit(".", 1)[0] + "_usage_autosave.pkl" if os.path.isfile(self.autosave_file): print('Auto-Save file "{}" already exists'.format(self.autosave_file)) if askyesno('Auto-Save file found', 'Auto-Save file "{}" found. Load it instead? ("No" will result in automatical overwriting of the file when auto-saving)'.format(self.autosave_file)): self.load_autosave_file = True self.root.wm_title("EMG-Visualization-Tool: {}".format(filename)) self.dataMgr = DataManager(filename) self.csv_out_file = filename.rsplit(".", 1)[0] + "_usage.csv" while os.path.isfile(self.csv_out_file): print('File "{}" already exists'.format(self.csv_out_file)) if askyesno('Overwrite File?', 'File "{}" already exists. Overwrite?'.format(self.csv_out_file)): print('overwriting "{}"'.format(self.csv_out_file)) break else: new_out_file = asksaveasfilename(initialfile=self.csv_out_file) if new_out_file: self.csv_out_file = new_out_file print('New Output file "{}"'.format(self.csv_out_file)) else: sys.exit(0) print("csv-out-file: {}".format(self.csv_out_file)) self.configFrame = Tk.Frame(self.root, height=500, width=400) Tk.Label(self.configFrame, text="\r\nPlot 1").pack() self.plot1_select = ttk.Combobox(self.configFrame, values=self.dataMgr.plot_columns, state="readonly") self.plot1_select.pack() if '"f"' in self.dataMgr.plot_columns: self.plot1_select.current(self.dataMgr.plot_columns.index('"f"')) else: self.plot1_select.current(0) Tk.Label(self.configFrame, text="Plot 2").pack() self.plot2_select = ttk.Combobox(self.configFrame, values=self.dataMgr.plot_columns, state="readonly") self.plot2_select.pack() if '"rmsd"' in self.dataMgr.plot_columns: self.plot2_select.current(self.dataMgr.plot_columns.index('"rmsd"')) else: self.plot2_select.current(0) Tk.Label(self.configFrame, text="Plot 3").pack() self.plot3_select = ttk.Combobox(self.configFrame, values=self.dataMgr.plot_columns, state="readonly") self.plot3_select.pack() if '"beat"' in self.dataMgr.plot_columns: self.plot3_select.current(self.dataMgr.plot_columns.index('"beat"')) else: self.plot3_select.current(0) Tk.Label(self.configFrame, text="\r\nUsage Plot").pack() self.usage_plots = {} for usg in self.dataMgr.usage_columns: if not usg == '"usage_manual"': chkbx_var = Tk.IntVar() chkbx_var.set(1) usg_check = ttk.Checkbutton(self.configFrame, text=usg, variable=chkbx_var) usg_check.pack() self.usage_plots[usg] = chkbx_var Tk.Label(self.configFrame, text="\r\nLoad/copy \"usage_manual\" from").pack() if self.load_autosave_file: Tk.Label(self.configFrame, text="provided Auto-Save file").pack() else: self.usg_man_select = ttk.Combobox(self.configFrame, values=self.dataMgr.usage_columns, state="readonly") self.usg_man_select.pack() if '"usage_manual"' in self.dataMgr.usage_columns: self.usg_man_select.current(self.dataMgr.usage_columns.index('"usage_manual"')) elif '"usage_total"' in self.dataMgr.usage_columns: self.usg_man_select.current(self.dataMgr.usage_columns.index('"usage_total"')) else: if len(self.dataMgr.usage_columns) > 0: self.usg_man_select.current(0) Tk.Label(self.configFrame, text="\r\nJump Column").pack() if len(self.dataMgr.jump_columns) == 0: self.jmp_select = ttk.Combobox(self.configFrame, values=['--none--'], state="readonly") self.jmp_select.current(0) else: self.jmp_select = ttk.Combobox(self.configFrame, values=self.dataMgr.jump_columns, state="readonly") if '"jump_ibi"' in self.dataMgr.jump_columns: self.jmp_select.current(self.dataMgr.jump_columns.index('"jump_ibi"')) else: self.jmp_select.current(0) self.jmp_select.pack() Tk.Label(self.configFrame, text="").pack() button_continue = Tk.Button(self.configFrame, text='Continue', command=self._CfgContinue) button_continue.pack() Tk.Label(self.configFrame, text="").pack() self.loading_label = Tk.Label(self.configFrame, text="") self.loading_label.pack() self.configFrame.pack() self.visualizerFrame = Tk.Frame(self.root) # Figure with Subplots self.fig = plt.figure(figsize=(17,8), dpi=80, tight_layout=True) gs = gridspec.GridSpec(4,1, height_ratios=[3,2,2,1]) self.ax1 = plt.subplot(gs[0]) self.ax2 = plt.subplot(gs[1], sharex=self.ax1) self.ax3 = plt.subplot(gs[2], sharex=self.ax1) self.ax4 = plt.subplot(gs[3], sharex=self.ax1) canvas = FigureCanvasTkAgg(self.fig, master=self.visualizerFrame) canvas.show() canvas.mpl_connect('key_press_event', self.on_key_event) canvas.mpl_connect('button_press_event', self.on_button_event) # GUI Elements self.mode_label = Tk.Label(self.visualizerFrame, text="Mode: ADD", background="green") self.progress_label = Tk.Label(self.visualizerFrame, text="Page {}/{}".format(self.dataMgr.current_page, self.dataMgr.num_pages)) button_prev = Tk.Button(master=self.visualizerFrame, text='Prev', command=self._prev) button_next = Tk.Button(master=self.visualizerFrame, text='Next', command=self._next) button_zoom_in = Tk.Button(master=self.visualizerFrame, text='Zoom In', command=self._zoom_in) button_zoom_out = Tk.Button(master=self.visualizerFrame, text='Zoom Out', command=self._zoom_out) button_add = Tk.Button(master=self.visualizerFrame, text='Add', command=self._add) button_del = Tk.Button(master=self.visualizerFrame, text='Del', command=self._del) saveFrame = Tk.Frame(self.visualizerFrame) button_autosave = Tk.Button(master=saveFrame, text='Auto-Save', command=self._autosave) button_save = Tk.Button(master=saveFrame, text='Save', command=self._save) button_autosave.grid(column=0, row=0) button_save.grid(column=1, row=0) button_quit = Tk.Button(master=self.visualizerFrame, text='Quit', command=self._quit) # Selection self.multi_cursor = MultiCursor(self.fig.canvas, (self.ax1, self.ax2, self.ax3, self.ax4), useblit=True, horizOn=False, vertOn=True, color='g', lw=1) self.span1 = SpanSelector(self.ax1, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) self.span2 = SpanSelector(self.ax2, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) self.span3 = SpanSelector(self.ax3, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) self.span4 = SpanSelector(self.ax4, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) # GUI Layout button_zoom_in.grid(column=0, row=0) button_zoom_out.grid(column=1, row=0) button_prev.grid(column=3, row=0) self.progress_label.grid(column=4, row=0) button_next.grid(column=5, row=0) canvas.get_tk_widget().grid(column=0, row=1, columnspan=6) canvas._tkcanvas.grid(column=0, row=1, columnspan=6) button_add.grid(column=0, row=2) button_del.grid(column=1, row=2) self.mode_label.grid(column=2, row=2, columnspan=2) saveFrame.grid(column=4, row=2) button_quit.grid(column=5, row=2) Tk.mainloop() def _CfgContinue(self): self.loading_label['text'] = 'loading ...' self.loading_label.update() self.plot_names = [self.plot1_select.get(), self.plot2_select.get(), self.plot3_select.get()] self.plot_cols = [] for pn in self.plot_names: self.plot_cols.append(self.dataMgr.header_columns.index(pn)) self.usage_names = [] self.usage_cols = [] for k,v in self.usage_plots.items(): if v.get() == 1: self.usage_names.append(k) self.usage_cols.append(self.dataMgr.header_columns.index(k)) if self.load_autosave_file: usg_manual_col = -1 else: if self.usg_man_select.get() in self.dataMgr.header_columns: usg_manual_col = self.dataMgr.header_columns.index(self.usg_man_select.get()) else: usg_manual_col = -1 if self.jmp_select.get() in self.dataMgr.jump_columns: jmp_col = self.dataMgr.header_columns.index(self.jmp_select.get()) else: jmp_col = -1 [self.x, self.plot_data, self.usage_data, self.usage_manual, self.jump_positions] = self.dataMgr.readData(self.plot_cols,self.usage_cols,self.loading_label, usg_manual_col, jmp_col) if self.load_autosave_file: infile = open(self.autosave_file, 'rb') self.usage_manual = pickle.load(infile) infile.close() self.configFrame.pack_forget() self.visualizerFrame.pack() print("displaying plots") self.ylim_ax1 = self.calc_ylims(self.plot_data[0]) self.ylim_ax2 = self.calc_ylims(self.plot_data[1]) self.ylim_ax3 = self.calc_ylims(self.plot_data[2]) self.loadPage(1) def HMS(seconds, pos): """Customized x-axis ticks Keyword arguments: seconds -- input in secs pos -- somehow required argument (matplotlib) """ seconds = int(seconds) hours = seconds / 3600 seconds -= 3600 * hours minutes = seconds / 60 seconds -= 60 * minutes if hours == 0: if minutes == 0: return "%ds" % (seconds) return "%dm%02ds" % (minutes, seconds) return "%dh%02dm" % (hours, minutes) def calc_ylims(self, data): [cnt, edge] = np.histogram(data, 25) s = len(data) thres = 0.975*s i = 0 j = len(cnt)-1 while True: if cnt[i] < cnt[j]: if s-cnt[i] < thres: break else: s -= cnt[i] i += 1 else: if s-cnt[j] < thres: break else: s -= cnt[j] j -= 1 return [min(0, edge[i]), max(1, edge[j+1])] def plotPage(self): index_low = self.dataMgr.low_Idx() index_high = self.dataMgr.high_Idx() if self.show_debug_msg: print("index_low: {} | index_high: {}".format(index_low, index_high)) self.ax1.clear() self.ax1.xaxis.set_major_formatter(plt.FuncFormatter(self.HMS)) self.ax1.plot(self.x[index_low:index_high], np.array(self.plot_data[0][index_low:index_high])) self.ax1.set_ylim(self.ylim_ax1) self.ax1.set_title(self.plot_names[0]) self.ax2.clear() self.ax2.plot(self.x[index_low:index_high], self.plot_data[1][index_low:index_high]) self.ax2.set_ylim(self.ylim_ax2) self.ax2.set_title(self.plot_names[1]) self.ax3.clear() self.ax3.plot(self.x[index_low:index_high], self.plot_data[2][index_low:index_high]) self.ax3.set_ylim(self.ylim_ax3) self.ax3.set_title(self.plot_names[2]) self.plotUsages() self.fig.canvas.draw() def plotUsages(self): index_low = self.dataMgr.low_Idx() index_high = self.dataMgr.high_Idx() self.ax4.clear() self.ax4.set_ylim(0,len(self.usage_names)+2) self.ax4.set_yticks([], minor=False) colors = ['#483D8B', '#228B22', '#B22222', '#8A2BE2', '#808000', '#FF4500', '#DA70D6', '#FFA500'] self.ax4.fill_between(self.x[index_low:index_high], 0, (len(self.usage_names)+2)*np.array(self.usage_manual[index_low:index_high]), facecolor='#7fbf7f', edgecolor='None') self.ax4.plot(self.jump_positions, [len(self.usage_names)+1]*len(self.jump_positions), 'r*') for u in range(0,len(self.usage_data)): self.ax4.fill_between(self.x[index_low:index_high], u, u+np.array(self.usage_data[u][index_low:index_high]), facecolor=colors[u], edgecolor='None') patches = [mpatches.Patch(color='green', alpha=0.5, label='usage_manual')] for i in range(0,len(self.usage_names)): patches.append(mpatches.Patch(color=colors[i], label=self.usage_names[i])) plt.legend(bbox_to_anchor=(0., 1.0, 1., .102), loc=3, ncol=5, mode="expand", borderaxespad=0., handles=patches) self.ax1.set_xlim(self.dataMgr.low_Xlimit(),self.dataMgr.high_Xlimit()) def onselectAdd(self, xmin, xmax): minIdx = max(0, round(xmin*500)) maxIdx = min(self.dataMgr.file_length-1, round(xmax*500)) if self.show_debug_msg: print("ADD: xmin: {} | xmax: {}".format(xmin, xmax)) print("ADD: minIdx: {} | maxIdx: {}".format(minIdx, maxIdx)) self.usage_manual[minIdx:maxIdx] = 1 self.plotUsages() self.fig.canvas.draw() def onselectDel(self, xmin, xmax): minIdx = max(0, round(xmin*500)) maxIdx = min(self.dataMgr.file_length-1, round(xmax*500)) if self.show_debug_msg: print("DEL: xmin: {} | xmax: {}".format(xmin, xmax)) print("DEL: minIdx: {} | maxIdx: {}".format(minIdx, maxIdx)) self.usage_manual[minIdx:maxIdx] = 0 self.plotUsages() self.fig.canvas.draw() def onselectZoom(self, xmin, xmax): if self.show_debug_msg: print("ZOOM: xmin: {} | xmax: {}".format(xmin, xmax)) self.plotUsages() self.ax1.set_xlim(xmin,xmax) self.fig.canvas.draw() def on_key_event(self, event): if self.show_debug_msg: print('you pressed %s'%event.key) if event.key == 'a': self._prev() elif event.key == 'd': self._next() elif event.key == 'w': self._add() elif event.key == 's': self._del() elif event.key == 'q': self._zoom_in() elif event.key == 'e': self._zoom_out() elif event.key == 'r': self._save() elif event.key == 'f': self._autosave() elif event.key == 'x': self._prevJump() elif event.key == 'c': self._nextJump() elif event.key == 'left': self._prev() elif event.key == 'right': self._next() elif event.key == 'up': self._add() elif event.key == 'down': self._del() def on_button_event(self, event): if self.show_debug_msg: print('you clicked %s'%event.button) if event.button == 3: #right mouse button self._zoom_out() elif event.button == 2: #middle mouse button (scroll wheel) self._zoom_in() def _quit(self): self.root.quit() # stops mainloop self.root.destroy() # this is necessary on Windows to prevent # Fatal Python Error: PyEval_RestoreThread: NULL tstate def _prev(self): if self.show_debug_msg: print('_prev()') if self.dataMgr.current_page > 1: self.loadPage(self.dataMgr.current_page-1) def _next(self): if self.show_debug_msg: print('next()') if self.dataMgr.current_page < self.dataMgr.num_pages: self.loadPage(self.dataMgr.current_page+1) def _prevJump(self): if self.show_debug_msg: print('_prevJump()') if self.dataMgr.current_page > 1: for p in reversed(self.jump_positions): num = self.dataMgr.getPageNumByX(p) if num < self.dataMgr.current_page: self.loadPage(num) break def _nextJump(self): if self.show_debug_msg: print('nextJump()') if self.dataMgr.current_page < self.dataMgr.num_pages: for p in self.jump_positions: num = self.dataMgr.getPageNumByX(p) if num > self.dataMgr.current_page: self.loadPage(num) break def loadPage(self, page_num): if self.autosave_period > -1 and page_num % self.autosave_period == 0: if self.show_debug_msg: print('autosaving on page {}'.format(page_num)) self._autosave() self.dataMgr.current_page = min(max(1, page_num), self.dataMgr.num_pages) if self.show_debug_msg: print('loadPage(): {}'.format(self.dataMgr.current_page)) self.plotPage() self.progress_label["text"] ="Page {}/{}".format(self.dataMgr.current_page, self.dataMgr.num_pages) def _add(self): if self.show_debug_msg: print('_add()') if float(matplotlib.__version__[0:3])>=1.4: self.multi_cursor.disconnect() self.multi_cursor = MultiCursor(self.fig.canvas, (self.ax1, self.ax2, self.ax3, self.ax4), useblit=True, horizOn=False, vertOn=True, color='g', lw=1) self.span1.disconnect_events() self.span2.disconnect_events() self.span3.disconnect_events() self.span4.disconnect_events() self.span1 = SpanSelector(self.ax1, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) self.span2 = SpanSelector(self.ax2, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) self.span3 = SpanSelector(self.ax3, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) self.span4 = SpanSelector(self.ax4, self.onselectAdd, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='green') ) self.mode_label['text'] = 'Mode: ADD' self.mode_label['bg'] = 'green' self.fig.canvas.draw() def _del(self): if self.show_debug_msg: print('_del()') if float(matplotlib.__version__[0:3])>=1.4: self.multi_cursor.disconnect() self.multi_cursor = MultiCursor(self.fig.canvas, (self.ax1, self.ax2, self.ax3, self.ax4), useblit=True, horizOn=False, vertOn=True, color='r', lw=1) self.span1.disconnect_events() self.span1.disconnect_events() self.span2.disconnect_events() self.span3.disconnect_events() self.span4.disconnect_events() self.span1 = SpanSelector(self.ax1, self.onselectDel, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red') ) self.span2 = SpanSelector(self.ax2, self.onselectDel, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red') ) self.span3 = SpanSelector(self.ax3, self.onselectDel, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red') ) self.span4 = SpanSelector(self.ax4, self.onselectDel, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red') ) self.mode_label['text'] = 'Mode: DEL' self.mode_label['bg'] = 'red' self.fig.canvas.draw() def _zoom_in(self): if self.show_debug_msg: print('_zoom_in()') if float(matplotlib.__version__[0:3])>=1.4: self.multi_cursor.disconnect() self.multi_cursor = MultiCursor(self.fig.canvas, (self.ax1, self.ax2, self.ax3, self.ax4), useblit=True, horizOn=False, vertOn=True, color='b', lw=1) self.span1.disconnect_events() self.span1.disconnect_events() self.span2.disconnect_events() self.span3.disconnect_events() self.span4.disconnect_events() self.span1 = SpanSelector(self.ax1, self.onselectZoom, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='blue') ) self.span2 = SpanSelector(self.ax2, self.onselectZoom, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='blue') ) self.span3 = SpanSelector(self.ax3, self.onselectZoom, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='blue') ) self.span4 = SpanSelector(self.ax4, self.onselectZoom, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='blue') ) self.mode_label['text'] = 'Mode: ZOOM' self.mode_label['bg'] = 'blue' self.fig.canvas.draw() def _zoom_out(self): if self.show_debug_msg: print('_zoom_out()') self.plotUsages() self.fig.canvas.draw() def _save(self): if self.show_debug_msg: print('_save()') savetxt = plt.text(20, 20, 'saving...', fontsize=46, color='r', weight='bold', ha='center', va='top') self.fig.canvas.draw() self.dataMgr.writeCSV(self.csv_out_file, self.usage_manual) savetxt.remove() self.fig.canvas.draw() if os.path.isfile(self.autosave_file): archive_filename = self.autosave_file.rsplit(".", 1)[0] + "_old.pkl" print('renaming autosave file from "{}" to "{}"'.format(self.autosave_file, archive_filename)) if os.path.isfile(archive_filename): os.unlink(archive_filename) os.rename(self.autosave_file, archive_filename) def _autosave(self): if self.show_debug_msg: print('_autosave()') savetxt = plt.text(20, 20, 'autosaving...', fontsize=46, color='r', weight='bold', ha='center', va='top') self.fig.canvas.draw() self.dataMgr.writeAutoSave(self.autosave_file, self.usage_manual) savetxt.remove() self.fig.canvas.draw()
class DisplayWindow(object): global CdMeOTPRef, MeOTPRef color_list = deque(['b','g','r','c','m','y','k']) current_checker = None def __init__(self, master,ax = None): self.rootref = master self.master = Toplevel() self.checker_frame=Tkinter.Frame(master = self.master)#,yscrollcommand=self.scroll.set) #self.scroll.config(command=self.checker_frame.yview) self.frame = Frame(master = self.master) self.Plot = Figure(figsize=(6,3)) self.channel_list = [] self.array_list = [] self.Plot.a = self.Plot.add_subplot(111) self.Plot.a.set_xlabel('Raman Shift (cm$^{-1}$)') self.Plot.a.set_ylabel('Intensity (a.u.)') self.Plot.a.legend([]) self.Plot.a.get_legend().set_visible(False) self.checker_list = self.Plot.a.lines self.legend_var = IntVar() self.legend_var.set(1) self.legendbox = Checkbutton(self.frame, variable=self.legend_var, command=self.update_legend,text='Legend') # self.legend_label=Label(self.master, bd=1, anchor=W) # self.legend_label.config(text = "Legend") self.statusbar = Label(self.master, bd=1, relief=SUNKEN, anchor=W) self.statusbar.config(text = "Ready") self.canvas = FigureCanvasTkAgg(self.Plot,master = self.frame) self.canvas.show() self.master.protocol("WM_DELETE_WINDOW", self.quitproc) self.master.title(string = "RamanViewer") #self.scroll = Tkinter.Scrollbar(self.frame) #self.scroll.pack(side = Tkinter.RIGHT, fill = Tkinter.BOTH) self.checker_frame=Tkinter.Frame(master = self.master)#,yscrollcommand=self.scroll.set) #self.scroll.config(command=self.checker_frame.yview) self.menubar = Menu(self.master) self.filemenu = Menu(self.menubar, tearoff=0) self.filemenu.add_command(label="New window", command = lambda: DisplayWindow(self.rootref)) self.filemenu.add_command(label="Open", command = self.DisplaySpectrum) self.filemenu.add_command(label="Save",command = self.SaveSpectrum) self.filemenu.add_command(label="SaveFig",command = self.SaveFigure) self.filemenu.add_command(label="ViewNotebook",command = self.ViewNotebook) self.filemenu.add_command(label="Exit", command = self.quitproc) self.menubar.add_cascade(label="File", menu=self.filemenu) # create more pulldown menus self.editmenu = Menu(self.menubar, tearoff=0) self.editmenu.add_command(label="Smooth", command = self.SmoothSpectrum) self.filemenu.add_command(label="Fitting window", command = lambda:FittingWindow(Toplevel(),ramanspectrum=self.current_checker.spectrum))#, kwargs = {'ramanspectrum':self.current_checker.channel.spec_array}) self.editmenu.add_command(label="Calc Noise", command = self.start_calc_noise) self.editmenu.add_command(label="Calc Area", command = self.start_calc_area) self.editmenu.add_command(label="Basline", command = self.start_autobaseline) self.editmenu.add_command(label="disconnect", command = self.disconnect) self.editmenu.add_command(label='Quick Scan',command = self.open_next_spectrum_in_folder) self.editmenu.add_command(label='Normalize All',command = self.normalizeall) self.editmenu.add_command(label='Zero All',command = self.zeroall) self.editmenu.add_command(label = 'FFT process', command=self.FFT) self.editmenu.add_command(label = 'Remove noise', command = self.removenoise) self.editmenu.add_command(label="Copy") self.editmenu.add_command(label="Paste") self.menubar.add_cascade(label="Edit", menu=self.editmenu) self.correctionmenu = Menu(self.menubar,tearoff=0) self.correctionmenu.add_command(label='SPID633', command = self.SPIDcorrect633) self.correctionmenu.add_command(label='SPID785', command = self.SPIDcorrect785) self.menubar.add_cascade(label = 'Corrections', menu = self.correctionmenu) self.notesmenu =Menu(self.menubar, tearoff=0) self.notesmenu.add_command(label = "Notes", command = self.ViewNotebook) self.notesmenu.add_command(label = "Spectrum Info", command = self.showinfo) self.menubar.add_cascade(label = 'Info', menu = self.notesmenu) self.refsmenu =Menu(self.menubar, tearoff=0) self.refsmenu.add_command(label = "chloroform", command = None) self.refsmenu.add_command(label = "CdMeOTP", command = lambda:self.AddChannel(CdMeOTPRef)) self.refsmenu.add_command(label = "MeOTP", command = lambda:self.AddChannel(MeOTPRef)) self.refsmenu.add_command(label = "ClTP", command = lambda:self.AddChannel(ClTPRef)) self.refsmenu.add_command(label = "BrTP", command = lambda:self.AddChannel(BrTPRef)) self.refsmenu.add_command(label = "FTP", command = lambda:self.AddChannel(FTPRef)) self.refsmenu.add_command(label = "MethylTP", command = lambda:self.AddChannel(MethylTPRef)) self.refsmenu.add_command(label = "CdODPA", command = lambda:self.AddChannel(CdODPARef)) self.refsmenu.add_command(label = "toluene", command = lambda:self.AddChannel(tolueneRef)) self.refsmenu.add_command(label = "CdMethylTP", command = lambda:self.AddChannel(CdMethylTPRef)) self.menubar.add_cascade(label = 'References', menu = self.refsmenu) self.master.config(menu= self.menubar) self.left_click_menu = Menu(self.frame, tearoff=0) self.left_click_menu.add_command(label="open", command = self.DisplaySpectrum) # self.left_click_menu.add_command(label="blue", command=lambda:self.change_color('b')) # self.left_click_menu.add_command(label="black", command=lambda:self.change_color('k')) # self.left_click_menu.add_command(label="yellow", command=lambda:self.change_color('y')) # self.canvas._tkcanvas.bind("<Button-3>", self.popup) self.frame.pack(side = TOP, expand=1, fill=BOTH)#(row = 0, column = 0, padx = 25, pady = 25) self.legendbox.pack(side=BOTTOM) self.statusbar.pack(side = BOTTOM,expand=1,fill=X) self.checker_frame.pack(side=BOTTOM,expand = 1,fill=X)#(row=1,column=0) self.canvas._tkcanvas.pack( expand = 1, fill = BOTH) self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.frame) self.toolbar.update() self.toolbar.pack(side= BOTTOM,expand =True) self.canvas.draw() list_of_display_windows.append(self) if ax is not None: for line in ax.lines: self.Plot.a.add_line(checker(self,line,color = line.get_color())) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] plt.close(ax.get_figure()) return None def popup(self,event): print event.x_root, event.y_root self.left_click_menu.post(event.x_root, event.y_root) def update_legend(self): if self.legend_var.get() == 0: self.Plot.a.get_legend().set_visible(False) else: l = list() for entry in self.checker_list: if True:#entry.get_visible(): l.append(entry.commentbox.get()) self.Plot.a.legend(l) self.Plot.canvas.draw() return 0 def showinfo(self): tkMessageBox.showinfo('Spectrum info',self.current_checker.spectrum.info) return 0 def getcolor(self): self.color_list.rotate(1) return self.color_list[0] def DisplaySpectrum(self): import re options = {} #options['defaultextension'] = '.SPE' options['filetypes'] = [('all files','.*'),('SPE','.spe'),('txt', '.txt'),('csv','.csv')] options['multiple'] = True options['title'] = 'Open Spectrum...' options['parent'] = self.master str_name_list = tkFileDialog.askopenfilenames(**options) if type(str_name_list) == tuple: for name in str_name_list: if 'notes' in name: SFG_Notebook.SFG_NotebookWindow(target_file = name) elif name =='': continue else: newspectrum = RamanSpectrum(name) self.Plot.a.add_line(checker(self,newspectrum,color = self.getcolor())) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] elif str_name_list == '': return 0 elif type(str_name_list) == list: for name in re.split(' ',str_name_list): newspectrum = RamanSpectrum(name) self.Plot.a.add_line(checker(self,newspectrum,color = self.getcolor())) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] return 0 def SaveSpectrum(self): file_opt = options = {} options['defaultextension'] = '.txt' options['filetypes'] = [('all files', '.*')] options['title'] = 'Open Spectrum...' options['initialfile'] = os.path.basename(self.current_checker.name) options['parent'] = self.master if self.current_checker == None: return 0 str_filename = tkFileDialog.asksaveasfilename(**options) if str_filename == '': return 0 else: data = transpose([self.current_checker.get_xdata(),self.current_checker.get_ydata()]) savetxt(str_filename,data,delimiter = ',',comments = '#'+str(self.current_checker.spectrum.info))#SaveSpectrum(self.current_checker.channel.spec_array,str_filename) os.chdir(os.path.dirname(str_filename)) return 0 def ViewNotebook(self): print os.path.dirname(self.current_checker.name) try: SFG_Notebook.SFG_NotebookWindow(target_dir = os.path.dirname(self.current_checker.name)) except IOError: tkSimpleDialog.Message('no file found') return 0 def zeroall(self): for c in self.Plot.a.lines: c.set_ydata(c.get_ydata()-min(c.get_ydata())) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() return 0 def SmoothSpectrum(self): if self.current_checker == None: return 0 newspectrum = smooth(self.current_checker.spectrum) self.Plot.a.add_line(checker(self,newspectrum,color = self.getcolor(),operations = 'sp = smooth(sp)\n')) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] return 0 def SPIDcorrect785(self): if self.current_checker == None: return 0 else: newspectrum = SPIDcorrect785(self.current_checker.spectrum) self.Plot.a.add_line(checker(self,newspectrum,color = self.getcolor(),operations = 'sp = SPIDcorrect785(sp)\n')) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] return 0 def SPIDcorrect633(self): if self.current_checker == None: return 0 else: newspectrum = SPIDcorrect633(self.current_checker.spectrum) self.Plot.a.add_line(checker(self,newspectrum,color = self.getcolor(),operations = 'sp = SPIDcorrect633(sp)\n')) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] return 0 def open_next_spectrum_in_folder(self): self.Plot.canvas.mpl_connect('key_press_event',self.open_next_spectrum) for c in self.checker_list[1:]: self.RemoveSpectrum(self.checker) self.checker_list[0].set_current(0) return 0 def open_next_spectrum(self,event): directory_index = os.listdir(os.path.dirname(os.path.abspath(self.current_checker.channel.spec_array.name))) for x in directory_index: if 'txt' not in x: directory_index.remove(x) directory_index.sort() i=directory_index.index(os.path.basename(self.current_checker.channel.spec_array.name)) if i>len(directory_index)-2: i=-1 if 'txt' not in directory_index[1+1]: i+=1 if event.key == 'right': i+=1 elif event.key == 'left': i-=1 try: newspectrum = RamanSpectrum(directory_index[i]) except: print 'error' print 'i=',i return -1 self.RemoveSpectrum(self.current_checker) self.AddChannel(self.newspectrum) self.checker_list[0].set_current(0) return 0 def normalizeall(self): for check in self.checker_list: data = check.get_ydata() data[:]-=min(data) data/=max(data) check.set_ydata(data) self.Plot.a.relim() self.Plot.a.set_ylim(-0.5,1.5) self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() return 0 def start_calc_noise(self): self.span = SpanSelector(self.Plot.a, self.calc_noise, 'horizontal') self.span.connect_event('pick_event',self.calc_noise) gcf().canvas.mpl_connect('button_press_event',self.disconnect) return 0 def start_calc_area(self): self.span = SpanSelector(self.Plot.a, self.calc_area, 'horizontal') self.span.connect_event('pick_event',self.calc_area) gcf().canvas.mpl_connect('button_press_event',self.disconnect) return 0 def start_autobaseline(self): # self.toolbar.release(None) self.span = SpanSelector(self.Plot.a, self.autobaseline, 'horizontal') self.span.connect_event('pick_event',self.autobaseline) gcf().canvas.mpl_connect('button_press_event',self.disconnect) return 0 def autobaseline(self,start,end): order = int(tkSimpleDialog.askinteger('Fit order', 'Choose the polynomial order.')) if order == None: return 0 if self.current_checker == None: return 0 newspectrum = autobaseline(self.current_checker.spectrum,(start,end),order = order) self.Plot.a.add_line(checker(self,newspectrum,color = self.getcolor(),operations = 'sp = autobaseline(sp), ('+str(start)+','+str(end)+'), order ='+str(order)+')\n')) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] self.span.disconnect_events() return 0 def calc_noise(self,start,end): try: print "STD =", calc_noise(pandas.Series(self.current_checker.channel.get_ydata(),self.current_checker.channel.get_xdata()),(start,end)) except: print 'error' return 0 def calc_area(self, start,end): try: print "Area =", calc_area(pandas.Series(self.current_checker.channel.get_ydata(),self.current_checker.channel.get_xdata()),(start,end)) except: print 'error' return 0 def disconnect(self): #print event.button#gcf().canvas.mpl_disconnect(self.cid) self.span.disconnect_events() return 0 def removenoise(self): newspectrum = removecorrelatednoise(self.current_checker.spectrum) self.Plot.a.add_line(checker(self,newspectrum,operations = 'sp = removecorrelatednoise(sp)',color=self.getcolor())) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] return None def AddChannel(self,spectrum): self.Plot.a.add_line(checker(self,spectrum)) self.Plot.a.lines[-1].set_color(self.getcolor()) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.Plot.canvas.draw() self.current_checker = self.Plot.a.lines[-1] return 0 def RemoveSpectrum(self,checker): self.Plot.a.lines.remove(checker) self.Plot.a.relim() self.Plot.a.autoscale_view(tight = False) self.canvas.draw() checker.frame.pack_forget() return 0 def SaveFigure(self): os.chdir('/home/chris/Desktop') self.Plot.savefig('figure.png') f = open('/home/chris/Desktop/figure.py','wb') for line in self.Plot.a.lines: f.write(line.operations) f.close() return 0 def FFT(self): return 0 def quitproc(self): self.master.destroy() list_of_display_windows.remove(self) if len(list_of_display_windows)==0: self.rootref.destroy() return 0
class LSFQDialg(QWidget): def __init__(self): QWidget.__init__(self) self.handles = [] self.create_canvas() self.segments = [] vbox = QVBoxLayout() vbox.addWidget(self.canvas) self.setLayout(vbox) self.resize(800, 600) self.move(320, 75) self.setWindowTitle("Least Square Fitting (2D)") def create_canvas(self): self.fig = plt.figure() self.canvas = FigureCanvas(self.fig) self.axes = plt.subplot(111) self.axes.set_xlabel("Scans") self.axes.set_ylabel("Instensity") self.axes.set_title("Least Square Fitting(2D)", fontsize=9) self.axes.tick_params(axis='both', labelsize=8) plt.subplots_adjust(bottom=0.22, top=0.90, left=0.08, right=0.9) self.span = SpanSelector(self.axes, self.span_select_callback, 'horizontal', minspan=0.002, useblit=True, rectprops=dict(alpha=0.5, facecolor='red'), onmove_callback=None, button=[1]) axspan = plt.axes([0.09, 0.04, 0.08, 0.075]) axundo = plt.axes([0.2, 0.04, 0.08, 0.075]) axstar = plt.axes([0.31, 0.04, 0.08, 0.075]) self.btnspan = Button(axspan, 'span') self.btnundo = Button(axundo, 'undo') self.btnstar = Button(axstar, 'start') self.btnspan.on_clicked(self.span_mode) self.btnundo.on_clicked(self.undo_mode) self.btnstar.on_clicked(self.star_mode) self.span.set_active(True) self.redraw() ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] def redraw(self): self.canvas.draw() self.update() def span_mode(self, event): self.span.connect_event('motion_notify_event', self.span.onmove) self.span.connect_event('button_press_event', self.span.press) self.span.connect_event('button_release_event', self.span.release) self.span.connect_event('draw_event', self.span.update_background) self.leftdblclick = False self.rightdblclick = False self.redraw() print "span" def undo_mode(self, event): self.span.disconnect_events() if len(self.segments) >= 1: del self.axes.collections[:] self.segments = self.segments[:-1] self.select_inter(self.segments) self.redraw() print "undo" def star_mode(self, event): if len(self.segments) == 0: msgBox = QMessageBox() msgBox.setText("No selected noise region") msgBox.exec_() else: fit, bas = self.backremv(self.segments) self.show_bas(bas) self.show_fit(fit) self.emit(SIGNAL('after_baseline'), fit) def show_bas(self, bas): self.axes.plot(np.sum(bas, axis=1), lw=2, c='k', alpha=.7, picker=5) def show_fit(self, fit): self.axes.plot(np.sum(fit, axis=1), lw=2, c='r', alpha=.7, picker=5) def show_org(self, x): self.axes.plot(np.sum(x, axis=0), lw=2, c='b', alpha=.7, picker=5) def span_select_callback(self, xmin, xmax): cc = np.arange(0, self.x.shape[0]) indmin, indmax = np.searchsorted(cc, (xmin, xmax)) indmax = min(len(self.x) - 1, indmax) self.segments.append((indmin, indmax)) self.axes.vlines(xmin, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(xmax, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.redraw() def updata_data(self, x): self.xx = x self.axes.clear() self.axes.set_xlabel("Scans") self.axes.set_ylabel("Instensity") self.axes.set_title("Least Square Fitting(2D)", fontsize=9) self.x = x['d'] self.y = np.sum(self.x, axis=1) self.axes.plot(self.y, lw=1, c='b', alpha=.7, picker=5) diff_y = max(self.y) - min(self.y) self.axes.set_xlim(0, len(self.y)) self.axes.set_ylim(0, max(self.y) * 1.1) ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] self.plotorg = True self.redraw() def select_inter(self, segments): for i in range(0, len(segments)): indmin, indmax = segments[i] self.axes.vlines(self.x[indmin], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(self.x[indmax], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') def backremv(self, seg): mn = np.shape(self.x) bak2 = np.zeros(mn) for i in range(0, mn[1]): tiab = [] reg = [] for j in range(0, len(seg)): tt = range(seg[j][0], seg[j][1]) tiab.extend(self.x[tt, i]) reg.extend(np.arange(seg[j][0], seg[j][1])) rm = reg - np.mean(reg) tm = tiab - np.mean(tiab) b = np.dot(np.dot(float(1) / np.dot(rm.T, rm), rm.T), tm) s = np.mean(tiab) - np.dot(np.mean(reg), b) b_est = s + b * np.arange(mn[0]) bak2[:, i] = self.x[:, i] - b_est bak = self.x - bak2 self.yy = bak2 return bak2, bak def accept(self): self.xx['d'] = self.yy self.close()
class TICPlot(QWidget): def __init__(self): QWidget.__init__(self) self.handles = [] self.ncr = dict() self.fileno = 0 self.segments = [] self.create_canvas() def create_canvas(self): self.fig = plt.figure() self.canvas = FigureCanvas(self.fig) self.axes = plt.subplot(111) self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.axes.tick_params(axis='both', labelsize=8) plt.subplots_adjust(bottom=0.25, top=0.90, left=0.08, right=0.9) self.zoom = RectangleSelector(self.axes, self.rectangle_select_callback, drawtype='box', useblit=True, button=[1], minspanx=5, minspany=5, spancoords='pixels') self.span = SpanSelector(self.axes, self.span_select_callback, 'horizontal', minspan=0.002, useblit=True, rectprops=dict(alpha=0.5, facecolor='red'), onmove_callback=None, button=[1]) axbasic = plt.axes([0.59, 0.04, 0.08, 0.075]) axPan = plt.axes([0.7, 0.04, 0.08, 0.075]) axPick = plt.axes([0.81, 0.04, 0.08, 0.075]) self.btnBasic = Button(axbasic, 'Zoom') self.btnPan = Button(axPan, 'Span') self.btnPick = Button(axPick, 'Undo') axtic = plt.axes([0.92, 0.825, 0.06, 0.075]) axext = plt.axes([0.92, 0.725, 0.06, 0.075]) axres = plt.axes([0.92, 0.625, 0.06, 0.075]) self.TICbutton = Button(axtic, 'TIC') self.EXTbutton = Button(axext, 'EXT') self.RESbutton = Button(axres, 'RES') vbox = QVBoxLayout() vbox.addWidget(self.canvas) self.setLayout(vbox) self.btnBasic.on_clicked(self.zoom_mode) self.btnPan.on_clicked(self.span_mode) self.btnPick.on_clicked(self.undo_mode) self.TICbutton.on_clicked(self.slot_tic) self.EXTbutton.on_clicked(self.slot_ext) self.RESbutton.on_clicked(self.slot_res) self.zoom_mode(True) self.redraw() ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] def slot_tic(self, event): self.add_tic(self.ncr, self.fileno) def slot_ext(self, event): self.emit(SIGNAL("ext_plot")) def slot_res(self, event): self.emit(SIGNAL("res_plot"), ) def add_tic(self, ncr, fn): if not len(self.segments): self.fn = fn self.ncr = ncr tic = self.ncr.tic() self.x = tic['rt'] self.y = tic['val'] self.axes.clear() self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.axes.set_title(str(fn), fontsize=9) self.axes.plot(self.x, self.y, lw=1, c='b', alpha=.7, picker=5) self.axes.set_xlim(min(self.x), max(self.x)) self.axes.set_ylim(min(self.y), max(self.y) * 1.1) ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)] self.redraw() # def add_ext(self): def clear_data(self): self.axes.clear() self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.redraw() def redraw(self): self.canvas.draw() self.update() def zoom_mode(self, event): self.zoom.set_active(True) self.span.set_active(False) self.cidPress = self.canvas.mpl_connect('button_press_event', self.mouse_press_callback) self.cidRelease = self.canvas.mpl_connect('button_release_event', self.mouse_release_callback) self.span.disconnect_events() self.leftdblclick = False self.rightdblclick = False self.redraw() print "zoom" def span_mode(self, event): self.zoom.set_active(False) self.span.set_active(True) self.span.connect_event('motion_notify_event', self.span.onmove) self.span.connect_event('button_press_event', self.span.press) self.span.connect_event('button_release_event', self.span.release) self.span.connect_event('draw_event', self.span.update_background) # self.span.connect_event('button_press_event', self.mouse_press_callback) self.rightdblclick = False self.leftdblclick = False self.rightdblclick = False self.redraw() print "span" def undo_mode(self, event): self.zoom.set_active(True) self.span.disconnect_events() self.cidPress = self.canvas.mpl_connect('button_press_event', self.mouse_press_callback) if len(self.segments) >= 1: self.emit(SIGNAL("delete_SELECT"), self.segments[-1]) del self.axes.collections[:] self.segments = self.segments[:-1] self.select_inter(self.segments) if self.ind_right_press != 0: self.axes.vlines(self.xdata, self.oxy[1][0], self.oxy[1][1], color='g', linestyles='-') self.redraw() print "undo" def mouse_press_callback(self, event): if (event.button == 1 and event.dblclick == True): self.leftdblclick = True if event.button == 3: self.xdata = event.xdata self.ind_right_press = np.searchsorted(self.x, event.xdata) del self.axes.collections[:] self.axes.vlines(event.xdata, self.oxy[1][0], self.oxy[1][1], color='g', linestyles='-') self.select_inter(self.segments) self.redraw() self.emit(SIGNAL("MASS_SELECT"), self.ncr, self.ind_right_press) def select_inter(self, segments): for i in range(0, len(segments)): indmin, indmax = segments[i] self.axes.vlines(self.x[indmin], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(self.x[indmax], self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') def mouse_release_callback(self, event): if (self.leftdblclick): self.leftdblclick = False self.axes.set_xlim(self.oxy[0]) self.axes.set_ylim(self.oxy[1]) self.redraw() if (self.rightdblclick): self.rightdblclick = False del self.axes.collections[:] self.redraw() def rectangle_select_callback(self, eclick, erelease): x1, y1 = eclick.xdata, eclick.ydata x2, y2 = erelease.xdata, erelease.ydata if eclick.button == 1 and erelease.button == 1: self.axes.set_xlim(min(x1, x2), max(x1, x2)) self.axes.set_ylim(min(y1, y2), max(y1, y2)) self.redraw() def span_select_callback(self, xmin, xmax): indmin, indmax = np.searchsorted(self.x, (xmin, xmax)) indmax = min(len(self.x) - 1, indmax) self.segments.append((indmin, indmax)) self.axes.vlines(xmin, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.axes.vlines(xmax, self.oxy[1][0], self.oxy[1][1], color='r', linestyles='--') self.redraw() self.emit(SIGNAL("range_SELECT"), self.ncr, (indmin, indmax)) def loading(self): self.axes.clear() self.axes.set_xlabel("Retention Time") self.axes.set_ylabel("Instensity") self.redraw() self.zoom_mode(True) ymino, ymaxo = self.axes.get_ylim() xmino, xmaxo = self.axes.get_xlim() self.oxy = [(xmino, xmaxo), (ymino, ymaxo)]