class GraphPlotter(tk.Frame): def __init__(self, master): super().__init__(master) self.grid(row=0, column=1, sticky='nsew') self.load_plotters() self.setup_canvas() self.rowconfigure(0, weight=1) self.columnconfigure(0, weight=1) def setup_canvas(self): self.figure = matplotlib.figure.Figure(figsize=(5, 5), dpi=100) self.canvas = FigureCanvasTkAgg(self.figure, self) self.draw_plot(None) self.canvas.get_tk_widget().grid(column=0, row=0, sticky='nsew') def load_plotters(self): import data_browser.plotting_modules self.plotters = {module.FILE_EXTENSION: module.DEFAULT_PLOTTER for module in data_browser.plotting_modules.__all__} def draw_plot(self, file): self.figure.clf() if file is None or os.path.isdir(file): plot_dir(file, self.figure) elif os.path.splitext(file)[1] in self.plotters: try: self.plotters[os.path.splitext(file)[1]](file, self.figure) except Exception as e: plot_error(e, self.figure) else: plot_error(ValueError('cannot plot {}'.format(file)), self.figure) self.canvas.draw_idle()
class NetIncomeGraph: def __init__(self): self.canvas = None self.fig = Figure(figsize=(12, 5), dpi=80) def plot_net_income(self, container, ticker_symbol, Frequency): ticker_object = ticker.get_ticker( ticker_symbol ) ## Gets the ticker object so you can access the various objects income_statements_data_drame = income.get_income_statement( ticker_object, Frequency) income_statement = income.get_net_income(income_statements_data_drame) company_name = priceData.get_company_name(ticker_object, ticker_symbol) dates = date.get_dates(income_statements_data_drame) income_statement_title = 'Net income' ax = self.fig.add_subplot(111) yLabelText = "Net Income in $" graph_title = company_name + " " + income_statement_title ax.set_title(graph_title) ax.set_xlabel('Period') ax.set_ylabel(yLabelText) ax.get_yaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) ax.bar(dates, income_statement, color=['r' if v < 0 else 'g' for v in income_statement]) for i, v in enumerate(income_statement): ax.text(i, v * 0.75, f'${v:,.0f}', fontweight='bold', va='center', ha='center', color='#0A0A0A') legend_handles = [ Line2D([0], [0], linewidth=0, marker='o', markerfacecolor=color, markersize=12, markeredgecolor='none') for color in ['g', 'r'] ] ax.legend(legend_handles, ['positive net income', 'negative net income']) if not self.canvas: self.canvas = FigureCanvasTkAgg(self.fig, container) self.canvas.get_tk_widget().pack(side="top", fill="both", expand=True) self.canvas.draw_idle() def clearPlotPage(self): self.fig.clear() # clear your figure self.canvas.draw_idle() # redraw your canvas so it becomes empty
class Fund(BaseFrame): def __init__(self, parent=None): super().__init__(parent) # 设置光标样式 # self.config(cursor='sb_h_double_arrow') self.make_widgets() self.handle = EventHandler(self.fig, self.canvas, self.ax) self.handle.connect() def make_widgets(self): self.fig, self.ax = plt.subplots() self.ax.yaxis.grid(linestyle="-.", color='silver') self.canvas = FigureCanvasTkAgg(self.fig, self) # self.draw() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=tk.YES) def display(self, data): self.ax.cla() # self.ax.clear() # 根据回测日期选择显示的时间格式fmt # temp = [f['Time'] for f in data["Fund"]] x = [pd.Timestamp(int2date(f['Time'])) for f in data['Fund']] y = [f['DynamicEquity'] for f in data['Fund']] self.ax.set_xlim(0, len(y) - 1) self.handle.set_border() self.handle.set_x_labels(x) if data['KLineType'] == EEQU_KLINE_DAY: fmt = mdate.DateFormatter('%Y-%m') elif data['KLineType'] == EEQU_KLINE_MINUTE: fmt = mdate.DateFormatter('%Y-%m-%d') else: # 有待更改 fmt = mdate.DateFormatter('%Y-%m-%d') self.ax.plot(y, marker='.', color='red', linewidth=2.0, linestyle='-') self.ax.set_xticklabels(x) def format_date(x_, pos=None): if x_ < 0 or x_ > len(x) - 1: return return x[int(x_)] #TODO: length先暂时这样处理吧! length = 0 if len(x) > 0 and len(x) <= 100: length = 30 elif len(x) > 100 and len(x) <= 1000: length = 200 elif len(x) > 1000 and len(x) < 10000: length = 2000 else: length = 20000 self.ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) self.ax.xaxis.set_major_locator(ticker.MultipleLocator(length)) # 此处使用self.canvas.draw()会使程序崩溃 self.canvas.draw_idle()
class StatisticBarGUI(BaseFrame): @staticmethod def default_gui_config(): default_config = BaseFrame.default_gui_config() default_config.figure = {'figsize': (6, 5), 'dpi': 100} default_config.legend = {'loc': 'upper right'} default_config.statistics = ad.Config() return default_config def __init__(self, master=None, gui_config=None, **kwargs): super().__init__(master=master, gui_config=gui_config, **kwargs) self.create_gui() def create_gui(self): # make the treeview in the frame resizable self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.figure = plt.Figure(**self.gui_config['figure']) self.ax = self.figure.add_subplot(111) self.legend = None self.figure_canvas = FigureCanvasTkAgg(self.figure, master=self) self.figure_canvas.get_tk_widget().grid(sticky=tk.NSEW) self.master.update_idletasks() def display_exploration_data(self, exploration_data, run_id): self.display_data(exploration_data.runs[run_id].statistics) def display_data(self, statistics): if not isinstance(statistics, collections.abc.Sequence): self.statistics = [statistics] else: self.statistics = statistics self.ax.clear() stat_names = [] for stat_config_idx in range(len(self.gui_config.statistics)): stat_config = self.gui_config.statistics[stat_config_idx] stat_name = stat_config['name'] disp_name = stat_config.get('disp_name', stat_name) stats_idx = stat_config.get('stats_idx', 0) stat_data = self.statistics[stats_idx][stat_name] stat_names.append(disp_name) self.ax.bar(stat_config_idx, stat_data, align='center') self.ax.set_xticks(range(len(stat_names))) self.ax.set_xticklabels(stat_names) self.figure_canvas.draw_idle()
class CashBasedEarningGraph: def __init__(self): self.canvas = None self.fig = Figure(figsize=(12, 5), dpi=80) def plotCashToEarnings(self, container, ticker_symbol, frequency): ticker_object = ticker.get_ticker( ticker_symbol ) # Gets the ticker object so you can access the various objects income_statements_data_frame = income.get_income_statement( ticker_object, frequency) net_income = income.get_net_income(income_statements_data_frame) cash_flow_data_frame = cash_flow_page.get_cash_flow_data( ticker_object, frequency) operating_cash_flow = cash_flow_page.get_operating_cash_flow( cash_flow_data_frame) company_name = price_data.get_company_name(ticker_object, ticker_symbol) all_dates = dates.get_dates(cash_flow_data_frame) if operating_cash_flow.iloc[-1] > net_income.iloc[-1]: print(f'{company_name} has high quality earnings') else: print(f'{company_name} has low quality earnings') title = 'Cash Based Earnings' ax = self.fig.add_subplot(111) yLabelText = "Amount in $" graph_title = company_name + " " + title ax.set_title(graph_title) ax.set_xlabel('Period') ax.set_ylabel(yLabelText) ax.get_yaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) ax.plot(all_dates, operating_cash_flow, '-o', label='Cash From Operations') ax.plot(all_dates, net_income, '-o', label='Net Income') ax.legend() if not self.canvas: self.canvas = FigureCanvasTkAgg(self.fig, container) self.canvas.get_tk_widget().pack(side="top", fill="both", expand=True) self.canvas.draw_idle() def clearPlotPage(self): self.fig.clear() # clear your figure self.canvas.draw_idle() # redraw your canvas so it becomes empty
class PieChartView(tk.Frame): canvas = None controller = None def __init__(self, parent, controller): tk.Frame.__init__(self, parent) self.controller = controller label = tk.Label(self, text="Pie chart", font=LARGE_FONT) label.pack(pady=10, padx=10) labels = 'Positive', 'Neutral', 'Negative' amount = [pos, neut, neg] print(amount) colors = ['green', 'lightskyblue', 'red'] explode = (0, 0.05, 0) # proportion with which to offset each # wedge entry1 = ttk.Entry(self) entry1.pack() button3 = ttk.Button(self, text="Start stream ", command=lambda: controller.start_stream( entry1.get())) button3.pack() piechart.pie(amount, # data explode=explode, # offset parameters labels=labels, # slice labels colors=colors, # array of colours autopct='%1.1f%%', # print the values inside the wedges shadow=True, # enable shadow startangle=70 # starting angle ) piechart.axis('equal') button1 = ttk.Button(self, text="Back to Home", command=lambda: self.stop()) button1.pack() self.canvas = FigureCanvasTkAgg(figure2, self) self.canvas.draw() self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True) ''' Roept de stop functie aan op de controller, en gaat terug naar de startpagina ''' def stop(self): self.controller.show_frame(WelcomePage) self.controller.controller.stop_stream() ''' Zorgt ervoor dat de pie chart de nieuwe waarden gebruikt ''' def update(self): piechart.clear() piechart.pie([pos, neut, neg]) self.canvas.draw_idle()
class Graph(Frame): """ Graph class that creates a linegraph and updates every 40 seconds Source: https://pythonprogramming.net/how-to-embed-matplotlib-graph-tkinter-gui/ """ def __init__(self, parent=None, shutter=None): super().__init__(parent) self.config(bg="ghost white") self.shutter = shutter f = Figure(figsize=(6, 6), dpi=100, facecolor='#f8f8ff') self.ax = f.add_subplot(111) # Sets for the plot self.timeset = [] self.valueset = [] self.ax.clear() self.ax.set_ylabel("Temperatuur in °C") self.ax.plot(self.timeset, self.valueset) # The graph magic self.canvas = FigureCanvasTkAgg(f, self) self.canvas.draw() self.canvas.get_tk_widget().pack(side="bottom", fill="both", expand=True) # Start 40 second update loop self.update_graph() def update_graph(self): # Append new value to plots self.timeset.append(datetime.now().strftime('%H:%M:%S')) self.valueset.append(self.shutter.get_temp()) # If there is more than 5 time entries, remove the oldest value if len(self.timeset) > 5: self.timeset.remove(self.timeset[0]) self.valueset.remove(self.valueset[0]) # Redraw the graph self.ax.clear() self.ax.set_title("Temperatuur over de tijd") self.ax.set_ylabel("Temperatuur in °C") self.ax.set_xticklabels(self.timeset, rotation='45') self.ax.plot(self.timeset, self.valueset) self.canvas.draw_idle() self.after(40000, self.update_graph)
def get_frame_for_figure(master, figure_function): frame = tk.Frame(master) fig = plt.figure(figsize=plt.figaspect(0.6)) canvas = FigureCanvasTkAgg(fig, frame) figure_function(fig=fig) canvas.draw_idle() canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) toolbar = NavigationToolbar2Tk(canvas, frame) toolbar.update() fig.savefig = ExperimentPlot.save_figure(fig.savefig.__func__, fig, frame) canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) frame.pack(fill=tk.BOTH, expand=True) return frame
def ecualizar(): global imageLoad global estilo global actual actual = "ecualizada" imageLoad = equalize(imageLoad) fig = plt.figure() ax = fig.add_subplot(111) ax.axis('off') ax.imshow(imageLoad, cmap=estilo) canvas = FigureCanvasTkAgg(fig, ventana) canvas.get_tk_widget().grid(row=5, column=0, columnspan=3) canvas.draw_idle()
class DebtGraph: def __init__(self): self.canvas = None self.fig = Figure(figsize=(12, 5), dpi=80) def plot_debt_graph(self, container, ticker_symbol, frequency): ticker_object = ticker.get_ticker( ticker_symbol ) ## Gets the ticker object so you can access the various objects balance_sheet_data_frame = balancesheet.get_balance_sheet_data( ticker_object, frequency) long_term_debt = balancesheet.get_long_term_debt( balance_sheet_data_frame) company_name = price_data.get_company_name(ticker_object, ticker_symbol) dates = date.get_dates(balance_sheet_data_frame) graph_title = 'Long Term Debt' ax = self.fig.add_subplot(111) yLabelText = "Long term Debt $" graph_title = company_name + " " + graph_title ax.set_title(graph_title) ax.set_xlabel('Period') ax.set_ylabel(yLabelText) ax.get_yaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) ax.bar(dates, long_term_debt, color='r') for i, v in enumerate(long_term_debt): ax.text(i, v * 0.75, f'${v:,.0f}', fontweight='bold', va='center', ha='center') if not self.canvas: self.canvas = FigureCanvasTkAgg(self.fig, container) self.canvas.get_tk_widget().pack(side="top", fill="both", expand=True) self.canvas.draw_idle() def clearPlotPage(self): self.fig.clear() # clear your figure self.canvas.draw_idle() # redraw your canvas so it becomes empty
def conv(): global imageLoad global filtro global estilo global actual global output output = convolucion(imageLoad, filtro) actual = "conv" fig = plt.figure() ax = fig.add_subplot(111) ax.axis('off') ax.imshow(output, cmap=estilo) canvas = FigureCanvasTkAgg(fig, ventana) canvas.get_tk_widget().grid(row=5, column=0, columnspan=3) canvas.draw_idle()
class PlottingCanvas(): def __init__(self,master,fig, grid_pos): container = ttk.LabelFrame(master, text='플로터') container.grid(row=grid_pos[0], column=grid_pos[1], rowspan=2) self.canvas = FigureCanvasTkAgg(fig, master=container) self.canvas.get_tk_widget().grid(row=0, column=0) def update(self): self.canvas.draw_idle() def cbind(self, id, func): self.canvas.mpl_connect(id, func) def __del__(self): print('PlottingCanvas has been deleted')
def textoCaja(textoEntrada): global imageLoad global estilo global actual actual = "original" imageLoad = cv2.imread(str(textoEntrada.get())) if len(imageLoad.shape) == 3: imageLoad = cv2.cvtColor(imageLoad, cv2.COLOR_BGR2GRAY) fig = plt.figure() ax = fig.add_subplot(111) ax.axis('off') ax.imshow(imageLoad, cmap=estilo) canvas = FigureCanvasTkAgg(fig, ventana) canvas.get_tk_widget().grid(row=5, column=0, columnspan=3) canvas.draw_idle()
def cambiarEstilo(style): global estilo global actual global output estilo = style if (actual == "original"): textoCaja(textoEntrada) elif (actual == "ecualizada"): ecualizar() elif (actual == "conv"): fig = plt.figure() ax = fig.add_subplot(111) ax.axis('off') ax.imshow(output, cmap=estilo) canvas = FigureCanvasTkAgg(fig, ventana) canvas.get_tk_widget().grid(row=5, column=0, columnspan=3) canvas.draw_idle()
class RevenueGraph: def __init__(self): self.canvas = None self.fig = Figure(figsize=(12, 5), dpi=80) def plot_revenue(self, container, ticker_symbol, frequency): ticker_object = ticker.get_ticker( ticker_symbol ) # Gets the ticker object so you can access the various objects earnings_data = earning.get_earnings_data(ticker_object) company_name = price_data.get_company_name(ticker_object, ticker_symbol) data = self.get_freqency(earnings_data, ticker_symbol, frequency) earnings_data_frame = pd.DataFrame(data) dates = earnings_data_frame['date'].astype(str) revenue = earnings_data_frame['revenue'] revenue = revenue / 100 # This scales the earnings value to Millions or Billions depends on how you want to read the chart ax = self.fig.add_subplot(111) yLabelText = "Amount in $" graph_title = company_name + " " + 'Revenue' ax.set_title(graph_title) ax.set_xlabel('Period') ax.set_ylabel(yLabelText) ax.get_yaxis().set_major_formatter( matplotlib.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) ax.bar(dates, revenue, color=['r' if v < 0 else 'g' for v in revenue]) ## adding color to bar graphs for i, v in enumerate(revenue): ax.text(i, v * 0.75, f'${v:,.0f}', fontweight='bold', va='center', ha='center') ## printing values into the bar graphs legend_handles = [ Line2D([0], [0], linewidth=0, marker='o', markerfacecolor=color, markersize=12, markeredgecolor='none') for color in ['g', 'r'] ] ax.legend(legend_handles, ['positive revenue', 'negative revenue']) # ax.legend() if not self.canvas: self.canvas = FigureCanvasTkAgg(self.fig, container) self.canvas.get_tk_widget().pack(side="top", fill="both", expand=True) self.canvas.draw_idle() def get_freqency(self, earnings_data, ticker_symbol, frequency): if frequency == 'yearly': yearly_finaincal_earnings = earnings_data[ticker_symbol][ 'financialsChart'][frequency] return yearly_finaincal_earnings else: quarterly_finaincal_earnings = earnings_data[ticker_symbol][ 'financialsChart'][frequency] return quarterly_finaincal_earnings def clear_plot(self): self.fig.clear() # clear your figure self.canvas.draw_idle() # redraw your canvas so it becomes empty
class Aplicacion: ANCHO_CANVAS = 200 ALTO_CANVAS = 200 NUM_FILAS = 10 NUM_COLUMNAS = 10 ANCHO_CURSOR = ANCHO_CANVAS // NUM_COLUMNAS ALTO_CURSOR = ALTO_CANVAS // NUM_FILAS TEMPERATURA = 1 PRESION = 2 HUMEDAD = 3 PERIODO_INICIAL = 1000 def __init__(self): self.sense = SenseHat() self.midiendo = True # Mediciones activas self.data_points = list() # Puntos para la gráfica self.queue = queue.Queue() # Para comunicacion con hebra worker self.cuadrados = dict( ) # Para ahorrar recursos GUI guardamos los cuadrados self.list_max = [105, 1260, 100] # Temp, pres, hum self.periodo = self.PERIODO_INICIAL self.ventana1 = tk.Tk() self.ventana1.title("Práctica GUI SenseHat") self.agregar_menu() self.cuaderno1 = ttk.Notebook(self.ventana1) self.pagina1 = ttk.Frame(self.cuaderno1) self.cuaderno1.add(self.pagina1, text="Monitorización") self.pagina2 = ttk.Frame(self.cuaderno1) self.cuaderno1.add(self.pagina2, text="Gráfica") self.cuaderno1.grid(column=0, row=0) # Página 1 self.control() self.mediciones() self.canvas() self.historico() # Página 2 self.matplotlib() # Ya no utilizado. Controlando posición desde el emulador #self.ventana1.bind("<KeyPress>", self.presion_tecla) #self.ventana1.bind("<Button-1>", self.presion_raton) # Lento # while True: # self.medir() # self.ventana1.update() # time.sleep(1) self.ventana1.after(self.periodo, self.llamada_medir) self.ventana1.after(1000, self.comprobar_joystick) self.ventana1.mainloop() # Métodos para colocar controles en interfaz gráfica def agregar_menu(self): self.menubar1 = tk.Menu(self.ventana1) self.ventana1.config(menu=self.menubar1) self.opciones1 = tk.Menu(self.menubar1, tearoff=0) self.opciones1.add_command(label="Configurar periodo", command=self.configurar) self.opciones1.add_command(label="Ver Contribuidores", command=self.contribuidores) self.menubar1.add_cascade(label="Opciones", menu=self.opciones1) def mediciones(self): self.labelframe1 = ttk.LabelFrame(self.pagina1, text="Medidas") self.labelframe1.grid(column=0, row=1) self.seleccion_tipo_dato = tk.IntVar(value=self.TEMPERATURA) self.radio1 = tk.Radiobutton(self.labelframe1, text="Temperatura", variable=self.seleccion_tipo_dato, value=self.TEMPERATURA) self.radio1.grid(column=0, row=1, padx=4, pady=4) self.datoSense = tk.StringVar() self.entryTemp = ttk.Entry(self.labelframe1, textvariable=self.datoSense) self.entryTemp.grid(column=1, row=0, padx=4, pady=4) self.radio2 = tk.Radiobutton(self.labelframe1, text="Presión", variable=self.seleccion_tipo_dato, value=self.PRESION) self.radio2.grid(column=1, row=1, padx=4, pady=4) self.radio3 = tk.Radiobutton(self.labelframe1, text="Humedad", variable=self.seleccion_tipo_dato, value=self.HUMEDAD) self.radio3.grid(column=2, row=1, padx=4, pady=4) def canvas(self): self.canvas1 = tk.Canvas(self.pagina1, width=self.ANCHO_CANVAS, height=self.ALTO_CANVAS, background="black") self.canvas1.grid(column=1, row=0, rowspan=2) self.columna_cursor = 0 self.fila_cursor = 0 self.crear_cuadrado() def control(self): self.labelframe2 = ttk.LabelFrame(self.pagina1, text="Control") self.labelframe2.grid(column=0, row=0) self.boton_start_stop = ttk.Button(self.labelframe2, text="Parar", command=self.start_stop) self.boton_start_stop.pack(side=tk.TOP) self.label_periodo = ttk.Label(self.labelframe2, text="Periodo: ") self.label_periodo.pack(side=tk.LEFT, padx=4, pady=4) self.label_periodo2 = ttk.Label(self.labelframe2, text=str(self.periodo)) self.label_periodo2.pack(side=tk.RIGHT, padx=4, pady=4) def historico(self): self.labelframe3 = ttk.LabelFrame(self.pagina1, text="Histórico") self.labelframe3.grid(column=0, row=2, columnspan=2, sticky=tk.W + tk.E) self.frame2 = tk.Frame(self.labelframe3) self.frame2.pack(side=tk.TOP, fill=tk.BOTH, expand=True) #self.listbox1=tk.Listbox(self.frame2) #self.listbox1.pack(side = tk.LEFT, fill = tk.BOTH, expand=True) self.tree = ttk.Treeview(self.frame2) self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.scroll1 = tk.Scrollbar(self.frame2, orient=tk.VERTICAL) self.scroll1.configure(command=self.tree.yview) self.scroll1.pack(side=tk.RIGHT, fill=tk.Y) self.tree.config( yscrollcommand=self.scroll1.set) # 2 conexiones tree <-> scroll self.tree['columns'] = ('value', 'when', 'type') self.tree.heading('#0', text='#Num') self.tree.heading('value', text='Valor') self.tree.heading('when', text='Fecha/Hora') self.tree.heading('type', text='Tipo') self.seleccion = tk.IntVar() self.check1 = tk.Checkbutton(self.labelframe3, text="Añadir a lista", variable=self.seleccion) self.check1.pack(side=tk.BOTTOM) self.frame_historico = tk.Frame(self.labelframe3) self.frame_historico.pack(side=tk.BOTTOM) self.boton_limpiar = tk.Button(self.frame_historico, text="Limpiar", command=self.limpiar_historico) self.boton_limpiar.pack(side=tk.LEFT) self.boton_exportar = tk.Button(self.frame_historico, text="Exportar", command=self.exportar_historico) self.boton_exportar.pack(side=tk.RIGHT) self.boton3 = ttk.Button(self.frame_historico, text="Calcular Media", command=self.comenzar_calculo) self.boton3.pack(side=tk.RIGHT) def matplotlib(self): tk.Label(self.pagina2, text="Temperatura", bg='white').pack() self.fig = Figure() self.ax = self.fig.add_subplot( 111 ) # https://matplotlib.org/3.1.3/api/_as_gen/matplotlib.pyplot.subplot.html: nºfilas, nºcolumnas, índice subplotcd self.ax.set_xlabel("X axis") self.ax.set_ylabel("Y axis") self.ax.cla() # clear axis self.ax.grid() # configura grid self.ax.set_xlim(0, 9) self.ax.set_ylim(0, 100) self.line, = self.ax.plot([], [], marker='o', color='orange') self.graph = FigureCanvasTkAgg( self.fig, master=self.pagina2) # Agg: Anti-Grain geometry rendering engine self.graph.get_tk_widget().pack(side="top", fill='both', expand=True) self.ani = animation.FuncAnimation(self.fig, self.pinta_grafica, interval=1000, blit=False) self.graph.draw_idle() # para comenzar refresco grafica #self.ventana1.after(1000,self.pinta_grafica) def configurar(self): dialogo1 = DialogoPeriodo(self.ventana1) self.periodo = dialogo1.mostrar() self.label_periodo2.configure(text=str(self.periodo)) def contribuidores(self): dialogo1 = DialogoContribuidores(self.ventana1) dialogo1.mostrar() # Esta función utiliza las coordenadas actuales del cursor para crear el # cuadrado con marco rojo def crear_cuadrado(self): # Solo se crea una vez. No se "desperdician" recursos self.cuadrado = self.canvas1.create_rectangle( self.columna_cursor * self.ANCHO_CURSOR, self.fila_cursor * self.ALTO_CURSOR, (self.columna_cursor + 1) * self.ANCHO_CURSOR, (self.fila_cursor + 1) * self.ALTO_CURSOR, outline='red') # Métodos relacionados con mediciones periódicas def start_stop(self): if self.midiendo: self.midiendo = False self.boton_start_stop.configure(text='Comenzar') else: self.midiendo = True self.boton_start_stop.configure(text='Parar') def limpiar_historico(self): self.tree.delete( *self.tree.get_children()) # * "desempaqueta" argumento def get_datos_historico(self): l = list() for med in self.tree.get_children(): # {'text': '0', 'image': '', 'values': ['25.0', '2020-03-04 21:17:44', 'Temperatura'], 'open': 0, 'tags': ''} id = self.tree.item(med)['text'] values = self.tree.item(med)['values'] l.append(Medicion(id, values[0], values[1], values[2])) return l def exportar_historico(self): ldatos = self.get_datos_historico() filename = tk.filedialog.asksaveasfilename( initialdir=".", title="Select file", filetypes=(("text files", "*.txt"), ("all files", "*.*"))) worker_exportar.ExporterTask(filename, ldatos).start() # Bloquea interfaz si hay muchos datos #for l in ldatos: # print(l) def str_tipo_medicion(self, tipo_medicion): if tipo_medicion == self.TEMPERATURA: res = "Temperatura" elif tipo_medicion == self.PRESION: res = "Presión" else: res = "Humedad" return res # Esta operación crea un cuadrado relleno según la temperatura en la posición # actual del cursor. # Actualiza también el cuadro de texto con la temperatura # # TODO: Comprobar si llamadas continuas a create_rectangle agotan recursos def medir(self): if self.seleccion_tipo_dato.get() == self.TEMPERATURA: self.datoSense.set(str(self.sense.temp)) elif self.seleccion_tipo_dato.get() == self.PRESION: self.datoSense.set(str(self.sense.pressure)) else: self.datoSense.set(str(self.sense.humidity)) #print(self.datoSense.get()) #self.canvas1.itemconfig(self.cuadrado,fill='red') # Evitamos crear rectángulos indefinidamente clave = (self.fila_cursor, self.columna_cursor) if clave in self.cuadrados: cuadrado = self.cuadrados[clave] self.canvas1.itemconfig(cuadrado, fill=self.color( float(self.datoSense.get()), self.seleccion_tipo_dato.get())) else: self.cuadrados[clave] = self.canvas1.create_rectangle( self.columna_cursor * self.ANCHO_CURSOR, self.fila_cursor * self.ALTO_CURSOR, (self.columna_cursor + 1) * self.ANCHO_CURSOR, (self.fila_cursor + 1) * self.ALTO_CURSOR, fill=self.color(float(self.datoSense.get()), self.seleccion_tipo_dato.get())) self.canvas1.tag_raise( self.cuadrado) # Para que el cursor siempre esté en primer plano if self.seleccion.get() == 1: # self.listbox1.insert(0,self.datoSense.get()) now = datetime.datetime.now() self.tree.insert('', 0, text=str(len(self.tree.get_children())), values=(self.datoSense.get(), now.strftime("%Y-%m-%d %H:%M:%S"), self.str_tipo_medicion( self.seleccion_tipo_dato.get()))) # def presion_tecla(self, evento): # if evento.keysym=='Right': # self.columna_cursor=self.columna_cursor+1 # self.canvas1.move(self.cuadrado, self.ANCHO_CURSOR, 0) # if evento.keysym=='Left': # self.columna_cursor=self.columna_cursor-1 # self.canvas1.move(self.cuadrado, -self.ANCHO_CURSOR, 0) # if evento.keysym=='Down': # self.fila_cursor=self.fila_cursor+1 # self.canvas1.move(self.cuadrado, 0, self.ALTO_CURSOR) # if evento.keysym=='Up': # self.fila_cursor=self.fila_cursor-1 # self.canvas1.move(self.cuadrado, 0, -self.ALTO_CURSOR) # # TODO: deshabilitar cuando está en otra ventana # def presion_raton(self, evento): # nueva_fila=int(evento.y/self.ANCHO_CURSOR) # nueva_columna=int(evento.x/self.ALTO_CURSOR) # difc = nueva_columna-self.columna_cursor # diff = nueva_fila-self.fila_cursor # self.fila_cursor=nueva_fila # self.columna_cursor=nueva_columna # self.canvas1.move(self.cuadrado, difc*self.ANCHO_CURSOR, # diff*self.ALTO_CURSOR) def color(self, valor, tipo): if valor < 0.25 * self.list_max[tipo - 1]: return 'cyan' elif valor < 0.5 * self.list_max[tipo - 1]: return 'blue' elif valor < 0.75 * self.list_max[tipo - 1]: return 'yellow' else: return 'red' def pinta_grafica(self, i): # def pinta_grafica(self): #self.ventana1.after(1000,self.pinta_grafica) self.data_points.append(self.sense.temp) if len(self.data_points) > 10: del self.data_points[0] self.line.set_data(range(len(self.data_points)), self.data_points) self.ax.set_ylim(min(self.data_points) - 1, max(self.data_points) + 1) #self.graph.draw_idle() # para refrescar grafica def llamada_medir(self): self.ventana1.after(self.periodo, self.llamada_medir) if self.midiendo: self.medir() # Métodos relacionados con movimiento cursor def move_dot(self, event): #print(event) if event.action in ('pressed', 'held'): if event.direction == 'right': self.columna_cursor = self.columna_cursor + 1 self.canvas1.move(self.cuadrado, self.ANCHO_CURSOR, 0) if event.direction == 'left': self.columna_cursor = self.columna_cursor - 1 self.canvas1.move(self.cuadrado, -self.ANCHO_CURSOR, 0) if event.direction == 'down': self.fila_cursor = self.fila_cursor + 1 self.canvas1.move(self.cuadrado, 0, self.ALTO_CURSOR) if event.direction == 'up': self.fila_cursor = self.fila_cursor - 1 self.canvas1.move(self.cuadrado, 0, -self.ALTO_CURSOR) def comprobar_joystick(self): self.ventana1.after(1000, self.comprobar_joystick) for event in self.sense.stick.get_events(): self.move_dot(event) # Metodos relacionados con "tarea larga duración" def process_queue(self): try: msg = self.queue.get(0) tk.messagebox.showinfo("Media", msg) except queue.Empty: self.ventana1.after(1000, self.process_queue) def comenzar_calculo(self): ldatos = self.get_datos_historico() # Lista mediciones worker_media.ThreadedTask(self.queue, ldatos).start() self.ventana1.after(1000, self.process_queue)
class Cut: def __init__(self, nb, app): self.nb = nb self.app = app self.frame = ttk.Frame(self.nb) self.levelCut = 30 #self.frame2 = ttk.Frame(self.nb) self.nb.add(self.frame, text=' Cut ') self.lastGcodeFileName = "" r = 0 self.cutBtn = tk.Button(self.frame, text='Cut', width=25, command=self.cut, state='disabled') self.cutBtn.grid(column=0, row=r, padx=1, pady=(20, 1)) r += 1 self.cancelBtn = tk.Button(self.frame, text='Cancel', command=self.app.tGrbl.resetGrbl, width=25, state='disabled') self.cancelBtn.grid(column=0, columnspan=2, row=r, pady=(10, 1), sticky=W) r += 1 self.button2 = tk.Button(self.frame, text='Save Gcode', width=25, command=self.saveGcode) self.button2.grid(column=0, row=r, padx=1, pady=(20, 1)) r += 1 tk.Label(self.frame, text="Usual cutting speed (mm/sec)").grid(column=0, row=r, pady=(20, 1), sticky=W) EntryFloat(self.frame, self.app.vCut, 0.1, 10, self.levelCut, width='6').grid(column=1, row=r, padx=1, pady=(20, 1), sticky=W) r += 1 tk.Label(self.frame, text="Errors").grid(column=0, row=r, pady=(20, 1), padx=(10, 1), sticky=W) r += 1 tk.Label(self.frame, textvariable=self.app.cutMsg, height=10).grid(column=0, columnspan=2, row=r, pady=(1, 1), padx=(10, 1), sticky=NW) self.figRoot = Figure(figsize=(10, 3), dpi=100) self.axesRoot = self.figRoot.add_subplot(1, 1, 1) self.axesRoot.autoscale(enable=False) self.axesRoot.set_xlim(0, 1300) self.axesRoot.set_ybound(0, 400) self.axesRoot.set_title('Root') self.lineRoot1, = self.axesRoot.plot([], []) self.lineRoot2, = self.axesRoot.plot([], []) self.canvasRoot = FigureCanvasTkAgg( self.figRoot, master=self.frame) # A tk.DrawingArea. self.canvasRoot.draw() self.canvasRoot.get_tk_widget().grid(column=2, row=0, rowspan=20, padx=10, pady=(10, 2)) self.figTip = Figure(figsize=(10, 3), dpi=100) self.axesTip = self.figTip.add_subplot(1, 1, 1) self.axesTip.autoscale(enable=False) self.axesTip.set_xlim(0, 1300) self.axesTip.set_ybound(0, 400) self.axesTip.set_title('Tip') self.lineTip1, = self.axesTip.plot([], []) self.lineTip2, = self.axesTip.plot([], []) self.canvasTip = FigureCanvasTkAgg( self.figTip, master=self.frame) # A tk.DrawingArea. self.canvasTip.draw() self.canvasTip.get_tk_widget().grid(column=2, row=20, rowspan=20, padx=10, pady=(10, 2)) def updateOProfil( self): #update plotting the bloc (2 canvas: Top and Back) self.lineRoot1.set_xdata(self.oSimRX) self.lineRoot1.set_ydata(self.oSimRY) self.lineRoot2.set_xdata(self.app.pRootX) self.lineRoot2.set_ydata(self.app.pRootY) self.canvasRoot.draw_idle() self.lineTip1.set_xdata(self.oSimTX) self.lineTip1.set_ydata(self.oSimTY) self.lineTip2.set_xdata(self.app.pTipX) self.lineTip2.set_ydata(self.app.pTipY) self.canvasTip.draw_idle() def cut(self): self.app.tGrbl.stream(self.gcode) pass def saveGcode(self): gcodeFileName = filedialog.asksaveasfilename(title="Save as...", defaultextension="*.gcode",\ filetypes=[("Gcode files","*.gcode"),("All files", "*")], initialfile=self.lastGcodeFileName) if len(gcodeFileName) > 0: f = open(gcodeFileName, 'w') f.write(self.gcode) f.close() self.lastGcodeFileName = gcodeFileName def calculateRedraw(self): self.calculate() self.updateOProfil() def calculate(self): #it start from PRoot and pTip (= profile taking care of bloc and margin) #add enty and exit points in bloc #applies offset for radiance #simplifies the profiles if possible = simRoot and Tip #calculate the projection GX GY DX and DY #Vérifier la présence et l'égalité du nombre de points dans les 2 profils #to do control number of synchro points if (len(self.app.tRootX) > 0) and ( len(self.app.tTipX) > 0): # and (len(self.app.tRootX) == len(self.app.tTipX)): # create eRoot and eTip and add entry and exit point in the bloc (before applying heating offset) #print("pRootX pTipX", self.app.pRootX , self.app.pTipX) eRootX = self.app.pRootX.tolist() eRootY = self.app.pRootY.tolist() eRootS = list(self.app.pRootS) eTipX = self.app.pTipX.tolist() eTipY = self.app.pTipY.tolist() eTipS = list(self.app.pTipS) eRootX.insert(0, self.app.blocToTableTrailingRoot.get()) eRootY.insert(0, self.app.pRootY[0]) eTipX.insert(0, self.app.blocToTableTrailingTip.get()) eTipY.insert(0, self.app.pTipY[0]) eRootX.append(self.app.blocToTableTrailingRoot.get()) eRootY.append(self.app.pRootY[-1]) eTipX.append(self.app.blocToTableTrailingTip.get()) eTipY.append(self.app.pTipY[-1]) eRootS.insert(0, 10) # add a Synchro and no radiance point eTipS.insert(0, 10) # add a Synchro and no radiance point eRootS[ -1] = 10 # mark the last point as Synchro and no radiance point eTipS[ -1] = 10 # mark the last point as Synchro and no radiance point eRootS.append(4) #add a last point as Synchro eTipS.append(4) #add a last point as Synchro #print("Root=", list(zip(eRootX, eRootY, eRootS))) #build 2 listes with length of segments rootL = lengthSegment(eRootX, eRootY) tipL = lengthSegment(eTipX, eTipY) #build list of index of pt of synchro and length of sections between synchro eRootI, eRootL = lengthSection(eRootS, rootL) eTipI, eTipL = lengthSection(eTipS, tipL) #print("index and length of root", eRootS , rootL , eRootI , eRootL) #compare les longueurs pour trouver le coté le plus long compLength = compareLength(eRootL, eTipL) #print("compare length", compLength) #Calcule la radiance de chaque côté ; met 0 si rRoot, rTip = self.calculate2Radiance(compLength, self.app.vCut.get()) #print("radiance root, tip", rRoot , rTip) #create eRootR and eTipR with the radiance to fit the same nbr of item as exxxS eRootR = self.createRadiance(eRootS, rRoot) #print('full radiance root', eRootR) eTipR = self.createRadiance(eTipS, rTip) #print('full radiance tip', eTipR) # calculate offset on each side; create one new point at each synchronisation to take care of different radiance offsets self.offsetRootX, self.offsetRootY, self.offsetRootS = self.calculateOffset( eRootX, eRootY, eRootR, eRootS) #print("offset root", list(zip( self.offsetRootX , self.offsetRootY ,self.offsetRootS))) self.offsetTipX, self.offsetTipY, self.offsetTipS = self.calculateOffset( eTipX, eTipY, eTipR, eTipS) #print("len R T",len(self.offsetRootX) , len(self.offsetTipX) ) # adjust points in order to have the same number of points on each section self.syncRX, self.syncRY, self.syncTX, self.syncTY = self.synchrAllSections( self.offsetRootX, self.offsetRootY, self.offsetRootS, self.offsetTipX, self.offsetTipY, self.offsetTipS) """ print("eRoot X Y", eRootX, eRootY) print("eTip X Y", eTipX, eTipY) print("offset RX RY", self.offsetRootX , self.offsetRootY) print("offset TX TY", self.offsetTipX , self.offsetTipY) print("distance offset Rx Ry", self.printDistance(self.offsetRootX , self.offsetRootY)) print("distance offset Tx Ty", self.printDistance(self.offsetTipX , self.offsetTipY)) """ #Remove points if they are to close from each other (on both sides) #print("Offset ", self.offsetRootX , self.offsetRootY , self.offsetTipX , self.offsetTipY) self.oSimRX, self.oSimRY, self.oSimTX, self.oSimTY = self.simplifyProfiles( self.syncRX, self.syncRY, self.syncTX, self.syncTY) #print("len before after", len(self.syncRX), len(self.oSimRX)) #Calculate projections on cnc axis, messages, speed and feedRate (inverted) if self.app.leftRightWing.get( ) == 'Right': #for right wing, the root is on the left side self.GX, self.DX, self.GY, self.DY, self.warningMsg, self.speed, self.feedRate = self.projectionAll( self.oSimRX, self.oSimTX, self.oSimRY, self.oSimTY, self.app.blocToTableLeft.get() + self.app.tableYG.get(), self.app.blocLX.get(), self.app.tableYY.get() - self.app.blocToTableLeft.get() - self.app.tableYG.get() - self.app.blocLX.get()) else: #Left wing = root is on rigth side self.GX, self.DX, self.GY, self.DY, self.warningMsg, self.speed, self.feedRate = self.projectionAll( self.oSimTX, self.oSimRX, self.oSimTY, self.oSimRY, self.app.blocToTableLeft.get() + self.app.tableYG.get(), self.app.blocLX.get(), self.app.tableYY.get() - self.app.blocToTableLeft.get() - self.app.tableYG.get() - self.app.blocLX.get()) #print(self.warningMsg) self.app.cutMsg.set(self.warningMsg) #print("Projection ", self.GX , self.DX , self.GY, self.DY) #print("Projection ", self.GX , self.DX ) #genère le Gcode # set G54 à la valeur actuelle, set absolu et mm, set feed rate, met en chauffe, attend 5 sec # monte à la hauteur du ppremier point puis avance au premier point # passe tous les points # revient à la verticale de l'origine puis à l'origine # attend 5 sec puis éteint la chauffe puis éteint les moteurs self.gcode = self.generateGcode(self.GX, self.DX, self.GY, self.DY, self.speed, self.feedRate) def createRadiance(self, s, r): # create a radiance list with the same nbr of items as s and using the radiance in r imax = len(s) i = 0 rIdx = 0 rTemp = 0 result = [] while i < (imax - 1): if s[i] > 0: if s[i] > 4: rTemp = 0 else: rTemp = r[rIdx] rIdx += 1 result.append(rTemp) i += 1 return result def printDistance(self, x, y): imax = len(x) i = 0 result = [] while i < imax - 1: d1 = x[i + 1] - x[i] d2 = y[i + 1] - y[i] result.append(math.sqrt(d1 * d1 + d2 * d2)) i += 1 return result def generateGcode(self, GX, DX, GY, DY, axisSpeed, feedRate): #gCodeStart ="G10 L20 P1 X0 Y0 Z0 A0 \n G90 G21 M3 \n G04 P5.0\n G01 X0 \n" #gCodeEnd = "G04 P5.0\n M5\n M2\n" heat = self.app.tGuillotine.calculateHeating(self.app.vCut.get()) formatAxis = "{:.3f} " #A="X{:.3f} Y{:.3f} Z{:.3f} A{:.3f}\n" L = self.app.gCodeLetters.get() + "XYZA" # contains 4 letters G00 = "G00 " + L[0] + formatAxis + L[1] + formatAxis + L[ 2] + formatAxis + L[3] + formatAxis + "\n" G01 = "G01 " + L[0] + formatAxis + L[1] + formatAxis + L[ 2] + formatAxis + L[3] + formatAxis + "F{:d}\n" xyza = L[0] + formatAxis + L[1] + formatAxis + L[2] + formatAxis + L[ 3] + formatAxis + "\n" st = self.app.gCodeStart1.get() + "\n" + self.app.gCodeStart2.get( ) + "\n" + self.app.gCodeStart3.get( ) + "\n" + self.app.gCodeStart4.get() + "\n" st = st + "G10 L20 P1" + xyza.format( 0, 0, 0, 0) #set wcs to current position: G10 L20 P1 X0 Y0 Z0 A0 st = st + "G54\n" # apply wcs1 st = st + "S{:d}\n".format( int(heat)) # set the heating value based on speed st = st + "G90 G21 G93 M3\n" # apply Absolute and mm and inverted feedrate and heating st = st + "G04 P{:.1f}\n".format( self.app.tPreHeat.get()) # pause for the preheat delay en = "G04 P{:.1f}\n".format( self.app.tPostHeat.get()) # pause for the post delay en = en + "G94\nM5\nM2\n" # go back to normal feedrate , stop heating and stop motor en = en + self.app.gCodeEnd1.get() + "\n" + self.app.gCodeEnd2.get( ) + "\n" + self.app.gCodeEnd3.get() + "\n" + self.app.gCodeEnd4.get( ) + "\n" li = [] imax = len(GX) if imax > 1: i = 1 li.append(st) #append start li.append(G00.format(0.0, GY[0], 0.0, DY[0]), ) #move up li.append(G00.format(GX[0], GY[0], DX[0], DY[0]), ) #move up to entry of bloc while i < imax: li.append( G01.format(GX[i], GY[i], DX[i], DY[i], int( feedRate[i - 1]))) # we use inverted feedRate i += 1 li.append(G00.format(0, GY[-1], 0, DY[-1])) li.append(G00.format(0.0, 0.0, 0.0, 0.0)) li.append(en) #append End #print("".join(li)) #print the Gcode return "".join(li) # return a string containing the /n def projectionAll(self, x1, x2, y1, y2, lg, l, ld): # lg = outside length on the left side (from bloc to axis) # l = legnth between the 2 sides of bloc # ld = outside length on the right side (from bloc to axis) # x1 y1 = profil on the left side # x2 y2 = profil on the rigth side # return projection, warning msg and speed xg = [] xd = [] yg = [] yd = [] speed = [] # in mm/sec feedRate = [ ] # inverted feed rate for G93: e.g. 2 means that the movement has to be executed in 1/2 min xgmin = x1[0] xgmax = x1[0] xdmin = x2[0] xdmax = x2[0] ygmin = y1[0] ygmax = y1[0] ydmin = y2[0] ydmax = y2[0] vxGMax = 0 vyGMax = 0 vxDMax = 0 vyDMax = 0 msg = "" i = 0 imax = len(x1) if imax > 0: while i < imax: xg.append(((x1[i] - x2[i]) / l * lg) + x1[i]) xd.append(((x2[i] - x1[i]) / l * (l + ld)) + x1[i]) yg.append(((y1[i] - y2[i]) / l * lg) + y1[i]) yd.append(((y2[i] - y1[i]) / l * (l + ld)) + y1[i]) if xg[i] < xgmin: xgmin = xg[i] if xg[i] > xgmax: xgmax = xg[i] if xd[i] < xdmin: xdmin = xd[i] if xd[i] > xdmax: xdmax = xd[i] if yg[i] < ygmin: ygmin = yg[i] if yg[i] > ygmax: ygmax = yg[i] if yd[i] < ydmin: ydmin = yd[i] if yd[i] > ydmax: ydmax = yd[i] if i > 0: #calculate speed on Y axis #calculate legnth of segment dx1 = x1[i - 1] - x1[i] dy1 = y1[i - 1] - y1[i] dx2 = x2[i - 1] - x2[i] dy2 = y2[i - 1] - y2[i] dxG = abs(xg[i - 1] - xg[i]) dyG = abs(yg[i - 1] - yg[i]) dxD = abs(xd[i - 1] - xd[i]) dyD = abs(yd[i - 1] - yd[i]) d1 = dx1 * dx1 + dy1 * dy1 d2 = dx2 * dx2 + dy2 * dy2 dG = dxG * dxG + dyG * dyG dD = dxD * dxD + dyD * dyD #select the longest side if d1 >= d2: d1 = math.sqrt(d1) dG = math.sqrt(dG) d2 = math.sqrt(d2) dD = math.sqrt(dD) v1 = self.app.vCut.get() speed.append(v1 * dG / d1) feedRate.append(v1 / d1 * 60) vGD = v1 * dG / d1 vxG = v1 * dxG / d1 vyG = v1 * dyG / d1 vxD = v1 * dxD / d1 vyD = v1 * dyD / d1 else: d1 = math.sqrt(d1) dG = math.sqrt(dG) d2 = math.sqrt(d2) dD = math.sqrt(dD) v2 = self.app.vCut.get() speed.append(v2 * dD / d2) feedRate.append(v2 / d2 * 60) vGD = v2 * dD / d2 vxG = v2 * dxG / d2 vyG = v2 * dyG / d2 vxD = v2 * dxD / d2 vyD = v2 * dyD / d2 #print(" point {} dG={:.3f} d1={:.3f} dD={:.3f} d2={:.3f} vGD={:.3f} vxG={:.3f} vyG={:.3f} , vxD={:.3f} , vyD={:.3f} "\ # .format(i , dG , d1, dD , d2, vGD, vxG , vyG , vxD , vyD)) if vxG > vxGMax: vxGMax = vxG if vyG > vyGMax: vyGMax = vyG if vxD > vxDMax: vxDMax = vxD if vyD > vyDMax: vyDMax = vyD i += 1 if xgmin < 0: msg = msg + "Left hor. axis exceeds origin\n" if xgmax > self.app.cMaxY.get(): msg = msg + "Left hor. axis exceeds limit\n" if xdmin < 0: msg = msg + "Right hor. axis exceeds origin\n" if xdmax > self.app.cMaxY.get(): msg = msg + "Right vertical axis exceeds limit\n" if ygmin < 0: msg = msg + "Left vertical axis exceeds origin\n" if ygmax > self.app.cMaxZ.get(): msg = msg + "Left vertical axis exceeds limit\n" if ydmin < 0: msg = msg + "Right vertical axis exceeds origin\n" if ydmax > self.app.cMaxZ.get(): msg = msg + "Right vertical axis exceeds limit\n" if vxGMax > self.app.vMaxY.get(): msg = msg + "Left hor. axis exceeds speed {:.3f}\n".format( vxGMax) if vyGMax > self.app.vMaxZ.get(): msg = msg + "Left vertical axis exceeds speed\n" if vxDMax > self.app.vMaxY.get(): msg = msg + "Right hor. axis exceeds speed\n" if vyDMax > self.app.vMaxZ.get(): msg = msg + "Right vertical axis exceeds speed\n" return xg, xd, yg, yd, msg, speed, feedRate def simplifyProfiles(self, rX, rY, tX, tY): imax = len(rX) oRX = [] oRY = [] oTX = [] oTY = [] i = 0 if imax > 0: rXp = rX[i] rYp = rY[i] tXp = tX[i] tYp = tY[i] oRX.append(rXp) oRY.append(rYp) oTX.append(tXp) oTY.append(tYp) i = 1 while i < imax: dRX = rX[i] - rXp dRX *= dRX dRY = rY[i] - rYp dRY *= dRY dTX = tX[i] - tXp dTX *= dTX dTY = tY[i] - tYp dTY *= dTY if dRX > 0.01 or dRY > 0.01 or dTX > 0.01 or dTY > 0.01: rXp = rX[i] rYp = rY[i] tXp = tX[i] tYp = tY[i] oRX.append(rXp) oRY.append(rYp) oTX.append(tXp) oTY.append(tYp) i += 1 return oRX, oRY, oTX, oTY def calculateOffset(self, x, y, r, s): #create an offset for curve x y at a distance r (which varies) # for each synchronisation point, create 2 offset points instead of 1 #x ,y, r (radiance) , s (synchro) have the same length # return new x y s # pour 3 points successifs p1-p2-p3 avec r1-r2, calcule les pt d'intersection des 2 offsets ox = [] oy = [] os = [] imax = len(r) i = 0 if imax >= 1: #met le premier point oxi, oxj, oyi, oyj = offset1Segment(x[0], x[1], y[0], y[1], r[0]) ox.append(oxi) oy.append(oyi) os.append(s[0]) while i < (imax - 1): oxi, oyi = offset2Segment(x[i], x[i + 1], x[i + 2], y[i], y[i + 1], y[i + 2], r[i]) ox.append(oxi) oy.append(oyi) os.append(s[i + 1]) if s[i + 1] > 0: oxi, oyi = offset2Segment(x[i], x[i + 1], x[i + 2], y[i], y[i + 1], y[i + 2], r[i + 1]) ox.append(oxi) oy.append(oyi) os.append(s[i + 1]) i += 1 oxi, oxj, oyi, oyj = offset1Segment(x[i], x[i + 1], y[i], y[i + 1], r[i]) ox.append(oxj) oy.append(oyj) os.append(s[-1]) return ox, oy, os def calculate2Radiance(self, compLength, speedMax): oMin = self.radiance(speedMax) imax = len(compLength) rR = [] #radiance at root rT = [] #radiance at tip i = 0 if imax > 0: while i < imax: cLi = compLength[i] speedLow = speedMax * cLi if cLi >= 0: # root is longer rR.append(oMin) rT.append(self.radiance(speedLow)) else: rT.append(oMin) rR.append(self.radiance(-speedLow)) i += 1 return rR, rT def radiance(self, speed): a = (self.app.mRadSpHalf.get() - self.app.mRadSpHigh.get()) / ( self.app.mSpeedHalf.get() - self.app.mSpeedHigh.get()) return 0.5 * ( (a * (speed - self.app.mSpeedHalf.get())) + self.app.mRadSpHalf.get() ) # use only 1/2 of radiance for the offset """ synchronise 2 profiles extrait le premier tronçon R et T pour chaque tronçon calcule la longueur R et T calcule la longueur cumulée R et T Ramène les longueurs cumulées dans un range 0 <> 1 pour R et T Crée une liste qui mélange les 2 (concatene, trie, élimine les doublons) Fait un interpolate de R et de T suivant cette liste Simplifie en enlevant les points trop rapprochés des 2 cotés """ def synchrAllSections(self, rX, rY, rS, tX, tY, tS): #synchronise 2 profiles in order to get the same number of points #it has to respect synchronisation points sectionsIdxR = self.sectionsIdx(rS) sectionsIdxT = self.sectionsIdx(tS) #print("sectionIdxR", sectionsIdxR) #print("sectionIdxT", sectionsIdxT) imax = len(sectionsIdxR) i = 0 syncRX = [] syncRY = [] syncTX = [] syncTY = [] if imax > 0: while i < imax: firstR = sectionsIdxR[i][0] lastR = sectionsIdxR[i][1] + 1 firstT = sectionsIdxT[i][0] lastT = sectionsIdxT[i][1] + 1 #print( "first fast", firstR, lastR , firstT, lastT) #print("rX" , rX[firstR:lastR] ) sRX, sRY, sTX, sTY = self.synchroOneSection( rX[firstR:lastR], rY[firstR:lastR], tX[firstT:lastT], tY[firstT:lastT]) syncRX = syncRX + sRX.tolist() syncRY = syncRY + sRY.tolist() syncTX = syncTX + sTX.tolist() syncTY = syncTY + sTY.tolist() i += 1 return syncRX, syncRY, syncTX, syncTY def sectionsIdx(self, s): # return a list of turple with begin and end Idx of each section i = 0 imax = len(s) result = [] if imax > 1: while i < (imax - 1): j = i + 1 while s[j] == 0: j += 1 result.append((i, j)) i = j + 1 return result def synchroOneSection(self, rX, rY, tX, tY): """pour chaque tronçon calcule la longueur cumulée R et T Ramène les longueurs cumulées dans un range 0 <> 1 pour R et T Crée une liste qui mélange les 2 (concatene, trie, élimine les doublons) Fait un interpolate de R et de T suivant cette liste Simplifie en enlevant les points trop rapprochés des 2 cotés """ #print("synchro one section", rX , rY ,tX , tY) cumulLengthR = np.array(self.cumulLength(rX, rY)) cumulLengthT = np.array(self.cumulLength(tX, tY)) totLengthR = cumulLengthR[-1] totLengthT = cumulLengthT[-1] normLengthR = cumulLengthR / totLengthR normLengthT = cumulLengthT / totLengthT mergedLength = np.concatenate([normLengthR, normLengthT]) # concatenate mergedLength = np.unique(mergedLength) mergedLength = np.insert(mergedLength, 0, 0) #print("merged mergedLength=", mergedLength) mytck, myu = interpolate.splprep([rX, rY], k=1, s=0) rXnew, rYnew = interpolate.splev(mergedLength, mytck) mytck, myu = interpolate.splprep([tX, tY], k=1, s=0) tXnew, tYnew = interpolate.splev(mergedLength, mytck) #print("one section result" , rXnew , rYnew , tXnew , tYnew) return rXnew, rYnew, tXnew, tYnew def cumulLength(self, x, y): imax = len(x) i = 0 cL = [] cumLength = 0 if imax > 1: while i < (imax - 1): dx = x[i + 1] - x[i] dy = y[i + 1] - y[i] cumLength += math.sqrt(dx * dx + dy * dy) #calculate cumulative length cL.append(cumLength) i += 1 return cL
class View: def __init__(self, main_ui, show_ortho_track): self.main_ui = main_ui window = tk.Toplevel(self.main_ui.parent) self.window = window self.current_image = None self.rotation = 0 canvas_frame = tk.Frame(window) canvas_frame.pack(side="left", fill=tk.BOTH, expand=1) self.toolbox = tk.Frame(canvas_frame) self.toolbox.pack(side="left", expand=False, fill=tk.BOTH) self.is_latlon_source = tk.BooleanVar(value=False) if show_ortho_track: self.latlons = self.load_latlons() if self.latlons: button = tk.Checkbutton( self.toolbox, text="Overhead focus", var=self.is_latlon_source, command=self.trackToggle, ) button.pack(side="top") else: self.latlons = {} self.visible_tracks = None self.image_list = tk.StringVar() self.image_list_box = tk.Listbox( self.toolbox, font=FONT, width=12, selectmode="browse", listvariable=self.image_list, ) self.image_list_box.pack(side="bottom", expand=True, fill=tk.Y) self.image_list_box.bind("<<ListboxSelect>>", self.onclick_image_list) self.figure = Figure() self.ax = self.figure.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.figure, canvas_frame) self.canvas.get_tk_widget().pack(side="top", fill=tk.BOTH, expand=1) self.canvas.mpl_connect("button_press_event", lambda event: self.onclick_image(event)) self.canvas.mpl_connect("scroll_event", lambda event: self.on_scroll(event)) self.zoomed_in = False self.last_seen_px = {} self.plt_artists = [] def load_latlons(self): """Loads a latlon associated with each image key""" return self.image_manager.load_latlons() def trackToggle(self): if self.is_latlon_source.get(): self.main_ui.clear_latlon_sources(self) def onclick_image(self, event): x, y = event.xdata, event.ydata if None in (x, y) or self.current_image is None: return if event.button == 2: # Middle / wheel click: if self.zoomed_in: self.zoom_out() else: self.zoom_in(x, y) self.figure.canvas.draw_idle() elif event.button in (1, 3): # Left click or right click self.last_seen_px[self.main_ui.curr_point] = x, y if self.visible_tracks: self.auto_gcp_create(x, y, event.button == 1) elif self.main_ui.curr_point is not None: self.add_move_or_remove_gcp(x, y, event.button == 1) self.main_ui.populate_gcp_list() self.update_image_list_text() self.display_points() else: return def on_scroll(self, event): if event.xdata is None or event.ydata is None: return if event.button == "up": self.go_to_next_image() elif event.button == "down": self.go_to_prev_image() def onclick_image_list(self, event): widget = event.widget sel = widget.curselection() if not sel: return self.go_to_image_index(int(sel[0])) def add_move_or_remove_gcp(self, x, y, add): if self.main_ui.curr_point is None: return reproj = self.main_ui.gcp_manager.gcp_reprojections.get( self.main_ui.curr_point) if reproj: reproj.pop(self.current_image, None) self.main_ui.gcp_manager.remove_point_observation( self.main_ui.curr_point, self.current_image) if add: self.main_ui.gcp_manager.add_point_observation( self.main_ui.curr_point, self.current_image, self.pixel_to_gcp_coordinates(x, y), latlon=self.pixel_to_latlon(x, y), ) self.zoom_in(x, y) else: self.zoom_out() def zoom_in(self, x, y): if self.zoomed_in: return radius = self.zoom_window_size_px / 2 self.ax.set_xlim(x - radius, x + radius) self.ax.set_ylim(y + radius, y - radius) self.zoomed_in = True def zoom_out(self): self.ax.autoscale() self.zoomed_in = False def zoom_logic(self): point_has_been_seen = self.main_ui.curr_point in self.last_seen_px if self.main_ui.sticky_zoom.get() and point_has_been_seen: # Zoom in to the last seen location of this GCP x, y = self.last_seen_px[self.main_ui.curr_point] self.zoom_in(x, y) else: # Show the whole image self.ax.axis("scaled") self.figure.set_tight_layout(True) self.ax.axis("off") def point_in_view(self, point): if point is None: return None for projection in self.main_ui.gcp_manager.points[point]: if projection["shot_id"] == self.current_image: return self.gcp_to_pixel_coordinates(*projection["projection"]) return None def display_points(self): visible_points_coords = self.main_ui.gcp_manager.get_visible_points_coords( self.current_image) self.clear_artists() for point_id, coords in visible_points_coords.items(): color = distinct_colors[divmod(hash(point_id), 19)[1]] x, y = self.gcp_to_pixel_coordinates(*coords) artists = [ mpatches.Circle((x, y), 5, color=color, fill=False), ] if self.main_ui.show_gcp_names.get( ) or point_id == self.main_ui.curr_point: text = matplotlib.text.Annotation( point_id, (x, y), xytext=[0, 7], # fontsize=9, textcoords="offset points", ha="center", va="bottom", color=color, ) text.set_path_effects([ patheffects.Stroke(linewidth=3, foreground=comp_color(color)), patheffects.Normal(), ]) artists.append(text) if point_id == self.main_ui.curr_point: artists.extend([ mpatches.Circle((x, y), 0.5, color=color, fill=True), mpatches.Circle((x, y), 10, color=color, fill=False), mpatches.Circle((x, y), 11, color=color, fill=False), mpatches.Circle((x, y), 12, color=color, fill=False), ]) for art in artists: self.plt_artists.append(art) self.ax.add_artist(art) self.figure.canvas.draw() def clear_artists(self): for artist in self.plt_artists: artist.set_visible(False) del artist def populate_image_list(self): self.update_image_list_text() self.update_image_list_highlight() def update_image_list_text(self): items = [] self.images_in_list = self.get_candidate_images() n_digits = len(str(len(self.images_in_list))) for ix, image_name in enumerate(self.images_in_list): points = self.main_ui.gcp_manager.get_visible_points_coords( image_name) txt = "{:0{n_digits}} {}".format(ix + 1, len(points), n_digits=n_digits) shot_std = self.main_ui.shot_std.get(image_name, None) if shot_std: txt += " {:.2f}".format(shot_std) items.append(txt) self.image_list.set(items) def update_image_list_highlight(self): defaultbg = self.window.cget("bg") for ix, shot in enumerate(self.images_in_list): bg = "green" if shot == self.current_image else defaultbg self.image_list_box.itemconfig(ix, bg=bg) def bring_new_image(self, new_image, force=False): if new_image == self.current_image and not force: return self.current_image = new_image self.ax.clear() img = self.get_image(new_image) img = np.rot90(img, k=-self.rotation) self.ax.imshow(img) self.ax.axis("on") self.ax.axis("scaled") self.zoomed_in = False self.set_title() # Update 'last seen' coordinates for all gcps in this view for gcp_id in self.main_ui.gcp_manager.points: gcp_visible = self.point_in_view(gcp_id) if gcp_visible is not None: self.last_seen_px[gcp_id] = gcp_visible self.zoom_logic() self.update_image_list_highlight() self.display_points() if self.main_ui.curr_point: self.highlight_gcp_reprojection(self.main_ui.curr_point, zoom=False) latlon = self.latlons.get(new_image) if self.is_latlon_source.get() and latlon: self.main_ui.refocus_overhead_views(latlon["lat"], latlon["lon"]) def highlight_gcp_reprojection(self, point_id, zoom=True): if point_id not in self.main_ui.gcp_manager.gcp_reprojections: return shot = self.current_image x, y = None, None for obs in self.main_ui.gcp_manager.points[point_id]: if obs["shot_id"] == shot: x, y = obs["projection"] if x is None: return reproj = self.main_ui.gcp_manager.gcp_reprojections[point_id].get(shot) if not reproj: return x2, y2 = reproj["reprojection"] x, y = self.gcp_to_pixel_coordinates(x, y) x2, y2 = self.gcp_to_pixel_coordinates(x2, y2) artists = self.ax.plot([x, x2], [y, y2], "r-") self.plt_artists.extend(artists) if zoom: self.zoom_in(x, y) self.canvas.draw_idle() def rotate_point(self, x, y, h, w, reverse): if self.rotation == 0: return (x, y) elif self.rotation == 1: return (y, h - x) if reverse else (h - y, x) elif self.rotation == 2: return (w - x, h - y) elif self.rotation == 3: return (w - y, x) if reverse else (y, w - x) else: raise ValueError def gcp_to_pixel_coordinates(self, x: float, y: float) -> Tuple[float, float]: """ Transforms from normalized coordinates to pixels The view displays images at a reduced resolution for speed. We use the image manager to obtain the reduced coordinates to use for de-normalization. """ h, w = self.image_manager.get_image_size(self.current_image) px = features.denormalized_image_coordinates(np.array([[x, y]]), w, h)[0] return self.rotate_point(px[0], px[1], h, w, reverse=False) def pixel_to_gcp_coordinates(self, x: float, y: float) -> Tuple[float, float]: """ Transforms from pixels to normalized coordinates The view displays images at a reduced resolution for speed. We use the image manager to obtain the reduced coordinates to use for normalization. """ h, w = self.image_manager.get_image_size(self.current_image) point = self.rotate_point(x, y, h, w, reverse=True) coords = features.normalized_image_coordinates(np.array([point]), w, h)[0] return coords.tolist() def go_to_next_image(self): self.go_to_adjacent_image(+1) def go_to_prev_image(self): self.go_to_adjacent_image(-1) def go_to_adjacent_image(self, offset): if not self.images_in_list: return target_ix = self.images_in_list.index(self.current_image) + offset if 0 <= target_ix < len(self.images_in_list): self.go_to_image_index(target_ix) def go_to_image_index(self, idx): self.bring_new_image(self.images_in_list[idx])
class ViewWidget(object): """ Draws images using the datasets recorded in the HDF5 file. Also provides widgets to pick which dataset is displayed. """ def __init__(self, f, master): self.f = f self.mainframe = tk.Frame(master=master) self.lbutton = tk.Button(self.mainframe, text="<= Back", command=self.back) self.rbutton = tk.Button(self.mainframe, text="Next =>", command=self.forward) self.loclabel = tk.Label(self.mainframe, text='To start, enter values and click "compute"') self.infolabel = tk.Label(self.mainframe, text='Or, click the "suggest" button for interesting locations') self.fig = Figure(figsize=(5, 5), dpi=100) self.plot = self.fig.add_subplot(111) self.canvas = FigureCanvasTkAgg(self.fig, master=self.mainframe) self.canvas.draw_idle() self.loclabel.grid(row=0, column=1) self.infolabel.grid(row=1, column=1) self.lbutton.grid(row=2, column=0) self.canvas.get_tk_widget().grid(row=2, column=1) self.rbutton.grid(row=2, column=2) self.index = 0 self.jumptolast() def draw_fractal(self): """ Read a dataset from the HDF5 file and display it """ with file_lock: name = list(self.f.keys())[self.index] dset = self.f[name] arr = dset[...] start = dset.attrs['start'] extent = dset.attrs['extent'] self.loclabel["text"] = 'Displaying dataset "%s" (%d of %d)' % (dset.name, self.index+1, len(self.f)) self.infolabel["text"] = "%(shape)s pixels, starts at %(start)s, extent %(extent)s" % dset.attrs self.plot.clear() self.plot.imshow(arr.transpose(), cmap='jet', aspect='auto', origin='lower', extent=(start.real, (start.real+extent.real), start.imag, (start.imag+extent.imag))) self.canvas.draw_idle() def back(self): """ Go to the previous dataset (in ASCII order) """ if self.index == 0: print("Can't go back") return self.index -= 1 self.draw_fractal() def forward(self): """ Go to the next dataset (in ASCII order) """ if self.index == (len(self.f)-1): print("Can't go forward") return self.index += 1 self.draw_fractal() def jumptolast(self,*args): """ Jump to the last (ASCII order) dataset and display it """ with file_lock: if len(self.f) == 0: print("can't jump to last (no datasets)") return index = len(self.f)-1 self.index = index self.draw_fractal()
class Tool_GUI(): def __init__(self, root): # Definition for audio devices self.input_devices_list = [] self.output_devices_list = [] self.input_device_index = None self.output_device_index = None self.find_device() # Main Dialog Definition main_dialog = root main_dialog.title("Tool for ASR") main_dialog.geometry("900x650") main_dialog.resizable(False, False) self.window = tk.Frame(master=main_dialog, relief="solid", bd=2, height=630, width=880) self.window.place(x=10, y=10) # Font definition bc10i = tkFont.Font(family="bitstream charter", size=10, slant="italic") bc10b = tkFont.Font(family="bitstream charter", size=10, weight="bold") bc12b = tkFont.Font(family="bitstream charter", size=12, weight="bold") bc12i = tkFont.Font(family="bitstream charter", size=12, slant="italic") # Definition for File info Frame file_info_frame = tk.Frame(master=self.window, relief="solid", bd=1, height=100, width=500) file_info_frame.place(x=10, y=10) # Definition for Source directory lbl_src = tk.Label(master=file_info_frame, text="Source", fg="coral4", font=bc12b, anchor="w") lbl_src.place(x=10, y=15) self.btn_src_path_var = tk.StringVar() self.btn_src_path_var.set("Source directory") self.btn_src_path = tk.Button(master=file_info_frame, textvariable=self.btn_src_path_var, font=bc12i, fg="gray", width=40, bg='white', anchor="w", command=lambda: self.select_src_folder()) self.btn_src_path.place(x=115, y=10) # Definition for Destination directory lbl_dst = tk.Label(master=file_info_frame, text="Destination", fg="coral4", font=bc12b, anchor="w") lbl_dst.place(x=10, y=60) self.btn_dst_path_var = tk.StringVar() self.btn_dst_path_var.set("Destination directory") self.btn_dst_path = tk.Button(master=file_info_frame, textvariable=self.btn_dst_path_var, font=bc12i, fg="gray", width=40, bg='white', anchor="w", command=lambda: self.select_dst_folder()) self.btn_dst_path.place(x=115, y=55) # Definition for device settings frame dev_info_frame = tk.Frame(master=self.window, relief="solid", bd=1, height=190, width=345) dev_info_frame.place(x=520, y=10) # Combobox Definition for Sample Rate lbl_sample_rate = tk.Label(master=dev_info_frame, text="Sampling", fg="coral4", font=bc12b, anchor="w") lbl_sample_rate.place(x=10, y=15) self.cmb_sample_rate_var = tk.StringVar() self.cmb_sample_rate = ttk.Combobox(master=dev_info_frame, textvariable=self.cmb_sample_rate_var, state="readonly", values=[8000, 16000, 44100, 48000]) self.cmb_sample_rate.config(height=1, width=10, font=bc10i) self.cmb_sample_rate.place(x=100, y=18) self.cmb_sample_rate.current(1) print("default sample rate = ", self.cmb_sample_rate.get()) # Combobox Definition for Channel number lbl_channel = tk.Label(master=dev_info_frame, text="Channel", fg="coral4", font=bc12b, anchor="w") lbl_channel.place(x=10, y=60) self.cmb_channel_var = tk.StringVar() self.cmb_channel = ttk.Combobox(master=dev_info_frame, textvariable=self.cmb_channel_var, state="readonly", values=[1, 2]) self.cmb_channel.config(height=1, width=10, font=bc10i) self.cmb_channel.place(x=100, y=63) self.cmb_channel.current(0) print("default channel numbers = ", self.cmb_channel.get()) # Combobox Definition for Output device lbl_out_dev = tk.Label(master=dev_info_frame, text="Output", fg="coral4", font=bc12b, anchor="w") lbl_out_dev.place(x=10, y=105) # self.cmb_out_dev_var = tk.StringVar() self.cmb_out_dev = ttk.Combobox(master=dev_info_frame, state="readonly", values=[], postcommand=self.cmb_out_dev_update) self.cmb_out_dev.config(height=1, width=28, font=bc10i) self.cmb_out_dev.place(x=100, y=108) self.cmb_out_dev_update() self.cmb_out_dev_init() print("default output device = ", self.cmb_out_dev.get()) # Combobox Definition for Input device lbl_in_dev = tk.Label(master=dev_info_frame, text="Input", fg="coral4", font=bc12b, anchor="w") lbl_in_dev.place(x=10, y=150) self.cmb_in_dev_var = tk.StringVar() self.cmb_in_dev = ttk.Combobox(master=dev_info_frame, textvariable=self.cmb_in_dev_var, state="readonly", values=[], postcommand=self.cmb_in_dev_update) self.cmb_in_dev.config(height=1, width=28, font=bc10i) self.cmb_in_dev.place(x=100, y=153) self.cmb_in_dev_update() self.cmb_in_dev_init() print("default input device = ", self.cmb_in_dev.get()) # Definition for Progress Info Frame prog_info_frame = tk.Frame(master=self.window, relief="solid", bd=1, height=80, width=500) prog_info_frame.place(x=10, y=120) # Definition for Current working file entry lbl_curr = tk.Label(master=prog_info_frame, text="Current file", fg="coral4", font=bc12b, anchor="w") lbl_curr.place(x=10, y=15) self.ent_curr_file_var = tk.StringVar() self.ent_curr_file_var.set("Working file...") ent_curr_file = tk.Entry(master=prog_info_frame, textvariable=self.ent_curr_file_var, font=bc12i, fg="gray", width=30, bg="white") ent_curr_file.place(x=115, y=15) # Definition for Progress information lbl_prog = tk.Label(master=prog_info_frame, text="Progress", fg="coral4", font=bc12b, anchor="w") lbl_prog.place(x=10, y=45) self.prog_bar = ttk.Progressbar(master=prog_info_frame, orient=HORIZONTAL, length=370, mode="determinate") self.prog_bar.place(x=115, y=47) self.update_prog_bar(0) # Definition for Reference Waveform Frame self.frm_src_wave = tk.Canvas(master=self.window, relief="solid", bd=2, height=150, width=855, bg="white") self.frm_src_wave.place(x=10, y=210) lbl_ref = tk.Label(master=self.frm_src_wave, text="Reference", fg="gray", font=bc12i, anchor="w", bg="white") lbl_ref.place(x=10, y=10) # Draw blank wave box for source self.fig_src = Figure(figsize=(8.45, 1.43), dpi=100) self.fig_src.subplots_adjust(bottom=0.18, left=0.1) self.a1 = self.fig_src.add_subplot(111) self.a1.set_ylim([-32768, 32767]) self.a1.set_yticklabels([]) self.a1.set_xticklabels([]) self.a1.plot([]) self.canvas_src = FigureCanvasTkAgg(self.fig_src, master=self.frm_src_wave) self.canvas_src.get_tk_widget().place(x=10, y=10) self.canvas_src.draw_idle() # Definition for Recorded Waveform Frame self.frm_rec_wave = tk.Canvas(master=self.window, relief="solid", bd=2, height=150, width=855, bg="white") self.frm_rec_wave.place(x=10, y=370) lbl_rec = tk.Label(master=self.frm_rec_wave, text="Recorded", fg="gray", font=bc12i, anchor="w", bg="white") lbl_rec.place(x=10, y=10) # Draw blank wave box for recorded self.fig_rec = Figure(figsize=(8.45, 1.43), dpi=100) self.fig_rec.subplots_adjust(bottom=0.18, left=0.1) self.a2 = self.fig_rec.add_subplot(111) self.a2.set_ylim([-32768, 32767]) self.a2.set_yticklabels([]) self.a2.set_xticklabels([]) self.a2.plot([]) self.canvas_rec = FigureCanvasTkAgg(self.fig_rec, master=self.frm_rec_wave) self.canvas_rec.get_tk_widget().place(x=10, y=10) self.canvas_rec.draw_idle() # Definition for option checkbox frm_conv = tk.Frame(master=self.window, relief='solid', bd=1, height=70, width=400) frm_conv.place(x=10, y=540) self.play_checkVar = tk.IntVar() play_check = tk.Checkbutton(master=frm_conv, text="play & record", variable=self.play_checkVar, font=bc12i, command=lambda: self.play_check_chk()) play_check.place(x=15, y=20) self.play_checkVar.set(1) self.flac_checkVar = tk.IntVar() flac_check = tk.Checkbutton(master=frm_conv, text="flac to wav", variable=self.flac_checkVar, font=bc12i, command=lambda: self.flac_check_chk()) flac_check.place(x=150, y=20) self.mp3_checkVar = tk.IntVar() mp3_check = tk.Checkbutton(master=frm_conv, text="mp3 to wav", variable=self.mp3_checkVar, font=bc12i, command=lambda: self.mp3_check_chk()) mp3_check.place(x=270, y=20) # Definition for MOS score frm_mos = tk.Frame(master=self.window, relief='solid', bd=1, height=70, width=130) frm_mos.place(x=430, y=540) lbl_mos = tk.Label(master=frm_mos, text='MOS', fg='gray', font=bc12b) lbl_mos.place(x=10, y=23) self.ent_mos_var = tk.StringVar() self.ent_mos_var.set("0.00") self.ent_mos = tk.Label(master=frm_mos, textvariable=self.ent_mos_var, font=bc12i, fg='black', anchor="e", width=5, height=2) self.ent_mos.place(x=60, y=15) # Definition for Buttons self.img_start = PhotoImage(file="resources\\start.png").subsample(10, 10) self.img_pause = PhotoImage(file="resources\\pause.png").subsample(10, 10) self.img_stop = PhotoImage(file="resources\\stop.png").subsample(10, 10) self.tool_started = tk.IntVar() self.tool_started.set(STOPPED) self.btn_start = tk.Button(master=self.window, image=self.img_start, font=bc12b, command=lambda: self.tool_start(), borderwidth=0) self.btn_start.place(x=700, y=538) self.btn_stop = tk.Button(master=self.window, image=self.img_stop, font=bc12b, command=lambda: self.tool_stop(), borderwidth=0) self.btn_stop.place(x=785, y=538) self.btn_stop["state"] = "disabled" def find_device(self): audio = pyaudio.PyAudio() device_num = audio.get_device_count() info = audio.get_host_api_info_by_index(0) numdevices = info.get('deviceCount') indev = {} outdev = {} self.input_devices_list.clear() self.output_devices_list.clear() for i in range(numdevices): # print("Input Device id", i, "-", audio.get_device_info_by_host_api_device_index(0, i)) if audio.get_device_info_by_host_api_device_index(0, i)['maxInputChannels'] > 0: indev['name'] = audio.get_device_info_by_host_api_device_index(0, i)['name'] indev['index'] = audio.get_device_info_by_host_api_device_index(0, i)['index'] self.input_devices_list.append(indev) indev = {} if audio.get_device_info_by_host_api_device_index(0, i)['maxOutputChannels'] > 0: outdev["name"] = audio.get_device_info_by_host_api_device_index(0, i)['name'] outdev['index'] = audio.get_device_info_by_host_api_device_index(0, i)['index'] self.output_devices_list.append(outdev) outdev = {} for i in range(len(self.input_devices_list)): if audio.get_default_input_device_info()['name'] == self.input_devices_list[i]['name']: self.input_device_index = i for i in range(len(self.output_devices_list)): if audio.get_default_output_device_info()['name'] == self.output_devices_list[i]['name']: self.output_device_index = i audio.terminate() # update input devices Combobox def cmb_in_dev_update(self): self.find_device() self.cmb_in_dev["values"] = [] lst = [] for i in range(len(self.input_devices_list)): lst.append(self.input_devices_list[i]['name']) self.cmb_in_dev["values"] = lst # set Default input device def cmb_in_dev_init(self): self.cmb_in_dev.current(self.input_device_index) # update output devices Combobox def cmb_out_dev_update(self): self.find_device() self.cmb_out_dev["values"] = [] lst = [] for i in range(len(self.output_devices_list)): lst.append(self.output_devices_list[i]['name']) self.cmb_out_dev["values"] = lst # set Default output device def cmb_out_dev_init(self): self.cmb_out_dev.current(self.output_device_index) def cmb_out_dev_index_get(self): self.output_device_index = self.output_devices_list[self.cmb_out_dev.current()]['index'] # print("output_device_index = ", self.output_device_index) def cmb_in_dev_index_get(self): self.input_device_index = self.input_devices_list[self.cmb_in_dev.current()]['index'] # print("input_device_index = ", self.input_device_index) # Update Progress information def update_prog_bar(self, percent): self.prog_bar["value"] = int(370 * percent / 370) def thread_play_and_record(self): self.cmb_out_dev_index_get() self.cmb_in_dev_index_get() # copy files from source directories to destination directories dirs_list = [] files_list = [] for (root, dirs, files) in os.walk(self.btn_src_path_var.get(), topdown=True): dirs_list.append(root) # print("root =", root) # print(dirs) # # print(files) if files: for file in files: if file.endswith(".wav"): files_list.append(os.path.join(root, file)) print("total files = ", len(files_list)) total_number = len(files_list) # new destination directories list new_dirs_list = [] for i in range(len(dirs_list)): new_dir = self.btn_dst_path_var.get() + "\\" + dirs_list[i][len(dirs_list[0]):] new_dirs_list.append(os.path.abspath(new_dir)) # print(new_dirs_list[i]) new_files_list = [] for i in range(len(files_list)): new_file = self.btn_dst_path_var.get() + "\\" + files_list[i][len(dirs_list[0]):] # new_file_wav = new_file.replace(".flac", ".wav") new_files_list.append(os.path.abspath(new_file)) # make destination directories for i in range(1, len(new_dirs_list)): print(new_dirs_list[i]) try: os.mkdir(new_dirs_list[i]) except FileExistsError: print(new_dirs_list[i], " exists.") for i in range(len(files_list)): # flac2wav(files_list[i], new_files_list[i]) # print(files_list[i]) # print(new_files_list[i]) self.ent_curr_file_var.set(os.path.basename(new_files_list[i])) self.update_prog_bar(int(i / total_number * 100)) # shutil.copy(files_list[i], new_files_list[i]) if self.tool_started.get() == STOPPED: print(self.tool_started.get()) break play_and_record(int(self.cmb_sample_rate.get()), int(self.cmb_channel.get()), self.input_device_index, self.output_device_index, files_list[i], new_files_list[i]) self.draw_src_wave(files_list[i]) self.draw_rec_wave(new_files_list[i]) mos = pesq_assess.evaluate(files_list[i], new_files_list[i], 16000, 'wb') self.ent_mos_var.set(f'{mos:.2f}') self.update_prog_bar((int(i+1)/total_number * 100)) self.tool_stop() print("thread end") messagebox.showwarning("Information", "Play and Record finished.") def thread_pause_play_and_record(self): pass def thread_stop_play_and_record(self): pass def tool_start(self): print("src=", self.btn_src_path_var.get()) print("dst=", self.btn_dst_path_var.get()) if not(os.path.isdir(self.btn_src_path_var.get())) or not(os.path.isdir(self.btn_dst_path_var.get())): messagebox.showwarning("Warning", "To check Source or Destination directories.") return if self.tool_started.get() == STOPPED: self.tool_started.set(STARTED) self.btn_start.config(image=self.img_pause) self.btn_stop["state"] = "normal" self.dialog_selectable(False) if self.flac_checkVar.get(): tool = threading.Thread(target=self.thread_flac_to_wav, ) tool.start() elif self.mp3_checkVar.get(): tool = threading.Thread(target=self.thread_mp3_to_wav, ) tool.start() else: tool = threading.Thread(target=self.thread_play_and_record, ) tool.start() elif self.tool_started.get() == STARTED: self.tool_started.set(PAUSED) self.btn_start.config(image=self.img_start) self.btn_stop["state"] = "normal" self.dialog_selectable(False) elif self.tool_started.get() == PAUSED: self.tool_started.set(STARTED) self.btn_start.config(image=self.img_pause) self.btn_stop["state"] = "normal" self.dialog_selectable(False) print("start thread started") def tool_stop(self): if self.tool_started.get() == STARTED: self.tool_started.set(STOPPED) self.btn_start.config(image=self.img_start) self.btn_stop.config(relief="flat") self.btn_stop["state"] = "disabled" self.dialog_selectable(True) elif self.tool_started.get() == PAUSED: self.tool_started.set(STOPPED) self.btn_start.config(image=self.img_start) self.btn_stop["state"] = "disabled" self.dialog_selectable(False) def dialog_selectable(self, enable): if not enable: self.btn_src_path["state"] = "disabled" self.btn_dst_path["state"] = "disabled" self.cmb_sample_rate["state"] = "disabled" self.cmb_channel["state"] = "disabled" self.cmb_out_dev["state"] = "disabled" self.cmb_in_dev["state"] = "disabled" else: self.btn_src_path["state"] = "normal" self.btn_dst_path["state"] = "normal" self.cmb_sample_rate["state"] = "normal" self.cmb_channel["state"] = "normal" self.cmb_out_dev["state"] = "normal" self.cmb_in_dev["state"] = "normal" def select_src_folder(self): new_folder = filedialog.askdirectory(initialdir=str(Path.home()), title="Select a Source directory") try: if new_folder != "": if os.path.isdir(new_folder): self.btn_src_path_var.set(os.path.abspath(new_folder)) else: messagebox.showwarning("Warning", "The selected location is not a directory") except: messagebox.showwarning("Warning", "Warning: There is a problem with the Directory !") def select_dst_folder(self): new_dst_folder = filedialog.askdirectory(initialdir=str(Path.home()), title="Select a Destination directory") try: if new_dst_folder != "": if os.path.isdir(new_dst_folder): self.btn_dst_path_var.set(os.path.abspath(new_dst_folder)) else: messagebox.showwarning("Warning", "The selected location is not a directory") except: messagebox.showwarning("Warning", "Warning: There is a problem with the Directory !") def draw_src_wave(self, src_file): spf = wave.open(src_file, "rb") signal = spf.readframes(-1) spf.close() signal = np.frombuffer(signal, "int16") print("source samples = ", len(signal)) fs = spf.getframerate() Time = np.linspace(0, len(signal) / fs, num=len(signal)) self.a1.clear() self.a1.set_ylim([-32768, 32767]) self.a1.set_xlim([0, len(signal) / fs]) self.a1.set_yticklabels([]) self.a1.plot(Time, signal) self.canvas_src.draw_idle() def draw_rec_wave(self, rec_file): spf = wave.open(rec_file, "rb") rec_signal = spf.readframes(-1) spf.close() rec_signal = np.frombuffer(rec_signal, "int16") print("recorded samples = ", len(rec_signal)) fs = spf.getframerate() Time = np.linspace(0, len(rec_signal) / fs, num=len(rec_signal)) self.a2.clear() self.a2.set_ylim([-32768, 32767]) self.a2.set_xlim([0, len(rec_signal) / fs]) self.a2.set_yticklabels([]) self.a2.plot(Time, rec_signal) self.canvas_rec.draw_idle() def play_check_chk(self): if self.play_checkVar.get(): self.mp3_checkVar.set(0) self.flac_checkVar.set(0) def flac_check_chk(self): if self.flac_checkVar.get(): self.play_checkVar.set(0) self.mp3_checkVar.set(0) def mp3_check_chk(self): if self.mp3_checkVar.get(): self.play_checkVar.set(0) self.flac_checkVar.set(0) def thread_flac_to_wav(self): # conv_thread = threading.Thread(target=self.flac_to_wav, ) # conv_thread.start() self.flac_to_wav() self.tool_stop() print("flac to wav thread end.") messagebox.showwarning("Information", "File conversion from flac to wav finished.") def flac_to_wav(self): # copy files from source directories to destination directories dirs_list = [] files_list = [] for (root, dirs, files) in os.walk(self.btn_src_path_var.get(), topdown=True): dirs_list.append(root) # print("root =", root) # print(dirs) # # print(files) if files: for file in files: if file.endswith(".flac"): files_list.append(os.path.join(root, file)) print("total files = ", len(files_list)) total_number = len(files_list) # new destination directories list new_dirs_list = [] for i in range(len(dirs_list)): new_dir = self.btn_dst_path_var.get() + "\\" + dirs_list[i][len(dirs_list[0]):] new_dirs_list.append(os.path.abspath(new_dir)) # print(new_dirs_list[i]) new_files_list = [] for i in range(len(files_list)): new_file = self.btn_dst_path_var.get() + "\\" + files_list[i][len(dirs_list[0]):] new_file_wav = new_file.replace(".flac", ".wav") new_files_list.append(os.path.abspath(new_file_wav)) # make destination directories for i in range(1, len(new_dirs_list)): print(new_dirs_list[i]) try: os.mkdir(new_dirs_list[i]) except FileExistsError: print(new_dirs_list[i], " exists.") for i in range(len(files_list)): if self.tool_started.get() == STOPPED: break flac2wav(files_list[i], new_files_list[i]) print(files_list[i]) print(new_files_list[i]) self.ent_curr_file_var.set(os.path.basename(new_files_list[i])) self.update_prog_bar(int((i+1) / total_number * 100)) # shutil.copy(files_list[i], new_files_list[i]) def thread_mp3_to_wav(self): # conv_thread = threading.Thread(target=self.flac_to_wav, ) # conv_thread.start() self.mp3_to_wav() self.tool_stop() print("flac to wav thread end.") messagebox.showwarning("Information", "File conversion from mp3 to wav finished.") def mp3_to_wav(self): # copy files from source directories to destination directories dirs_list = [] files_list = [] for (root, dirs, files) in os.walk(self.btn_src_path_var.get(), topdown=True): dirs_list.append(root) # print("root =", root) # print(dirs) # # print(files) if files: for file in files: if file.endswith(".mp3"): files_list.append(os.path.join(root, file)) print("total files = ", len(files_list)) total_number = len(files_list) # new destination directories list new_dirs_list = [] for i in range(len(dirs_list)): new_dir = self.btn_dst_path_var.get() + "\\" + dirs_list[i][len(dirs_list[0]):] new_dirs_list.append(os.path.abspath(new_dir)) # print(new_dirs_list[i]) new_files_list = [] for i in range(len(files_list)): new_file = self.btn_dst_path_var.get() + "\\" + files_list[i][len(dirs_list[0]):] new_file_wav = new_file.replace(".mp3", ".wav") new_files_list.append(os.path.abspath(new_file_wav)) # make destination directories for i in range(1, len(new_dirs_list)): print(new_dirs_list[i]) try: os.mkdir(new_dirs_list[i]) except FileExistsError: print(new_dirs_list[i], " exists.") for i in range(len(files_list)): if self.tool_started.get() == STOPPED: break mp3towav(files_list[i], new_files_list[i]) print(files_list[i]) print(new_files_list[i]) self.ent_curr_file_var.set(os.path.basename(new_files_list[i])) self.update_prog_bar((int(i+1) / total_number * 100))
class ValuesFrame(tk.Frame): MIN_VALUE = 0 MAX_VALUE = 105 def __init__(self, title, *args, **kwargs): self._title = title tk.Frame.__init__(self, *args, **kwargs) fig, self._ax = plt.subplots() self._ax.xaxis.set_tick_params(rotation=15, labelsize=8) self._ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S')) self._ax.xaxis.set_major_locator( mdates.SecondLocator(bysecond=[0, 15, 30, 45])) self._ax.xaxis.set_minor_locator( mdates.SecondLocator( bysecond=[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55])) self._ax.grid(True) self._canvas = FigureCanvasTkAgg(fig, self) self._canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) self.last_line = None self.poly = None self.update_timeline() def invalidate_viewport(self): t2 = datetime.today() t1 = t2 - timedelta(seconds=65) self._ax.set_xlim([t1, t2]) self._ax.set_ylim([self.MIN_VALUE, self.MAX_VALUE]) self._canvas.draw_idle() def update_timeline(self): now = datetime.today() '''extend last_line to the current time''' if self.last_line: xd = self.last_line.get_xdata() xd[-1] = now self.last_line.set_xdata(xd) '''extend the poly to the current time''' if self.poly: self.poly.xy[-3][0] = mdates.date2num(now) self.poly.xy[-2][0] = mdates.date2num(now) self.invalidate_viewport() self.after(1000, self.update_timeline) def draw_data(self, data): ''' update frame with data where data elems are points [(datetime,value),] ''' ''''convert input data to xy arrays''' tx = [] tv = [] last_v = None for x, v, *_ in data: if last_v != None: tx.append(x) tv.append(last_v) tx.append(x) tv.append(v) last_v = v '''append last point for the current time''' if tx and tv: tx.append(datetime.today()) tv.append(last_v) '''clear old plots and patches''' self._ax.clear() self._ax.grid(True) [p.remove() for p in reversed(self._ax.patches)] if tx and tv: '''plot main lines''' *_, self.last_line = self._ax.plot_date(tx, tv, 'r-', xdate=True, lw=3) '''draw transparent polygon area''' verts = [(mdates.date2num(tx[0]), 0), *zip(map(mdates.date2num, tx), tv), (mdates.date2num(tx[-1]), 0)] self.poly = Polygon(verts, alpha=0.2, facecolor='r', edgecolor='r') self._ax.add_patch(self.poly) self._ax.set_title(self._title) else: self._ax.set_title('No data for ' + self._title) '''update viewport''' self.invalidate_viewport()
class NetworkPlotTk(KWallNetworkPlotBase): """ This class implements UIs using Tkinter. The content of this class is independent of the parent class. It only depends on the grandparent class, which should be 'NetworkPlotBase'. Therefore this class can inherit any class whose parent is 'NetworkPlotBase'; just change the name of the parent in the definition of this class. """ def __init__(self, master=None, title=None, ): super(NetworkPlotTk, self).__init__( matplotlib_figure=matplotlib.figure.Figure(), ) if master is None: master = tk.Tk() master.withdraw() self.master = master #self.master.protocol("WM_DELETE_WINDOW", self.on_closing) # Create a Toplevel widget, which is a child of GUILoom # and contains plots, self.toplevel = tk.Toplevel(master) self.toplevel.wm_title(title) self.toplevel.protocol("WM_DELETE_WINDOW", self.on_closing) self.plot_idx_scale = None self.plot_idx_entry = None self.plot_idx_entry_var = tk.StringVar() self.plot_idx_entry_var.trace('w', self.plot_idx_entry_change) self.canvas = FigureCanvas( self.figure, master=self.toplevel, resize_callback=self.canvas_resize_callback ) self.canvas.show() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) toolbar = NavigationToolbar(self.canvas, self.toplevel) toolbar.update() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) def on_closing(self): self.toplevel.destroy() self.master.destroy() def scale_action(self, scale_value): new_plot_idx = int(scale_value) self.update_current_plot(new_plot_idx) self.plot_idx_entry_var.set(new_plot_idx) def plot_idx_entry_change(self, *args): try: new_plot_idx = int(self.plot_idx_entry_var.get()) if new_plot_idx == self.current_plot_idx: return None elif new_plot_idx < 0: new_plot_idx = 0 elif new_plot_idx > len(self.plots) - 1: new_plot_idx = len(self.plots) - 1 self.plot_idx_scale.set(new_plot_idx) self.update_current_plot(new_plot_idx) except ValueError: pass return None def update_current_plot(self, new_plot_idx): if self.data_cursor is not None: self.data_cursor.hide().disable() self.plots[self.current_plot_idx].set_visible(False) self.plots[new_plot_idx].set_visible(True) # Update the index variable for the currently displayed plot. self.current_plot_idx = new_plot_idx self.set_data_cursor() self.canvas.draw_idle() self.canvas.get_tk_widget().focus_set() return None def canvas_resize_callback(self, event): self.set_data_cursor() def show(self): plot_idx = 0 self.current_plot_idx = plot_idx self.plots[plot_idx].set_visible(True) self.set_data_cursor() if(len(self.plots) > 1): tk.Label( self.toplevel, text='Plot #', ).pack(side=tk.LEFT) self.plot_idx_entry_var.set(plot_idx) self.plot_idx_entry = tk.Entry( self.toplevel, textvariable=self.plot_idx_entry_var, width=len(str(len(self.plots)-1)), ) self.plot_idx_entry.pack(side=tk.LEFT) tk.Label( self.toplevel, text='/{}'.format(len(self.plots)-1), ).pack(side=tk.LEFT) self.plot_idx_scale = tk.Scale( self.toplevel, command=self.scale_action, #length=100*len(self.plots), orient=tk.HORIZONTAL, #showvalue=1, showvalue=0, to=len(self.plots)-1, variable=self.current_plot_idx, ) self.plot_idx_scale.pack( expand=True, fill=tk.X, side=tk.LEFT, )
class AllTransactions: def __init__(self, root, main): self.main = main self.root = root self.set_styles() matplotlib.rcParams.update({ "font.family": self.main.font, "font.size": 10, "text.color": "white" }) self.tFrame = Frame(self.root, bg=self.main.colors[0]) self.topFrame = Frame(self.tFrame, bg=self.main.colors[0], height=1000) Label(self.topFrame, text="All Transactions", fg=self.main.colors[4], bg=self.main.colors[0], font=(self.main.font, 24), padx=15, pady=10).pack(side=LEFT) self.backbtn = Button(self.topFrame, text="Back", font=(self.main.font, 12, "bold"), bd=0, highlightthickness=0, padx=10, pady=10, bg=self.main.colors[1], fg=self.main.colors[0], command=self.showDashboard) self.backbtn.pack(side=RIGHT, padx=10) self.topFrame.pack(side=TOP, fill=X) self.bottomFrame = Frame(self.tFrame, bg=self.main.colors[0], padx=15, pady=10) self.treeV = ttk.Treeview(self.bottomFrame) self.treeV['columns'] = ("Amount", "Type", "Category", "Date", "Client", "Contact") self.treeV.column("#0", width=0, stretch=NO) self.treeV.column("Amount", anchor=W, width=150) self.treeV.column("Type", anchor=W, width=40) self.treeV.column("Category", anchor=W, width=130) self.treeV.column("Date", anchor=W, width=60) self.treeV.column("Client", anchor=W) self.treeV.column("Contact", anchor=W, width=50) self.treeV.heading("Amount", text="Amount", anchor=W) self.treeV.heading("Type", text="Type", anchor=W) self.treeV.heading("Category", text="Wallet", anchor=W) self.treeV.heading("Date", text="Date", anchor=W) self.treeV.heading("Client", text="Client", anchor=W) self.treeV.heading("Contact", text="Contact", anchor=W) self.treeV.pack(fill=BOTH, expand=1, side=TOP) self.line = Frame(self.bottomFrame, bg=self.main.colors[4], pady=3, padx=3).pack(side=TOP, pady=5, fill=X) self.ef = Frame(self.bottomFrame, bg=self.main.colors[0]) self.fig = Figure(figsize=(7, 5), dpi=100) self.fig.set_facecolor(self.main.colors[0]) self.ax = self.fig.add_subplot(111) self.chartcanv = FigureCanvasTkAgg(self.fig, self.ef) self.canv = self.chartcanv.get_tk_widget() self.canv.pack(side=LEFT, expand=1) self.canv['bd'] = 0 self.canv['highlightthickness'] = 0 self.canv['bg'] = self.main.colors[0] Label(self.ef, font=(self.main.font, 18), fg=self.main.colors[4], text="Search by client", bg=self.main.colors[0]).pack(side=LEFT) self.search_by_client = Entry(self.ef, bd=0, highlightthickness=0, fg=self.main.colors[2], bg=self.main.colors[3], font=(self.main.font, 16)) self.search_by_client.bind("<KeyRelease>", self.checkMatch) self.search_by_client.pack(side=LEFT, padx=20) self.ef.pack(side=BOTTOM) self.bottomFrame.pack(fill=BOTH, expand=1) self.tplot() def checkMatch(self, e): typed = self.search_by_client.get() if typed == '': data = self.main.db.get_all_transactions() else: data = [] for i in self.main.db.get_all_transactions(): if typed.lower() in i[4].lower() or typed.lower( ) in i[3].lower(): data.append(i) self.treeV.delete(*self.treeV.get_children()) for i in range(len(data)): self.treeV.insert(parent='', index='end', iid=i, text='', values=(data[i][1], data[i][0], data[i][2], data[i][3], data[i][4], data[i][5])) def tplot(self): data = self.main.db.getAmtAndDate() sizes = [i[0] for i in data] labels = [i[1] for i in data] print(sizes, labels) self.ax.clear() self.ax.pie(sizes, labels=labels, autopct="%1.1f%%", colors=self.main.colors, radius=1.4) self.chartcanv.draw_idle() def add(self): amt = float(self.amt.get()) name = self.personName.get() contact = self.clientContact.get() date = datetime.date.today() category = self.categories[self.category.current()][0] if amt > 0 and len(name) < 20 and len(contact) < 20: self.main.db.new_transaction(name, contact, self.trans_type.get(), amt, category, date) self.showDashboard() def set_styles(self): self.style = ttk.Style() self.style.configure("Treeview", background=self.main.colors[0], foreground=self.main.colors[3], fieldbackground=self.main.colors[1], rowheight=25, height=100, borderwidth=0, bd=0, highlightthickness=0, font=(self.main.font, 12)) self.style.map("Treeview", background=[('selected', self.main.colors[2])]) self.style.configure( "Treeview.Heading", font=(self.main.font, 12), background=self.main.colors[3], foreground=self.main.colors[0], padding=5, bd=0, highlightthickness=0, ) self.style.layout("Treeview", [('Treeview.treearea', { 'sticky': 'nswe' })]) def show(self): self.main.mainFrame.pack_forget() self.tFrame.pack(fill=BOTH, expand=True) self.main.db.refresh_treev(self.treeV) self.tplot() def showDashboard(self): self.tFrame.pack_forget() self.main.mainFrame.pack(fill=BOTH, expand=1)
class PhaseApp(tk.Tk): """Tkinter application for manual phase correction. See Also -------- :py:func:`manual_phase_spectrum` """ def __init__(self, spectrum, max_p1): super().__init__() self.p0 = 0.0 self.p1 = 0.0 self.n = spectrum.size self.pivot = int(self.n // 2) self.init_spectrum = copy.deepcopy(spectrum) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) self.fig = Figure(figsize=(6, 4), dpi=160) # Set colour of figure frame color = self.cget('bg') self.fig.patch.set_facecolor(color) self.ax = self.fig.add_axes([0.03, 0.1, 0.94, 0.87]) self.ax.set_yticks([]) self.specline = self.ax.plot(np.real(spectrum), color='k')[0] ylim = self.ax.get_ylim() mx = max( np.amax(np.real(spectrum)), np.abs(np.amin(np.real(spectrum))), ) self.pivotline = self.ax.plot( 2 * [self.pivot], [-10 * mx, 10 * mx], color='r', )[0] self.ax.set_ylim(ylim) self.canvas = FigureCanvasTkAgg(self.fig, master=self) self.canvas.draw() self.canvas.get_tk_widget().grid( row=0, column=0, padx=10, pady=10, sticky='nsew', ) self.toolbar = NavigationToolbar2Tk( self.canvas, self, pack_toolbar=False, ) self.toolbar.grid(row=1, column=0, pady=(0, 10), sticky='w') self.scale_frame = tk.Frame(self) self.scale_frame.grid( row=2, column=0, padx=10, pady=(0, 10), sticky='nsew', ) self.scale_frame.columnconfigure(1, weight=1) self.scale_frame.rowconfigure(0, weight=1) items = [ (self.pivot, self.p0, self.p1), ('pivot', 'p0', 'p1'), (0, -np.pi, -max_p1), (self.n, np.pi, max_p1), ] for i, (init, name, mn, mx) in enumerate(zip(*items)): lab = tk.Label(self.scale_frame, text=name) pady = (0, 10) if i != 2 else 0 lab.grid(row=i, column=0, sticky='w', padx=(0, 5), pady=pady) self.__dict__[f'{name}_scale'] = scale = tk.Scale( self.scale_frame, from_=mn, to=mx, resolution=0.001, orient=tk.HORIZONTAL, showvalue=0, sliderlength=15, bd=0, highlightthickness=1, highlightbackground='black', relief='flat', command=lambda value, name=name: self.update_phase(name), ) scale.set(init) scale.grid(row=i, column=1, sticky='ew', pady=pady) self.__dict__[f'{name}_label'] = label = tk.Label( self.scale_frame, text=f"{self.__dict__[f'{name}']:.3f}" if i != 0 else str(self.__dict__[f'{name}'])) label.grid(row=i, column=2, padx=5, pady=pady, sticky='w') self.button_frame = tk.Frame(self) self.button_frame.columnconfigure(0, weight=1) self.button_frame.grid(row=3, column=0, padx=10, pady=10, sticky='ew') self.save_button = tk.Button(self.button_frame, width=8, highlightbackground='black', text='Save', bg='#77dd77', command=self.save) self.save_button.grid(row=1, column=0, sticky='e') self.cancel_button = tk.Button(self.button_frame, width=8, highlightbackground='black', text='Cancel', bg='#ff5566', command=self.cancel) self.cancel_button.grid(row=1, column=1, sticky='e', padx=(10, 0)) def update_phase(self, name): value = self.__dict__[f'{name}_scale'].get() if name == 'pivot': self.pivot = int(value) self.pivot_label['text'] = str(self.pivot) self.pivotline.set_xdata([self.pivot, self.pivot]) else: self.__dict__[name] = float(value) self.__dict__[f'{name}_label']['text'] = \ f"{self.__dict__[name]:.3f}" spectrum = phase( self.init_spectrum, [self.p0], [self.p1], [self.pivot], ) self.specline.set_ydata(np.real(spectrum)) self.canvas.draw_idle() def save(self): self.p0 = self.p0 - self.p1 * (self.pivot / self.n) self.destroy() def cancel(self): self.destroy() self.p0 = None self.p1 = None
class GraphFrame(tk.Frame): def __init__(self, parent, **kw): super().__init__(parent, **kw) self.atoms_logic = AtomsLogic() self.condition_build_surface = True label = tk.Label(self, text="Graph Page", font=LARGE_FONT) label.pack(pady=10, padx=10) self.is_new_point = False self.quit = False self.x_arr, self.y_arr = np.meshgrid(np.arange(0, MAX_FIELD_SIZE, 1), np.arange(0, MAX_FIELD_SIZE, 1)) self.surface = None self.tool_tip = None self.captured_atom = None fig = plt.figure() self.ax = fig.add_subplot(111, projection='3d') plt.xlim(0, MAX_FIELD_SIZE + 2) plt.ylim(0, MAX_FIELD_SIZE + 2) self.canvas = FigureCanvasTkAgg(fig, self) self.canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) toolbar = NavigationToolbar2Tk(self.canvas, self) toolbar.update() self.canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True) def update_graph_data_algorithm(self): if self.atoms_logic.is_new_point(): try: self.tool_tip.remove() if self.tool_tip is not None else None self.captured_atom.remove( ) if self.captured_atom is not None else None except Exception as e: self.captured_atom = None print(traceback.format_exc()) print(str(e)) if self.atoms_logic.atom_release_event: self.ax.scatter(*self.atoms_logic.get_tool_coordinate(), s=5, c=COLOR_ATOM, marker='8') self.atoms_logic.atom_release_event = False self.atoms_logic.update_tool_coordinate() self.tool_tip = self.ax.scatter( *self.atoms_logic.get_tool_coordinate(), s=5, c=COLOR_TIP, marker='8') if self.atoms_logic.atom_collection.append_unique_atom(): self.ax.scatter(*self.atoms_logic.get_tool_coordinate(), s=5, c=COLOR_ATOM, marker='8') if self.atoms_logic.atom_captured_event: self.__update_all_dots_on_graph() self.atoms_logic.atom_captured_event = False if self.atoms_logic.is_atom_captured(): self.captured_atom = self.ax.scatter( *self.atoms_logic.get_tool_coordinate(), s=5, c=COLOR_ATOM, marker='8') if self.condition_build_surface: self.__build_surface() self.__reset_sensor() def __reset_sensor(self): if self.atoms_logic.tool_is_coming_down(): return self.atoms_logic.set_is_surface(False) self.atoms_logic.set_is_atom(False) def __update_all_dots_on_graph(self): self.ax.collections = [] self.__set_tool_tip_dot() for atom in self.atoms_logic.atom_collection.atoms_list: atom: Atom if not atom.is_captured: self.ax.scatter(*atom.coordinates, s=5, c=COLOR_ATOM, marker='8') else: self.captured_atom = self.ax.scatter( *self.atoms_logic.get_tool_coordinate(), s=5, c=COLOR_ATOM, marker='8') def __set_tool_tip_dot(self): self.tool_tip = self.ax.scatter( *self.atoms_logic.get_tool_coordinate(), s=5, c=COLOR_TIP, marker='8') def show_surface(self): self.__build_surface() def remove_surface(self): try: if self.surface is not None: self.surface.remove() except Exception as e: print(traceback.format_exc()) print(str(e)) def draw_graph(self): while not self.quit: try: time.sleep(SLEEP_BETWEEN_DRAW_GRAPH) self.canvas.draw_idle() except Exception as e: self.quit = True print(traceback.format_exc()) print(str(e)) exit(0) @staticmethod def write_data_to_json_file(file_name: str, data): if os.path.exists(file_name): with open(file_name, 'rb+') as data_file: data_file.seek(-1, os.SEEK_END) data_file.truncate() with open(file_name, 'a') as data_file: data_file.write(f",{json.dumps(data)}]") else: with open(file_name, 'a') as data_file: data_file.write(f"[{json.dumps(data)}]") @staticmethod def read_json_file(file_name: str): if os.path.exists(file_name): with open(file_name, 'r') as data_file: return json.load(data_file) def __build_surface(self): self.remove_surface() self.surface = self.ax.plot_surface( self.x_arr, self.y_arr, self.atoms_logic.surface_data, rstride=1, cstride=1, cmap=plt.cm.get_cmap('Blues_r'), ) self.canvas.draw_idle() self.ax.mouse_init() def get_data(self) -> object: return self.atoms_logic.surface_data.tolist()
class StrainMapping: def __init__(self, directory): self.directory = directory self.sampleArray = self.directory.sampleFits.arrays self.openArray = self.directory.openFits.arrays self.im = self.sampleArray[sliderInd] self.frame = tk.Toplevel() self.fig = Figure(figsize=(7, 7)) self.ax = self.fig.add_subplot(111) self.strainButton = tk.Button(self.frame, text="do", command=self.strainMap) self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame) self.canvas.show() self.canvas.get_tk_widget().grid(row=0) self.canvas.mpl_connect('key_press_event', self.onKey) self.strainButton.grid(row=1) self.mask = np.zeros((512, 512)) self.pix = np.arange(512) self.XX, self.YY = np.meshgrid(self.pix, self.pix) self.pix = np.vstack((self.XX.flatten(), self.YY.flatten())).T self.lasso = LassoSelector(self.ax, self.onselect) def do(self): self.canvas.mpl_connect('key_press_event', self.onKey) self.ax.imshow(self.im, cmap=plt.cm.gray) def strainMap(self): zipped = zip(self.sampleArray, self.openArray) transmitted = np.zeros((len(zipped), 1, 512 * 512)).astype(np.float32) l = 0 kernel = np.ones((5, 5)) kernel = kernel / kernel.sum() for sample, empty in zipped: sample = sample * self.mask.reshape(512, 512) empty = empty * self.mask.reshape(512, 512) transmitted[l] = convolve2d( sample, kernel, mode='same').flatten() / convolve2d( empty, kernel, mode='same').flatten() l += 1 print l lambdas = [] for c in range(512 * 512): if transmitted[:, :, c][posList[0]:posList[-1]].all() == False: lambdas.append(0) print 'empty' else: try: popt, pcov = curve_fit( self.func, wavelength[posList[0]:posList[-1] + 1], np.dstack( np.nan_to_num( transmitted[:, :, c][posList[0]:posList[-1] + 1]))[0][0], p0=initial_guess) lambdas.append( (initial_guess[2] - popt[2]) / initial_guess[2]) print 'full' "fit Bragg edge, record position" except (OptimizeWarning, RuntimeError): lambdas.append( (initial_guess[2] - popt[2]) / initial_guess[2]) print 'Exception' strainMap = np.array(lambdas).reshape(512, 512) * self.mask.reshape( 512, 512) strainMap = np.ma.masked_where(strainMap == 0, strainMap) minVal = strainMap.min() maxVal = strainMap.max() cmap = plt.cm.coolwarm cmap.set_bad(color='black') fig = plt.figure() ax = fig.add_subplot(111) cax = ax.imshow(strainMap, interpolation='None', cmap=cmap) cbar = fig.colorbar(cax, ticks=[minVal, 0, maxVal]) cbar.ax.set_yticklabels(['< ' + minVal, '0', '> ' + maxVal]) plt.show() plt.close() def func(self, x, c_1, c_2, lambda0, sigma, tau): return c_1 * (scipy.special.erfc( (lambda0 - x) / (np.sqrt(2) * sigma)) - np.exp( ((lambda0 - x) / tau) + (sigma**2 / (2 * tau**2))) * scipy.special.erfc(( (lambda0 - x) / (np.sqrt(2) * sigma)) + sigma / (np.sqrt(2) * tau))) + c_2 def updateArray(self, im, indices, mask): lin = np.arange(self.im.size) self.mask = self.mask.flatten() self.mask[lin[indices]] = 1 newArray = im.flatten() #newArray[lin[indices]] = 1 newArray = newArray * self.mask self.ax.imshow(newArray.reshape(self.im.shape), cmap=plt.cm.gray) self.canvas.draw() print self.mask return newArray.reshape(self.im.shape) def onselect(self, verts): p = path.Path(verts) ind = p.contains_points(self.pix, radius=1) array = self.updateArray(self.im, ind, self.mask) self.canvas.draw_idle() def onKey(self, event): print "key pressed" if event.key == 'r': self.ax.imshow(self.im, cmap=plt.cm.gray) self.canvas.draw()
class StrainMapping: def __init__(self, directory): self.directory = directory self.sampleArray = self.directory.sampleFits.arrays self.openArray = self.directory.openFits.arrays self.im = self.sampleArray[sliderInd] self.frame = tk.Toplevel() self.fig = Figure(figsize=(7, 7)) self.ax = self.fig.add_subplot(111) self.strainButton = tk.Button(self.frame, text="do", command=self.strainMap) self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame) self.canvas.show() self.canvas.get_tk_widget().grid(row=0) self.canvas.mpl_connect('key_press_event', self.onKey) self.strainButton.grid(row=1) self.mask = np.zeros((512,512)) self.pix = np.arange(512) self.XX, self.YY = np.meshgrid(self.pix, self.pix) self.pix = np.vstack((self.XX.flatten(), self.YY.flatten())).T self.lasso = LassoSelector(self.ax, self.onselect) def do(self): self.canvas.mpl_connect('key_press_event', self.onKey) self.ax.imshow(self.im, cmap = plt.cm.gray) def strainMap(self): zipped = zip(self.sampleArray, self.openArray) transmitted = np.zeros((len(zipped),1,512*512)).astype(np.float32) l = 0 kernel = np.ones((5,5)) kernel = kernel / kernel.sum() for sample, empty in zipped: sample = sample * self.mask.reshape(512,512) empty = empty * self.mask.reshape(512,512) transmitted[l] = convolve2d(sample, kernel, mode='same').flatten() / convolve2d(empty, kernel, mode='same').flatten() l += 1 print l lambdas = [] for c in range(512*512): if transmitted[:,:,c][posList[0]:posList[-1]].all() == False: lambdas.append(0) print 'empty' else: try: popt, pcov = curve_fit(self.func, wavelength[posList[0]:posList[-1]+1], np.dstack(np.nan_to_num(transmitted[:,:,c][posList[0]:posList[-1]+1]))[0][0], p0=initial_guess) lambdas.append((initial_guess[2] - popt[2])/initial_guess[2]) print 'full' "fit Bragg edge, record position" except (OptimizeWarning, RuntimeError): lambdas.append((initial_guess[2] - popt[2])/initial_guess[2]) print 'Exception' strainMap = np.array(lambdas).reshape(512,512)*self.mask.reshape(512,512) strainMap = np.ma.masked_where(strainMap == 0, strainMap) minVal = strainMap.min() maxVal = strainMap.max() cmap = plt.cm.coolwarm cmap.set_bad(color='black') fig = plt.figure() ax = fig.add_subplot(111) cax = ax.imshow(strainMap, interpolation='None', cmap=cmap) cbar = fig.colorbar(cax, ticks=[minVal, 0, maxVal]) cbar.ax.set_yticklabels(['< '+minVal, '0', '> '+maxVal]) plt.show() plt.close() def func(self, x, c_1, c_2, lambda0, sigma, tau): return c_1 * (scipy.special.erfc((lambda0 - x) / (np.sqrt(2) * sigma)) - np.exp( ((lambda0 - x) / tau) + (sigma ** 2 / (2 * tau ** 2))) * scipy.special.erfc( ((lambda0 - x) / (np.sqrt(2) * sigma)) + sigma / (np.sqrt(2) * tau))) + c_2 def updateArray(self, im, indices,mask): lin = np.arange(self.im.size) self.mask = self.mask.flatten() self.mask[lin[indices]] = 1 newArray = im.flatten() #newArray[lin[indices]] = 1 newArray = newArray*self.mask self.ax.imshow(newArray.reshape(self.im.shape), cmap=plt.cm.gray) self.canvas.draw() print self.mask return newArray.reshape(self.im.shape) def onselect(self, verts): p = path.Path(verts) ind = p.contains_points(self.pix, radius=1) array = self.updateArray(self.im, ind, self.mask) self.canvas.draw_idle() def onKey(self, event): print "key pressed" if event.key == 'r': self.ax.imshow(self.im, cmap=plt.cm.gray) self.canvas.draw()
class LiveDataView(ttk.Frame): def __init__(self, parent, x_history=30, scale_x=1, scale_y = 1, data_types={'default': 'line'}, **ax_kwargs): self.parent = parent self.x_history = x_history * scale_x self.scale_x = scale_x self.scale_y = scale_y # Create matplotlib figure self.fig_preview = Figure() self.ax_preview = self.fig_preview.add_subplot(111) self.data = {} for name, plot_type in data_types.items(): if plot_type in ['line', 'plot']: data, = self.ax_preview.plot(0, 0) elif plot_type == 'scatter': data = self.ax_preview.scatter(0, 0) self.data[name] = data self.ax_preview.set(**ax_kwargs) self.ax_preview.set_xlim((-self.x_history, 0)) # Add to tkinter self.canvas_preview = FigureCanvasTkAgg(self.fig_preview, self.parent) self.canvas_preview.draw() self.canvas_preview.get_tk_widget().grid(row=0, column=0, sticky='wens') def update_view(self, xy, name='default'): # Update data # Need to determine the type of plot it is. new_xy = xy * np.array([self.scale_x, self.scale_y]) data_type = type(self.data[name]) if data_type == matplotlib.lines.Line2D: # Line plot current = self.data[name].get_xydata() updated = self.update_data(current, new_xy) self.data[name].set_data(updated.T) elif data_type == matplotlib.collections.PathCollection: # Scatter plot current = self.data[name].get_offsets() updated = self.update_data(current, new_xy) self.data[name].set_offsets(updated) # Update view new_xlim = new_xy[0] + np.array([-self.x_history, 0]) self.ax_preview.set_xlim(new_xlim) self.canvas_preview.draw_idle() def update_data(self, current, xy): # Only keep data for window defined by `x_history` # Should keep down on resource usage. new_ix = current[:, 0] > xy[0] - self.x_history return np.concatenate([current[new_ix, :], [xy]], axis=0) def clear_data(self): blank = np.zeros((1, 2)) for name, data in self.data.items(): data_type = type(self.data[name]) if data_type == matplotlib.lines.Line2D: # Need at least 2 data points for some reason... self.data[name].set_data(np.concatenate([blank, blank])) elif data_type == matplotlib.collections.PathCollection: self.data[name].set_offsets(blank) # Update view self.ax_preview.set_xlim([-self.x_history, 0]) self.canvas_preview.draw_idle()
class SpectralNetworkPlotTk(SpectralNetworkPlotUIBase): """ This class implements UIs using Tkinter. The content of this class is independent of the parent class. It only depends on the grandparent class, which should be 'NetworkPlotBase'. Therefore this class can inherit any class whose parent is 'NetworkPlotBase'; just change the name of the parent in the definition of this class. """ def __init__(self, master=None, title=None, plot_range=None,): super(SpectralNetworkPlotTk, self).__init__( matplotlib_figure=matplotlib.figure.Figure(), plot_range=plot_range, ) if master is None: root = tk.Tk() root.withdraw() self.root = root else: self.root = master self.master = master # Create a Toplevel widget, which is a child of GUILoom # and contains plots, self.toplevel = tk.Toplevel(self.root) self.toplevel.wm_title(title) self.toplevel.protocol("WM_DELETE_WINDOW", self.on_closing) self.plot_idx_scale = None self.plot_idx_entry = None self.plot_idx_entry_var = tk.StringVar() self.plot_idx_entry_var.trace('w', self.plot_idx_entry_change) self.canvas = FigureCanvas( self.figure, master=self.toplevel, resize_callback=self.canvas_resize_callback ) self.canvas.show() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) toolbar = NavigationToolbar(self.canvas, self.toplevel) toolbar.update() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1) def on_closing(self): self.toplevel.destroy() if self.master is None: self.root.destroy() def scale_action(self, scale_value): new_plot_idx = int(scale_value) self.update_current_plot(new_plot_idx) self.plot_idx_entry_var.set(new_plot_idx) def plot_idx_entry_change(self, *args): try: new_plot_idx = int(self.plot_idx_entry_var.get()) if new_plot_idx == self.current_plot_idx: return None elif new_plot_idx < 0: new_plot_idx = 0 elif new_plot_idx > len(self.plots) - 1: new_plot_idx = len(self.plots) - 1 self.plot_idx_scale.set(new_plot_idx) self.update_current_plot(new_plot_idx) except ValueError: pass return None def update_current_plot(self, new_plot_idx): if self.data_cursor is not None: self.data_cursor.hide().disable() self.plots[self.current_plot_idx].set_visible(False) self.plots[new_plot_idx].set_visible(True) # Update the index variable for the currently displayed plot. self.current_plot_idx = new_plot_idx self.set_data_cursor() self.canvas.draw_idle() self.canvas.get_tk_widget().focus_set() return None def canvas_resize_callback(self, event): self.set_data_cursor() def show(self): plot_idx = 0 self.current_plot_idx = plot_idx self.plots[plot_idx].set_visible(True) self.set_data_cursor() if(len(self.plots) > 1): tk.Label( self.toplevel, text='Plot #', ).pack(side=tk.LEFT) self.plot_idx_entry_var.set(plot_idx) self.plot_idx_entry = tk.Entry( self.toplevel, textvariable=self.plot_idx_entry_var, width=len(str(len(self.plots) - 1)), ) self.plot_idx_entry.pack(side=tk.LEFT) tk.Label( self.toplevel, text='/{}'.format(len(self.plots) - 1), ).pack(side=tk.LEFT) self.plot_idx_scale = tk.Scale( self.toplevel, command=self.scale_action, # length=100*len(self.plots), orient=tk.HORIZONTAL, showvalue=0, to=len(self.plots) - 1, variable=self.current_plot_idx, ) self.plot_idx_scale.pack( expand=True, fill=tk.X, side=tk.LEFT, )
class Watch(): xy_data_style = {'fontsize': 28, 'rotation': 0} main_panel = 0 def __init__(self, frame, config=None, width=100, height=100, ready=None): self._frame = frame self._fig = None self.config = config self.canvas = None self.width = width self.height = height self.ready = ready self.type = '' if 'fontsize' in config: self.xy_data_style['fontsize'] = config['fontsize'] self.k_watch = data.K(other.stock_csv_path(self.config)) self.k = None self.trend_watch = data.Trend(other.csv_path(self.config)) self.trend = None self.k_trend = None self._use_style() # 繪製 def plot(self, code, date=None, **kwargs): if self._fig is not None: self.clear() else: self._fig = plt.figure() self._fig.set_size_inches((self.width / 100, self.height / 100)) self.canvas = FigureCanvasTkAgg(self._fig, self._frame) self.kwargs = kwargs self.update_plot(code, date=date, **kwargs) return self._fig # 繪製某個股 def update_plot(self, code, date=None, **kwargs): type = kwargs.get('type') if type == 'k': self._plot_k(code, date=date, **kwargs) elif type == 'trend': self._plot_trend(code, date=date, **kwargs) elif type == 'k_trend': self._plot_k_trend(code, date=date, **kwargs) self.canvas.draw_idle() return True # K線看盤 def _plot_k(self, code, date=None, **kwargs): if self.k is None: self.k = KWatch( self._fig, self.canvas, self.k_watch, ) self.k.plot(code, date=date, **kwargs) # 走勢圖看盤 def _plot_trend(self, code, date=None, **kwargs): if self.trend is None: self.trend = TrendWatch( self._fig, self.canvas, self.trend_watch, self.k_watch.get_stock(), ) self.trend.plot(code, date=date, **kwargs) def _plot_k_trend(self, code, date=None, **kwargs): if self.k_trend is None: self.k_trend = KTrendWatch( self._fig, self.canvas, self.k_watch, self.trend_watch, self.k_watch.get_stock(), ) self.k_trend.plot(code, date=date, **kwargs) # 設定看盤樣式 def _use_style(self): plt.rcParams['font.sans-serif'] = ['Taipei Sans TC Beta'] plt.rcParams['axes.unicode_minus'] = False plt.style.use('dark_background') plt.rcParams.update([ ('axes.edgecolor', 'white'), ('axes.linewidth', 1.5), ('axes.labelsize', 'large'), ('axes.labelweight', 'semibold'), ('axes.grid', True), ('axes.grid.axis', 'y'), ('grid.linewidth', 0.4), ('lines.linewidth', 2.0), ('font.weight', 'medium'), ('font.size', 10.0), ]) plt.rcParams.update({ 'axes.facecolor': '#0f0f10', 'grid.linestyle': '-', 'grid.color': '#a0a0a0', }) def clear(self): for ax in [self.k, self.trend, self.k_trend]: if ax is not None: ax.remove() self._fig.clear() # 執行 def pack(self): self.canvas.draw() self.canvas.get_tk_widget().focus_force() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
class Main(): def __init__(self): self.thread_handler = thread_handler.ThreadHandler() self.temperature_control = TC.TemperatureControl() self.ph_control = PHC.PHControl() self.pressure_control = PC.PressureControl() self.co2_control = CC.Co2Control() self.reactor = reactor.reactor() self.thermocouple = TCS.thermocouple() self.phsensor = PHS.phsensor() self.pressure_sensor = PS.SensorPressure() self.co2_sensor = CS.SensorCo2() self.running = False self.shutting_down = False self.update_delay = 250 self.should_update_setpoint = False self.should_update_spinbox = False def shut_down(self): """ Stop all running threads before stopping main thread """ self.m.after_cancel(self.window_update) self.window_update = None self.temperature_control.stop() self.ph_control.stop() self.pressure_control.stop() self.co2_control.stop() self.reactor.stop() self.thread_handler.stop_threads() self.running = False self.m.quit() def start_drawing(self): ''' Root ''' self.m = tk.Tk(className='Bioreactor Simulator') self.m.title("Bioreactor Simulator") self.m.geometry("800x600") self.m['background'] = 'white' ''' Menu ''' self.menu = tk.Menu(self.m) self.m.config(menu=self.menu) ''' File - Reset and Exit''' self.menu_file = tk.Menu(self.menu) self.menu.add_cascade(label='File', menu=self.menu_file) self.menu_file.add_command(label='Reset', command=self.on_reset) self.menu_file.add_separator() self.menu_file.add_command(label='Exit', command=self.on_closing) ''' Help - About''' self.menu_help = tk.Menu(self.menu) self.menu.add_cascade(label='Help', menu=self.menu_help) self.menu_help.add_command(label='About', command=self.show_about) ''' Canvas, used for drawing matplotlib plot ''' canvas = tk.Canvas(self.m, width=800, height=600) canvas.pack(side=tk.LEFT) ''' Matplotlib plot ''' figure = plt.figure(figsize=(6, 5), dpi=100) self.ax = figure.add_subplot(111) self.plot_canvas = FigureCanvasTkAgg(figure, master=canvas) self.plot_canvas.get_tk_widget().pack() ''' Controls frame, contains three sections: Setpoint control - Allows PID setpoints to be changed Effector selection - Allows plotted effector to be changed Labels for current values - Display current values from PIDs''' frame_controls = tk.Frame(self.m, width=200, height=200) frame_controls.pack(side=tk.RIGHT) ''' Setpoint control ''' frame_setpoint = tk.Frame(frame_controls, width=200, height=200) frame_setpoint.pack(pady=20) lbl_setpoint = tk.Label(frame_setpoint, text="Setpoint:") lbl_setpoint.pack() self.spbx_setpoint = tk.Spinbox(frame_setpoint) self.spbx_setpoint.pack(side=tk.LEFT) btn_setpoint = tk.Button(frame_setpoint, text='Update', command=self.on_setpoint_changed) btn_setpoint.pack(side=tk.RIGHT) ''' Effector selection ''' frame_plot_select = tk.Frame(frame_controls, width=200, height=200) frame_plot_select.pack(pady=20) lbl_plot_select = tk.Label(frame_plot_select, text="Plot Shown:", justify=tk.LEFT) lbl_plot_select.pack() self.selected_plot = tk.IntVar(self.m) radbtn_temp = tk.Radiobutton(frame_plot_select, text="Temperature", variable=self.selected_plot, value=0, command=self.on_plot_source_changed, width=100, indicatoron=0) radbtn_temp.pack() radbtn_ph = tk.Radiobutton(frame_plot_select, text="pH", variable=self.selected_plot, value=1, command=self.on_plot_source_changed, width=100, indicatoron=0) radbtn_ph.pack() radbtn_pressure = tk.Radiobutton(frame_plot_select, text="Pressure", variable=self.selected_plot, value=2, command=self.on_plot_source_changed, width=100, indicatoron=0) radbtn_pressure.pack() radbtn_co2 = tk.Radiobutton(frame_plot_select, text="CO2", variable=self.selected_plot, value=3, command=self.on_plot_source_changed, width=100, indicatoron=0) radbtn_co2.pack() ''' Labels for current values ''' frame_curr_vals = tk.Frame(frame_controls, width=200, height=200) frame_curr_vals.pack(pady=20) ''' Label - Temperature ''' frame_lbl_temp = tk.Frame(frame_curr_vals, width=200, height=100) frame_lbl_temp.pack() label_temp = tk.Label(frame_lbl_temp, text="Temperature (\xb0C):", justify=tk.LEFT) label_temp.pack(side=tk.LEFT) self.lbl_temp = tk.Label(frame_lbl_temp, text="0", justify=tk.LEFT) self.lbl_temp.pack(side=tk.RIGHT) ''' Label - pH ''' frame_lbl_ph = tk.Frame(frame_curr_vals, width=200, height=100) frame_lbl_ph.pack() lbl_ph = tk.Label(frame_lbl_ph, text="pH:", justify=tk.LEFT) lbl_ph.pack(side=tk.LEFT) self.lbl_ph = tk.Label(frame_lbl_ph, text="0", justify=tk.LEFT) self.lbl_ph.pack(side=tk.RIGHT) ''' Label - Pressure ''' frame_lbl_pressure = tk.Frame(frame_curr_vals, width=200, height=100) frame_lbl_pressure.pack() lbl_pressure = tk.Label(frame_lbl_pressure, text="Pressure (bar):", justify=tk.LEFT) lbl_pressure.pack(side=tk.LEFT) self.lbl_pressure = tk.Label(frame_lbl_pressure, text="0", justify=tk.LEFT) self.lbl_pressure.pack(side=tk.RIGHT) ''' Label - CO2 ''' frame_lbl_co2 = tk.Frame(frame_curr_vals, width=200, height=100) frame_lbl_co2.pack() lbl_co2 = tk.Label(frame_lbl_co2, text="CO2 (%):", justify=tk.LEFT) lbl_co2.pack(side=tk.LEFT) self.lbl_co2 = tk.Label(frame_lbl_co2, text="0", justify=tk.LEFT) self.lbl_co2.pack(side=tk.RIGHT) ''' Call the gui_update function once, after set time has passed ''' self.window_update = self.m.after(self.update_delay, self.update_gui) ''' Set up window functions ''' self.m.protocol("WM_DELETE_WINDOW", self.on_closing) ''' Start main loop (do this last) ''' self.m.mainloop() def on_plot_source_changed(self): ''' When changing the plot source, schedule spinbox to be updated ''' self.should_update_spinbox = True def on_setpoint_changed(self): ''' When changing setpoint, schedule update for draw call ''' self.should_update_setpoint = True def on_reset(self): ''' When reset uption is selcted, reset effectors ''' self.temperature_control.reset() self.ph_control.reset() self.pressure_control.reset() self.co2_control.reset() def on_closing(self): self.shut_down() def show_about(self): message_to_show = """Credits: Calum MacRobert Mirrin Gillespie Natasha Sutherland Stefan Olsson""" self.msgbx_about = tk.messagebox.Message(self.m) self.msgbx_about.show(title="About", message=message_to_show) def draw_plot(self): ''' Draw selected plot on canvas from latest effector values''' if self.selected_plot.get() == 0: effector = self.temperature_control elif self.selected_plot.get() == 1: effector = self.ph_control elif self.selected_plot.get() == 2: effector = self.pressure_control elif self.selected_plot.get() == 3: effector = self.co2_control if (self.should_update_setpoint == True): ''' Update setpoint if value is valid ''' new_setpoint = float(self.spbx_setpoint.get()) if (new_setpoint <= effector.upper_range and new_setpoint >= effector.lower_range): effector.set_setpoint(new_setpoint) self.spbx_setpoint.config(background="White") else: self.spbx_setpoint.config(background="Red") self.should_update_setpoint = False setpoint = effector.get_setpoint() lower_range = effector.lower_range upper_range = effector.upper_range lower_domain = effector.lower_domain upper_domain = effector.upper_domain self.spbx_setpoint.config(from_=lower_range, to=upper_range) if (self.should_update_spinbox == True): ''' Update spinbox after switching plot''' self.spbx_setpoint.delete(0, 'end') self.spbx_setpoint.insert(0, setpoint) self.should_update_spinbox = False self.ax.clear() self.ax.plot(effector.get_x(), effector.get_y()) self.ax.hlines(setpoint, lower_domain, upper_domain, 'C1', 'dashed') plt.xlim(lower_domain, upper_domain) plt.ylim(lower_range, upper_range) self.ax.set_title(effector.get_title()) self.ax.set_ylabel(effector.get_y_label()) self.ax.set_xlabel("Time (s)") self.plot_canvas.draw_idle() def update_gui(self): ''' Update GUI, refreshing plots ''' self.draw_plot() self.lbl_temp.config( text=str(round(self.temperature_control.get_current_value(), 3))) self.lbl_ph.config( text=str(round(self.ph_control.get_current_value(), 1))) self.lbl_pressure.config( text=str(round(self.pressure_control.get_current_value(), 1))) self.lbl_co2.config( text=str(round(self.co2_control.get_current_value(), 1))) ''' Schedule update function again''' self.window_update = self.m.after(self.update_delay, self.update_gui) def update_reactor(self): ''' Grabs values from reactor, passes them to places ''' self.thermocouple.set_sensor_value(self.reactor.get_temperature()) #self.temperature_control.set_current_value(self.thermocouple.get_sensor_value()) self.reactor.set_peltier_temp( self.temperature_control.get_current_value()) self.phsensor.set_sensor_value(self.reactor.get_ph()) #self.ph_control.set_current_value(self.phsensor.get_sensor_value()) self.reactor.set_ph_input(self.ph_control.get_current_value()) self.pressure_sensor.set_sensor_value(self.reactor.get_pressure()) #self.pressure_control.set_current_value(self.pressure_sensor.get_sensor_value()) self.reactor.set_pressure_input( self.pressure_control.get_current_value()) self.co2_sensor.set_sensor_value(self.reactor.get_co2()) #self.co2_control.set_current_value(self.co2_sensor.get_sensor_value()) self.reactor.set_co2_input(self.co2_control.get_current_value()) def main(self): ''' Main loop starts threads for window and effectors then continually runs own update function Currently waiting 1 second between updates, to aid debugging ''' self.running = True self.thread_handler.start_thread("temperaturecontrol", self.temperature_control.start) self.thread_handler.start_thread("PHcontroler", self.ph_control.start) self.thread_handler.start_thread("PressureControler", self.pressure_control.start) self.thread_handler.start_thread("CO2 Controler", self.co2_control.start) self.thread_handler.start_thread("reactor", self.reactor.start) self.thread_handler.start_thread("window", self.start_drawing) while (self.running == True): time.sleep(1) # Delay when polling, mainly for debugging self.update_reactor() self.shutting_down = True while (self.shutting_down == True): ''' Check all other threaded processes have stopped ''' if (self.temperature_control.get_running() == False and self.ph_control.get_running() == False and self.pressure_control.get_running() == False and self.co2_control.get_running() == False and self.reactor.get_running() == False): self.shutting_down = False print("Main - Shutdown complete")
class matplotlibSwitchGraphs: def __init__(self, master): self.master = master self.frame = Frame(self.master) self.fig, self.ax, self.toolbar = config_plot() self.lanes = ['r', 'g', 'b', 'y'] self.lane_idx = 0 self.canvas = FigureCanvasTkAgg(self.fig, self.master) self.config_window() self.frame.pack(expand=YES, fill=BOTH) self.epsilon = 7 self.active_point = None self.last_point = -1 self.last_point_reference = None self.alpha = 0.8 self.xs = [] self.ys = [] self.categories = [] self.line = None self.point_references = [] self.save_dir = 'annotations' self.image_paths = None self.current_image = -1 self.init_save_dir() def config_window(self): self.canvas.mpl_connect("key_press_event", self.on_key_press) self.canvas.mpl_connect('button_press_event', self.on_click) self.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback) self.canvas.mpl_connect('button_release_event', self.button_release_callback) toolbar = NavigationToolbar2Tk(self.canvas, self.master) toolbar.update() self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1) self.file_button = Button(self.master, text="Open", command=self.openfile) self.file_button.pack(side=RIGHT) self.button_image = Button(self.master, text="Next Image", command=self.load_image) self.button_image.pack(side=RIGHT) self.lane_switch = Button(self.master, text="Switch Lane", command=self.switch_lane) self.lane_switch.pack(side=RIGHT) self.save_button = Button(self.master, text="Save Annotation", command=self.save_annotation) self.save_button.pack(side=RIGHT) self.ax.set(title=self.lanes[self.lane_idx]) def on_key_press(self, event): print("you pressed {}".format(event.key)) def openfile(self): self.image_paths_file = filedialog.askopenfilename() with open(self.image_paths_file, 'r') as file: self.image_paths = file.readlines() for path in range(len(self.image_paths)): self.image_paths[path] = self.image_paths[path].replace('\n', '') def on_click(self, event): ret = False if not event.inaxes or self.canvas.toolbar._lastCursor in [3, 2]: return if len(self.xs) > 0: ret, self.active_point = self.get_ind_under_point(event) if ret: self.last_point = self.active_point self.highlight_active_point() if ret or event.button == 3: if event.button == 3 and ret: self.remove_active_point() self.last_point -= 1 if len(self.xs) > 0: self.highlight_active_point() return idx = self.last_point + 1 if self.line: self.line.remove() self.line = None self.xs.insert(idx, event.xdata) self.ys.insert(idx, event.ydata) self.categories.insert(idx, self.lanes[self.lane_idx]) point_reference = self.ax.plot(event.xdata, event.ydata, self.lanes[self.lane_idx] + 'o', alpha=self.alpha) self.point_references.insert(idx, point_reference[0]) self.draw_line(category=self.lanes[self.lane_idx]) self.last_point += 1 self.highlight_active_point() self.canvas.draw_idle() def highlight_active_point(self): if self.last_point_reference is not None: self.last_point_reference.remove() self.last_point_reference = self.ax.plot(self.xs[self.last_point], self.ys[self.last_point], 'ko', alpha=self.alpha)[0] def load_image(self): if self.image_paths == None: self.openfile() self.save_annotation() self.reset_annotation() self.ax.clear() self.current_image = (self.current_image + 1) % len(self.image_paths) img = cv2.imread(self.image_paths[self.current_image])[:, :, (2, 1, 0)] self.image = img self.ax.imshow(img) self.load_annotation() self.ax.set(title=self.lanes[self.lane_idx]) self.canvas.draw() def reset_annotation(self): self.active_point = None self.last_point = -1 self.last_point_reference = None self.xs = [] self.ys = [] self.categories = [] self.line = None self.point_references = [] def save_annotation(self): '''saves annotations as 3 x n_points''' if len(self.xs) > 0: annotations = np.vstack([self.xs, self.ys, self.categories]) filename = os.path.basename( self.image_paths[self.current_image]).split('.')[0] np.save(f'{self.save_dir}/{filename}', annotations) return True def init_save_dir(self): if not os.path.exists(self.save_dir): os.mkdir(self.save_dir) def load_annotation(self): filename = os.path.basename( self.image_paths[self.current_image]).split('.')[0] if os.path.exists(f'{self.save_dir}/{filename}.npy'): xs, ys, categories = np.load(f'{self.save_dir}/{filename}.npy') self.xs, self.ys, self.categories = list( xs.astype('float32')), list( ys.astype('float32')), list(categories) for point in range(len(xs)): point_resference = self.ax.plot(self.xs[point], self.ys[point], f'{self.categories[point]}o', alpha=self.alpha)[0] self.point_references.append(point_resference) self.last_point = 0 self.highlight_active_point() def _quit(self): self.master.quit() # stops mainloop def switch_lane(self): self.lane_idx = (self.lane_idx + 1) % len(self.lanes) self.ax.set(title=self.lanes[self.lane_idx]) self.canvas.draw_idle() def get_ind_under_point(self, event): '''get the index of the vertex under point if within epsilon tolerance''' is_available = True t = self.ax.transData.inverted() tinv = self.ax.transData xy = t.transform([event.x, event.y]) x, yvals = np.array(self.xs), np.array(self.ys) xr = np.reshape(x, (np.shape(x)[0], 1)) yr = np.reshape(yvals, (np.shape(yvals)[0], 1)) xy_vals = np.append(xr, yr, 1) xyt = tinv.transform(xy_vals) xt, yt = xyt[:, 0], xyt[:, 1] d = np.hypot(xt - event.x, yt - event.y) indseq, = np.nonzero(d == d.min()) ind = indseq[0] if d[ind] >= self.epsilon: is_available = False return is_available, ind def motion_notify_callback(self, event): if self.active_point is None: return if event.inaxes is None or event.button != 1: return self.ys[self.active_point] = event.ydata self.xs[self.active_point] = event.xdata self.update_point() self.highlight_active_point() self.canvas.draw_idle() def button_release_callback(self, event): if event.button == 1: self.active_point = None self.canvas.draw_idle() def remove_active_point(self): category = self.categories[self.active_point] if self.line: self.line.remove() self.line = None if self.active_point is not None: self.point_references[self.active_point].remove() self.point_references.pop(self.active_point) self.xs.pop(self.active_point) self.ys.pop(self.active_point) self.categories.pop(self.active_point) self.active_point = None self.draw_line(category) self.canvas.draw_idle() def update_point(self): self.point_references[self.active_point].remove() if self.line: self.line.remove() new_point_reference = self.ax.plot( self.xs[self.active_point], self.ys[self.active_point], f'{self.categories[self.active_point]}o', alpha=self.alpha) self.point_references[self.active_point] = new_point_reference[0] self.draw_line() def draw_line(self, category=None): if category is None: category = self.categories[self.active_point] if len(self.xs) > 0: xnp, ynp, cats_np = np.array(self.xs), np.array(self.ys), np.array( self.categories) xnp = xnp[cats_np == category] ynp = ynp[cats_np == category] self.line = self.ax.plot(xnp, ynp, f'{category}-', alpha=self.alpha)[0]
class Screen(Frame): def __init__(self, master, locations, debug=False, debug_update=False, debug_update2=False, debug_netatmo=False, debug_nowcast=False, debug_forecast=False, test_fail_netatmo=False, test_fail_forecast=False, test_fail_nowcast=False, updtime=300000, timeout_netatmo=5, timeout_nowcast=4, timeout_forecast=5): Frame.__init__(self, master) # Initialize self.master = master self.loc_index = 0 self.locations = locations self.location = self.locations[self.loc_index] self.days = 5 self.debug = debug self.debug_update = debug_update self.debug_update2 = debug_update2 self.debug_netatmo = debug_netatmo self.debug_nowcast = debug_nowcast self.debug_forecast = debug_forecast self.test_fail_netatmo = test_fail_netatmo self.test_fail_forecast = test_fail_forecast self.test_fail_nowcast = test_fail_nowcast self.updtime = updtime self.timeout_netatmo = timeout_netatmo self.timeout_nowcast = timeout_nowcast self.timeout_forecast = timeout_forecast # Raspberry pi has 800x480 pixels # Set fullscreen self.pad = 1 self._geom = '200x200+0+0' # self.master.geometry("{0}x{1}+0+0".format( # self.master.winfo_screenwidth()-self.pad, self.master.winfo_screenheight()-self.pad)) self.master.geometry("{0}x{1}+0+0".format(800, 480)) self.master.bind('<Escape>', self.toggle_geom) self.master.bind("<Button-1>", self.change_location) self.master.bind("<Button-3>", self.quit) self.master.wm_attributes('-type', 'splash') master.configure(background='white') screenwidth = self.master.winfo_screenwidth() screenheight = self.master.winfo_screenheight() if debug: print(screenwidth) print(screenheight) self.times = [] self.dts = [] self.indoor_station = None self.netatmo_updated = None self.indoor_temp = None self.indoor_pressure = None self.indoor_co2 = None self.outdoor_station = None self.netatmo_outdoor_updated = None self.outdoor_temp = None self.outdoor_humidity = None self.rain1h = None self.vars = ["temperature", "windDirection", "windSpeed", "windGust", "areaMaxWindSpeed", "humidity", "pressure", "cloudiness", "fog", "lowClouds", "mediumClouds", "highClouds", "temperatureProbability", "windProbability", "dewpointTemperature"] self.netatmo = Canvas(self.master, bg="white", width=380, height=150) self.netatmo_outdoor = Canvas(self.master, bg="white", width=380, height=130) self.time1 = '' self.clock = Label(self.master, font=('times', 60, 'bold'), bg='white') my_dpi = 80 sthisfig = Figure(figsize=(int(float(400)/float(my_dpi)), int(float(150)/float(my_dpi))), dpi=my_dpi) sthisfig.patch.set_facecolor('white') self.sthisplot = sthisfig.add_subplot(111) sthisplotcanvas = FigureCanvasTkAgg(sthisfig, master=self.master) sthisplotcanvas.draw() self.sthisplot.set_visible(False) self.bottomfig = Figure(figsize=(int(float(800)/float(my_dpi)), int(float(200)/float(my_dpi))), dpi=my_dpi) self.bottomfig.patch.set_facecolor('white') gs = gridspec.GridSpec(1, 2, width_ratios=[1, 3]) self.nowcast = self.bottomfig.add_subplot(gs[0]) self.forecast = self.bottomfig.add_subplot(gs[1]) # a tk.DrawingArea self.bottomplots = FigureCanvasTkAgg(self.bottomfig, master=self.master) self.bottomplots.draw() self.netatmo.grid(row=0, column=0) sthisplotcanvas.get_tk_widget().grid(row=0, column=1) sthisplotcanvas._tkcanvas.grid(row=0, column=1) self.netatmo_outdoor.grid(row=1, column=0) self.clock.grid(row=1, column=1) self.bottomplots.get_tk_widget().grid(row=2, columnspan=2) self.bottomplots._tkcanvas.grid(row=2, columnspan=2) self.master.grid_columnconfigure(0, weight=1, uniform="group1") self.master.grid_columnconfigure(1, weight=1, uniform="group1") self.master.grid_rowconfigure(0, weight=1) self.test_increase = 0 self.update() # start the update loop def quit(self, event): Frame.quit(self) def change_location(self, event): self.loc_index = self.loc_index + 1 if self.loc_index >= len(self.locations): self.loc_index = 0 self.location = self.locations[self.loc_index] if self.debug: print("Change location") self.location.print_location() # Clear canvas elements if hasattr(self, "indoor_station"): self.netatmo.delete(self.indoor_station) if hasattr(self, "netatmo_updated"): self.netatmo.delete(self.netatmo_updated) if hasattr(self, "indoor_temp"): self.netatmo.delete(self.indoor_temp) if hasattr(self, "indoor_pressure"): self.netatmo.delete(self.indoor_pressure) if hasattr(self, "indoor_co2"): self.netatmo.delete(self.indoor_co2) if hasattr(self, "outdoor_station"): self.netatmo_outdoor.delete(self.outdoor_station) if hasattr(self, "netatmo_outdoor_updated"): self.netatmo_outdoor.delete(self.netatmo_outdoor_updated) if hasattr(self, "outdoor_temp"): self.netatmo_outdoor.delete(self.outdoor_temp) if hasattr(self, "outdoor_humidity"): self.netatmo_outdoor.delete(self.outdoor_humidity) if hasattr(self, "rain1h"): self.netatmo_outdoor.delete(self.rain1h) if hasattr(self, "nowcast"): self.nowcast.clear() if hasattr(self, "forecast"): self.forecast.clear() self.update() def toggle_geom(self, event): geom = self.master.winfo_geometry() if debug: print(geom, self._geom) self.master.geometry(self._geom) self._geom = geom def find_x_center(self, canvas, item): if debug: print(self.master.winfo_screenwidth() - self.pad) return (self.master.winfo_screenwidth() - self.pad) / 8 def set_time_dimension(self, now, hours): self.times = [] self.dts = [] for t in range(0, hours): self.times.append(t) self.dts.append(now+timedelta(hours=t)) def get_time_indices(self, dts, values_in=None): if values_in is not None and len(dts) != len(values_in): raise Exception("Mismatch in length: "+str(len(dts))+" != "+str(len(values_in))) indices = [] values = [] j = 0 for dt in dts: for t in range(0, len(self.dts)): if dt == self.dts[t]: indices.append(t) if values_in is not None: values.append(values_in[j] + self.test_increase) j = j + 1 indices = np.asarray(indices) values = np.asarray(values) if values_in is not None: return indices, values else: return indices def update(self): # self.testIncrease=self.testIncrease-1 if self.debug_update: print(datetime.now()) self.tick() self.days = 5 now = datetime.utcnow() now = now.replace(second=0, minute=0, microsecond=0) self.set_time_dimension(now, self.days*24) ################################################################### # Netatmo ################################################################### indoor_values = None outdoor_values = None rain_values = None test_fail_netatmo = False if self.debug_update and self.test_fail_netatmo: test_fail_netatmo = True try: indoor_values, outdoor_values, rain_values = get_measurement(self.location, debug=self.debug_netatmo, test_fail_netatmo=test_fail_netatmo) except: pass if indoor_values is not None and outdoor_values is not None and rain_values is not None: # if self.debug: # print(indoor_values) # print(outdoor_values) # print(rain_values) # Inddor label = str(self.location.name) + " (inne)" len_label = len(label) x_pos = int((len_label * 8) * 0.5) if hasattr(self, "indoor_station"): self.netatmo.delete(self.indoor_station) self.indoor_station = self.netatmo.create_text(x_pos, 12, text=label, font=('verdana', 10)) updated = "Oppdatert: NA" if "time_utc" in indoor_values: updated = "Oppdatert: " + datetime.fromtimestamp(indoor_values["time_utc"], pytz.timezone('Europe/Amsterdam')).strftime("%H:%M") if hasattr(self, 'netatmo_updated'): self.netatmo.delete(self.netatmo_updated) self.netatmo_updated = self.netatmo.create_text(300, 10, text=updated, font=('verdana', 10)) # Temp if hasattr(self, 'indoor_temp'): self.netatmo.delete(self.indoor_temp) temp = "NA" if "Temperature" in indoor_values: temp = indoor_values["Temperature"] self.indoor_temp = self.netatmo.create_text(60, 40, text=self.temp_text(temp), fill=self.temp_color(temp), font=('verdana', 20)) # Pressure if hasattr(self, 'indoor_pressure'): self.netatmo.delete(self.indoor_pressure) pres = "NA" if "Pressure" in indoor_values: pres = "{0:.0f}".format(round(float(indoor_values["Pressure"]), 0))+' mb' self.indoor_pressure = self.netatmo.create_text(45, 90, text=pres, fill="black", font=('verdana', 12)) # CO2 if hasattr(self, 'indoor_co2'): self.netatmo.delete(self.indoor_co2) co2 = "NA" if "CO2" in indoor_values: co2 = str(indoor_values["CO2"]) self.indoor_co2 = self.netatmo.create_text(65, 120, text='co2: '+co2+'ppm', fill="black", font=('verdana', 12)) ####################### # Outdoor ####################### label = str(self.location.name) + " (ute)" len_label = len(label) x_pos = int((len_label * 8) * 0.5) if hasattr(self, "outdoor_station"): self.netatmo_outdoor.delete(self.outdoor_station) self.outdoor_station = self.netatmo_outdoor.create_text(x_pos, 12, text=label, font=('verdana', 10)) updated = "Oppdatert: NA" if "time_utc" in outdoor_values: updated = "Oppdatert: " + datetime.fromtimestamp(outdoor_values["time_utc"], pytz.timezone('Europe/Amsterdam')).strftime("%H:%M") if hasattr(self, 'netatmo_outdoor_updated'): self.netatmo_outdoor.delete(self.netatmo_outdoor_updated) self.netatmo_outdoor_updated = self.netatmo_outdoor.create_text(300, 12, text=updated, font=('verdana', 10)) if hasattr(self, 'outdoor_temp'): self.netatmo_outdoor.delete(self.outdoor_temp) temp = "NA" if "Temperature" in outdoor_values: temp = outdoor_values["Temperature"] self.outdoor_temp = self.netatmo_outdoor.create_text(235, 75, text=self.temp_text(temp), fill=self.temp_color(temp), font=('verdana', 60)) # Humidity if hasattr(self, 'outdoor_humidity'): self.netatmo_outdoor.delete(self.outdoor_humidity) hum = "NA" if "Humidity" in outdoor_values: hum = str(outdoor_values["Humidity"]) self.outdoor_humidity = self.netatmo_outdoor.create_text(40, 90, text=hum + '%', fill="black", font=('verdana', 15)) # Rain if hasattr(self, 'rain1h'): self.netatmo_outdoor.delete(self.rain1h) rain1h = "" if "sum_rain_1" in rain_values: rain1h = "{0:.1f}".format(round(float(rain_values["sum_rain_1"]), 1))+'mm/h' self.rain1h = self.netatmo_outdoor.create_text(60, 120, text=rain1h, font=('verdana', 15)) if self.debug_update: print("Updated netatmo") else: print("Can not update netatmo") ########################################################### # Nowcast ########################################################### minutes = None values = None test_fail_nowcast = False if self.debug_update and self.test_fail_nowcast: test_fail_nowcast = True try: minutes, values = get_nowcast(self.location, debug=self.debug_nowcast, timeout_nowcast=self.timeout_nowcast, test_fail_nowcast=test_fail_nowcast) except: pass self.nowcast.clear() if minutes is not None and values is not None: ticks = [0, 15, 30, 45, 60, 75, 90] self.nowcast.axes.get_xaxis().set_ticks(ticks) if len(values) > 0: lines = self.nowcast.plot(minutes, values) lines[0].set_ydata(values) self.nowcast.set_ylim(bottom=0., top=max(values)+0.2) if max(values) > 0: self.nowcast.fill_between(minutes, 0, values) if self.debug_update: print("Updated nowcast") else: print("Could not update nowcast") ############################################################################### # Location forecast ############################################################################### acc_vars1h = None other_vars = None test_fail_forecast = False if self.debug_update and self.test_fail_forecast: test_fail_forecast = True try: acc_vars1h, other_vars, acc_vars2h, acc_vars3h, acc_vars6h = \ get_location_forecast(self.location, self.vars, debug=self.debug_forecast, timeout_forecast=self.timeout_forecast, test_fail_forecast=test_fail_forecast) except: pass if acc_vars1h is not None and other_vars is not None: # if self.debug: # print(acc_vars1h) precipitation = [] times = [] var = "precipitation" for time in sorted(acc_vars1h): # if self.debug: # print(time, var, acc_vars1h[time]) times.append(time) precipitation.append(acc_vars1h[time][var]["value"]) prec_indices, precipitation = self.get_time_indices(times, precipitation) temperature = [] windspeed = [] times = [] for time in sorted(other_vars): var = "temperature" times.append(time) temperature.append(float(other_vars[time][var]["value"])) var = "windSpeed" windspeed.append(float(other_vars[time][var]["mps"])) temp_indices, temperature = self.get_time_indices(times, temperature) wind_indices, windspeed = self.get_time_indices(times, windspeed) c = ['r' if t > 0 else 'b' for t in temperature] lines = [((x0, y0), (x1, y1)) for x0, y0, x1, y1 in zip(temp_indices[:-1], temperature[:-1], temp_indices[1:], temperature[1:])] colored_lines = LineCollection(lines, colors=c, linewidths=(2,)) self.forecast.clear() self.forecast.set_ylim(bottom=np.min(temperature) - 1, top=np.max(temperature) + 1) self.forecast.add_collection(colored_lines) if not hasattr(self, "axP"): self.axP = self.forecast.twinx() self.axP.clear() self.axP.bar(prec_indices, height=precipitation, width=1) self.axP.set_ylim(bottom=0, top=max(np.maximum(precipitation, 2))) line_wind = self.forecast.plot(wind_indices, windspeed, color="grey") today = now.replace(hour=0, second=0, minute=0, microsecond=0) ticks = [] labels = [] for d in range(1, self.days+1): ticks.append(today+timedelta(days=d)) labels.append((today+timedelta(days=d)).strftime("%d/%m")) tick_positions = self.get_time_indices(ticks) self.forecast.axes.set_xticks(ticks=tick_positions, minor=False) self.forecast.axes.set_xticklabels(labels, fontdict=None, minor=False) line_wind[0].set_ydata(windspeed) if self.debug_update: print("Updated forecast") else: print("Can not update location forecast") self.bottomplots.draw_idle() if self.debug_update: if not self.debug_update2: self.debug_update = False else: if self.debug_update2: self.debug_update = True if self.debug_update2: self.debug_update2 = False self.after(self.updtime, self.update) # ask the mainloop to call this method again in ms def tick(self): # get the current local time from the PC time2 = strftime('%H:%M:%S') # if time string has changed, update it if time2 != self.time1: time1 = time2 self.clock.config(text=time2) # calls itself every 200 milliseconds # to update the time display as needed # could use >200 ms, but display gets jerky self.clock.after(200, self.tick) @staticmethod def temp_color(value): color = "red" if value != "NA" and value < 0: color = "blue" return color @staticmethod def temp_text(value): if value != "NA": # txt = "%s °C" % (value) txt = "%s" % value else: txt = "NA" return txt