class BokehButton(BokehControl): def getBokehComponent(self): self.bk = Button(label=self._settings['label']) self.bk.on_event(ButtonClick, self.handle_click) return self.bk def handle_click(self, event): raise Exception("Should not be creating a general button")
def create_disp(): ##### 各画面要素作成 # テーブル作成 df_columns = target_data.columns.tolist() datatable_source = ColumnDataSource(data=target_data) table_columns = create_datatable_columns(df_columns) data_table = DataTable(source=datatable_source, selectable=True, columns=table_columns, sortable=True) # カラムが変わった時に呼び出す関数リスト column_change_functions = [] # 表示を切り替えるplotリスト visible_plots = [] cm_operation_area, cm_plot_area = create_cm(column_change_functions, visible_plots, datatable_source) # upload button がクリックされた時の処理 def upload_button_callback(event): global target_data global user csv_str = base64.b64decode(csv_input.value) target_data = pd.read_csv(io.BytesIO(csv_str)) df_columns = target_data.columns.tolist() call_column_change(column_change_functions, df_columns) table_columns = create_datatable_columns(df_columns) data_table.columns = table_columns datatable_source.data = target_data data_table.update() try: user.csv_data = target_data.to_json() db.session.commit() except Exception as e: warn = str(e) # csvアップロード実行ボタン upload_button = Button(label="Upload", button_type="success") upload_button.on_event(ButtonClick, upload_button_callback) # ファイル選択ボックス csv_input = FileInput() scatter_operation_area, scatter_plot_area = create_scatter( column_change_functions, visible_plots, datatable_source) # サブオペレーションエリア sub_operation_area = Row(cm_operation_area, scatter_operation_area) operation_area = Column(csv_input, upload_button, sub_operation_area, data_table) graph_area = Column(cm_plot_area, scatter_plot_area) layout_disp = Row(graph_area, operation_area) return layout_disp
def createFigures(self, metadata: Metadata): for i in range(len(metadata.Data.columns)): y1 = metadata.Data[i].astype(float) x1 = np.arange(0, y1.size, 1) plot = figure( tools="", title="Channel[" + str(i) + "] Sampling rate[1/" + str(metadata.Definitions["samplingfreq"]) + "]" + " Muscle names[" + str(metadata.SourceNames) + "]", width=1200, height=350, y_range=(metadata.Data[i].min(), metadata.Data[i].max()), x_range=(0, y1.size), name=str(uuid.uuid1()) # y_axis_type="datetime", Does not make sence to time this really # x_axis_type="datetime", ) plot.xaxis.axis_label = "Ticks[Individual samples]" plot.yaxis.axis_label = str(list(metadata.Units)[0]) plot.add_tools(HelpTool(name=str(i) + "pt" + str(uuid.uuid1()))) plot.add_tools(PanTool(name=str(i) + "pt" + str(uuid.uuid1()))) plot.add_tools(ZoomInTool(name=str(i) + "zit" + str(uuid.uuid1()))) plot.add_tools(ZoomOutTool(name=str(i) + "zot" + str(uuid.uuid1()))) plot.add_tools( BoxSelectTool(name=str(i) + "bst" + str(uuid.uuid1()))) plot.add_tools(ResetTool(name=str(i) + "rt" + str(uuid.uuid1()))) plot.add_tools(SaveTool(name=str(i) + "st" + str(uuid.uuid1()))) plot.line(x1, y1, line_width=1, name=str(i) + str(uuid.uuid1())) plot.scatter( "xvals", "yvals", source=self.DataSources[metadata.Definitions["phasename"] + metadata.Id][i], alpha=0, selection_color="firebrick", selection_line_alpha=0.1, nonselection_fill_alpha=0.0, name=str(uuid.uuid1())) btn = Button(label='Find similarities', button_type='success', width=100, name=str(i) + str(uuid.uuid1())) btn.on_event( ButtonClick, partial(self.beforeClicked, button=btn, graphId=i, metadata=metadata)) self.Buttons.append(btn) self.Figures.append(plot)
def start_program(): # Set up widgets text = TextInput(title="HashTag", placeholder='Write a HashTag') columns = [ 'Today', 'From yesterday', 'Two days ago', 'Three days ago', 'Four days ago', 'Five days ago', 'Six days ago' ] days = Select(title='Days', value='Today', options=columns) button = Button(label="Fetch Data", button_type="success") button1 = Button(label="Refresh Map", button_type="danger", disabled=True) message_box = Div(text="Welcome") # Callback function for running the program when hastag requested def callback(event): if (text.value == ""): layout1.children[0] = display_message( "HashTag should not be Empty") return # Disabled the properties for user utill data is fetched button.disabled = True button.button_type = "danger" sentiment.disabled = True continent.disabled = True button1.disabled = True button1.button_type = "danger" old = 0 if (days.value == "Today"): old = 0 elif (days.value == "From yesterday"): old = 1 elif (days.value == "Two days ago"): old = 2 elif (days.value == "Three days ago"): old = 3 elif (days.value == "Four days ago"): old = 4 elif (days.value == "Five days ago"): old = 5 else: old = 6 #Calling the main function for retriving the data main(hashtag=text.value, days=old, layout=layout1, button=button, sentiment=sentiment, continent=continent, button1=button1) # create_figure function for creating the google map onto the browser with data from output.csv def create_figure(event): conti = continent.value senti = sentiment.value if (conti == "North America"): map_options = GMapOptions(lat=33.465777, lng=-88.369025, map_type="roadmap", zoom=3) elif (conti == "South America"): map_options = GMapOptions(lat=-8.783195, lng=-55.491477, map_type="roadmap", zoom=3) elif (conti == "Africa"): map_options = GMapOptions(lat=-8.783195, lng=34.508523, map_type="roadmap", zoom=3) elif (conti == "Asia"): map_options = GMapOptions(lat=34.047863, lng=100.619655, map_type="roadmap", zoom=3) elif (conti == "Europe"): map_options = GMapOptions(lat=54.525961, lng=15.255119, map_type="roadmap", zoom=3) elif (conti == "Antartica"): map_options = GMapOptions(lat=-82.862752, lng=135.000000, map_type="roadmap", zoom=3) else: map_options = GMapOptions(lat=-25.274398, lng=133.775136, map_type="roadmap", zoom=3) # Calling the Google API Key for displaying google maps p = gmap("AIzaSyCJMprrXTtmUqciVaVgskmHxskLkVjrE6A", map_options, title="World Map", width=950) #Ploting the legends on the map p.circle(None, None, size=5, fill_color="green", fill_alpha=0.7, legend="Positive") p.circle(None, None, size=5, fill_color="yellow", fill_alpha=0.7, legend="Neutral") p.circle(None, None, size=5, fill_color="red", fill_alpha=0.7, legend="Negative") # Load function for extracting data from "output.csv" file def load(data): lat = [] lon = [] with open('output.csv') as csvfile: reader = csv.DictReader(csvfile) for row in reader: x = float(row["longitude"]) y = float(row["latitude"]) z = row["sentiment"] if (z == data): lat.append(y) lon.append(x) data1 = dict(lat=lat, lon=lon) return data1 # pointing the data on Google Maps if (senti == "All"): source = ColumnDataSource(data=load(data="positive")) p.circle(x="lon", y="lat", size=8, fill_color="green", fill_alpha=1.0, source=source) source = ColumnDataSource(data=load(data="negative")) p.circle(x="lon", y="lat", size=8, fill_color="red", fill_alpha=1.0, source=source) source = ColumnDataSource(data=load(data="neutral")) p.circle(x="lon", y="lat", size=8, fill_color="yellow", fill_alpha=1.0, source=source) elif (senti == "Positive"): source = ColumnDataSource(data=load(data="positive")) p.circle(x="lon", y="lat", size=8, fill_color="green", fill_alpha=1.0, source=source) elif (senti == "Negative"): source = ColumnDataSource(data=load(data="negative")) p.circle(x="lon", y="lat", size=8, fill_color="red", fill_alpha=1.0, source=source) else: source = ColumnDataSource(data=load(data="neutral")) p.circle(x="lon", y="lat", size=8, fill_color="yellow", fill_alpha=1.0, source=source) return p #End of function create_figure() #update function for on_change event listener def update(attr, old, new): layout.children[1] = create_figure(event=None) #update1 function for on_click event listener def update1(): layout.children[1] = create_figure(event=None) # Event listner for buttons button.on_event(ButtonClick, callback) button1.on_click(update1) #Set all Parameters for dropdown menus columns = ["All", "Positive", "Neutral", "Negative"] sentiment = Select(title='Sentiment', value='All', options=columns, disabled=True) sentiment.on_change('value', update) continents = [ "North America", "South America", "Africa", "Asia", "Antartica", "Europe", "Australia" ] continent = Select(title='Continents', value='North America', options=continents, disabled=True) continent.on_change('value', update) # Set up layouts and add to document controls = widgetbox([text, days, button, sentiment, continent, button1]) layout1 = column(display_message("Welcome"), controls) layout = row(layout1, create_figure(event=None)) #Drawing widgets onto the browser curdoc().add_root(layout) curdoc().title = "World Map"
'Hermite': { 'drag': [], 'data': [] }, 'Lagrange': {'data': []}, 'Catmull-Rom': {'data': []}, 'Four-Point': {'data': []}, } show_convex_hull = False curve, control, drag, hull = get_data(method) plot = make_plot(curve, control, drag, method) # Holder variable for Drag Eventz drag_event = None # Add Method Selection Dropdown and Handler options = ['B-Spline', 'Hermite Interpolation', 'Hermite Spline', 'Lagrange Interpolation', 'Catmull-Rom Spline', 'Four Point Subdivision'] method_select = Select(value=method, title='Subdivision Method', options=options) method_select.on_change('value', update_plot) # Add Clear Button clear_button = Button(label='Clear') clear_button.on_event(ButtonClick, clear) convex_hull_button = Button(label='Convex Hull') convex_hull_button.on_event(ButtonClick, toggle_convex_hull) curdoc().add_root(row(plot, column(method_select, clear_button, convex_hull_button))) curdoc().title = 'Subdivision Methods Toolbox'
def main() -> None: """メイン処理 Returns: None: None """ # データソースの初期設定 source = ColumnDataSource(data=dict(length=[], width=[])) source.data = {"0": [], "1": []} df = pd.DataFrame() # CSVファイル設定テキストボックス csv_input = TextInput(value="default.csv", title="Input CSV") # 可視化手法選択ラジオボタン method_group = analysis_method() method_radio_group = RadioGroup(labels=list(method_group.keys()), active=0) # グラフ初期設定 p = figure( tools=("pan,box_zoom,lasso_select,box_select,poly_select" ",tap,wheel_zoom,reset,save,zoom_in"), title="Analyze Result", plot_width=1000, plot_height=800, ) p.circle(x="0", y="1", source=source) # データ表示データテーブル data_table = DataTable(source=source, columns=[], width=600, height=500, fit_columns=False) # 色設定項目用選択セレクトボックス def color_select_callback(attr, old, new) -> None: mapper = create_mapper(df, new) p.circle(x="0", y="1", source=source, line_color=mapper, color=mapper) color_select = Select(title="color:", value="0", options=[]) color_select.on_change("value", color_select_callback) # 解析実行ボタン def execute_button_callback_inner(evnet): nonlocal df df = pd.read_csv(csv_input.value, index_col=0) result = method_group[method_radio_group.labels[ method_radio_group.active]](df) source.data = to_source_data_from(df, result) data_table.columns = to_datatable_columns_from(df) mapper = create_mapper(df, df.columns.values[0]) p.circle(x="0", y="1", source=source, line_color=mapper, color=mapper) p.add_tools(create_hover(["ID", df.columns.values[0]])) color_select.options = list(df.columns) execute_button = Button(label="Execute", button_type="success") execute_button.on_event(ButtonClick, execute_button_callback_inner) # レイアウト operation_area = Column(csv_input, method_radio_group, execute_button, color_select, data_table) layout = Row(p, operation_area) curdoc().add_root(layout)
end=2.000, value=0.400, step=0.001, format="0[.]000", ) slider_X_RADIUS.on_change( "value", lambda attr, old, new: slider_callback(attr, old, new)) slider_Y_RADIUS.on_change( "value", lambda attr, old, new: slider_callback(attr, old, new)) # save file savefilename = TextInput(title="Save file as (.csv or .pkl)", placeholder="edited_peaks.csv") button = Button(label="Save", button_type="success") button.on_event(ButtonClick, save_peaks) # call fit_peaks fit_button = Button(label="Fit selected cluster", button_type="primary") radio_button_group = RadioButtonGroup( labels=["PV", "G", "L", "PV_L", "PV_G", "PV_PV", "G_L"], active=0) lineshapes = { 0: "PV", 1: "G", 2: "L", 3: "PV_L", 4: "PV_G", 5: "PV_PV", 6: "G_L" } ls_div = Div( text=
options=x_select_options, value='beatsperminute') y_select_options = unsup_cols.copy() y_select_options.append('ALL') y_select = Select(title='Y-axis feature', options=x_select_options, value='energy') controls = [x_select, y_select] for control in controls: control.on_change('value', lambda attr, old, new: update()) # Cluster Buttons cluster_button = Button(label='Plot inertia', button_type='success') cluster_button.on_event(ButtonClick, calculate_inertia) # KMeans controls data_key_options = df.columns.tolist() data_key_options.append('None') data_key_select_1 = Select(title='Data Key #1', options=data_key_options, value='None') data_key_select_2 = Select(title='Data Key #2', options=data_key_options, value='None') n_cluster_slider = Slider(title='n_clusters=', start=1, end=10, value=3, step=1)
squa = p.quad(top='top', bottom='bottom', left='left', right='right', color="navy", alpha=0.8, source=source) p.xaxis.ticker = [x for x in range(-20, 20)] p.yaxis.ticker = [x for x in range(-20, 20)] circ.visible = False squa.visible = False text_input = TextInput(value="", title="INPUT (only numbers):") circlebutton = Button(label="Circle", button_type="primary") circlebutton.on_event(ButtonClick, circlecallback) squarebutton = Button(label="Square", button_type="primary") squarebutton.on_event(ButtonClick, squarecallback) clearbutton = Button(label="Clear", button_type="warning") clearbutton.on_event(ButtonClick, clearcallback) div2 = Div(text='', width=300, height=100) aa = row([text_input, circlebutton, squarebutton, clearbutton]) bb = column([p, aa, div2]) doc.add_root(bb) show(bb)
def create_scatter(column_change_functions, visible_plots, datatable_source): # 散布図x x_select = Select(title="散布図x:", value="", options=[""]) # 散布図y y_select = Select(title="散布図y:", value="", options=[""]) # 色カラム color_select = Select(title="色カラム:", value="", options=[""]) # テーブルカラムが変わった時に呼ばれる関数 def column_change(columns): x_select.options = columns y_select.options = columns color_select.options = columns column_change_functions.append(column_change) scatter_plot = figure( title="特徴量空間", tools= "zoom_in,wheel_zoom,box_zoom,hover,box_select,poly_select,lasso_select,tap,reset" ) scatter_plot.visible = False visible_plots.append(scatter_plot) scatter_source = ColumnDataSource() def on_scatter_change(self, attr, *callbacks): data = target_data.loc[scatter_source.selected.indices, :] datatable_source.data = data def scatter_callbacks(): global target_data col = color_select.value scatter_source.data = { col: target_data[col], 'legend': [f'{col}_{x}' for x in target_data[col]], 'x': target_data[x_select.value], 'y': target_data[y_select.value] } mapper = linear_cmap(field_name=col, palette=Viridis256, low=target_data[col].min(), high=target_data[col].max()) plot = scatter_plot.circle(x="x", y="y", source=scatter_source, line_color=mapper, color=mapper, legend_field='legend') plot.data_source.selected.on_change('indices', on_scatter_change) scatter_plot.legend.location = "top_right" scatter_plot.legend.click_policy = "hide" scatter_plot.visible = True unvisible_other_plots(scatter_plot, visible_plots) # 散布図作成実行ボタン scatter_button = Button(label="散布図作成", button_type="success") scatter_button.on_event(ButtonClick, scatter_callbacks) # 散布図オペレーションエリア scatter_operation_area = Column(x_select, y_select, color_select, scatter_button) return scatter_operation_area, scatter_plot
def create_cm(column_change_functions, visible_plots, datatable_source): # 正解ラベル label_select = Select(title="正解ラベル:", value="", options=[""]) # 推論ラベル pred_select = Select(title="推論ラベル:", value="", options=[""]) # テーブルカラムが変わった時に呼ばれる関数 def column_change(columns): label_select.options = columns pred_select.options = columns column_change_functions.append(column_change) # 混同行列ヒートマップ confusion_matrix_source = ColumnDataSource(data={}) tooltips = [ ('count', '@count'), ('label', '$y{0}'), ('pred', '$x{0}'), ] hm = figure(title="混同行列", tools="hover", toolbar_location=None, tooltips=tooltips) hm.y_range.flipped = True hm.visible = False visible_plots.append(hm) def cm_callback(): global target_data cm = confusion_matrix(target_data[label_select.value], target_data[pred_select.value]) cm = pd.DataFrame(cm) cm = cm.stack().reset_index().rename( columns={ 'level_0': label_select.value, 'level_1': pred_select.value, 0: 'count' }) confusion_matrix_source.data = cm mapper = LinearColorMapper(palette=Viridis256, low=cm['count'].min(), high=cm['count'].max()) hm.rect(x=pred_select.value, y=label_select.value, source=confusion_matrix_source, width=1, height=1, line_color=None, fill_color=transform('count', mapper)) hm.text(x=pred_select.value, y=label_select.value, text="count", text_font_style="bold", source=confusion_matrix_source, text_align="left", text_baseline="middle") color_bar = ColorBar(color_mapper=mapper, label_standoff=12) hm.add_layout(color_bar, 'right') hm.visible = True unvisible_other_plots(hm, visible_plots) def cm_click_callback(event): label = round(event.y) pred = round(event.x) data = target_data[(target_data[label_select.value] == label) & (target_data[pred_select.value] == pred)] datatable_source.data = data hm.on_event(DoubleTap, cm_click_callback) # 混同行列作成実行ボタン cm_button = Button(label="混同行列作成", button_type="success") cm_button.on_event(ButtonClick, cm_callback) # 混同行列オペレーションエリア cm_operation_area = Column(label_select, pred_select, cm_button) return cm_operation_area, hm
else: #If the number of stations deployed is max, display message print("Max number of stations reached") # #----------------------------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------------------------------------------------- #-------------------------------This allows you to interact with the drone sim button to start the drone simulation----------------------- #----------------------------------------------------------------------------------------------------------------------------------------- # def callbackSimRun(event): eventTrigger(coordList) # #----------------------------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------------------------------------------------- #These plot the new stations and the button to run the simulation p.on_event(DoubleTap, callback) button_widget.on_event(ButtonClick, callbackSimRun) #This sets the layout of the plot layout=Column(p,widgetbox(button_widget)) #This updates the plot to the server curdoc().add_root(layout)
def modify_doc(doc): p1 = figure(plot_width=600, plot_height=500, title='Quantum Tunneling Animation') p1.xaxis.axis_label = 'position (Angstrom)' p1.yaxis.axis_label = 'Amplitude Squared (normalized)' p1.toolbar.logo = None p1.toolbar_location = None r11 = p1.line([], [], legend='Barrier', color=Colorblind[8][5], line_width=2) r12 = p1.line([], [], legend='Wavefunction', color=Colorblind[8][7], line_width=2) p2 = figure(plot_width=400, plot_height=250, title='Normalized wavefunctions at start') p2.xaxis.axis_label = 'position (Angstrom)' p2.yaxis.axis_label = 'Amplitude' p2.toolbar.logo = None p2.toolbar_location = None r21 = p2.line([], [], legend='Barrier', color=Colorblind[8][5]) r22 = p2.line([], [], legend='Magnitude', color=Colorblind[8][7]) r23 = p2.line([], [], legend='Real part', color=Colorblind[8][0]) r24 = p2.line([], [], legend='Imag. part', color=Colorblind[8][6]) p3 = figure(plot_width=400, plot_height=250, title='Normalized wavefunctions at end') p3.xaxis.axis_label = 'position (Angstrom)' p3.yaxis.axis_label = 'Amplitude' p3.toolbar.logo = None p3.toolbar_location = None r31 = p3.line([], [], color=Colorblind[8][5]) r32 = p3.line([], [], color=Colorblind[8][7]) r33 = p3.line([], [], color=Colorblind[8][0]) r34 = p3.line([], [], color=Colorblind[8][6]) barrier_height = Slider(title='Barrier Height (eV)', value=600, start=20, end=1000, step=100) barrier_width = Slider(title='Barrier Width (Angstrom)', value=0.3, start=0.3, end=1.0, step=0.1) electron_energy = Slider(title='Electron Energy (eV)', value=500, start=10, end=900, step=100) psi_spread = Slider(title='Wavefunction Spread (Angstrom)', value=0.8, start=0.3, end=1.0, step=0.1) startbutton = Button(label='Start', button_type='success') textdisp = Div(text='''<b>Note:</b> Wait for simulation to stop before pressing buttons.''') texttitle = Div(text='''<b>QUANTUM TUNNELING</b>''', width=1000) textdesc = Div(text='''This application simulates quantum tunneling of an electron across a potential barrier by solving the Schrodinger's equation using the finite-difference time-domain method. You can change the height and width of the barrier, as well as the energy and spread of the electron to see how it would affect the probability of tunneling.''', width=1000) textrel = Div(text='''Learn more about quantum mechanics especially in the context of quantum computing in <b>ES 170</b>''', width=1000) def run_qt_sim(event): # Reset plots r21.data_source.data['x'] = [] r22.data_source.data['x'] = [] r23.data_source.data['x'] = [] r24.data_source.data['x'] = [] r21.data_source.data['y'] = [] r22.data_source.data['y'] = [] r23.data_source.data['y'] = [] r24.data_source.data['y'] = [] r31.data_source.data['x'] = [] r32.data_source.data['x'] = [] r33.data_source.data['x'] = [] r34.data_source.data['x'] = [] r31.data_source.data['y'] = [] r32.data_source.data['y'] = [] r33.data_source.data['y'] = [] r34.data_source.data['y'] = [] # Get widget values V0 = barrier_height.value bw = barrier_width.value ke = electron_energy.value sig = psi_spread.value # Create Qtunnel object qt = Qtunnel(V0, bw, ke, sig) # Plot initial states r21.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r22.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r23.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r24.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r21.data_source.data['y'] = qt.Vx / np.amax(qt.Vx) r22.data_source.data['y'] = qt.psimag / np.amax(qt.psimaginit) r23.data_source.data['y'] = qt.psir / np.amax(qt.psirinit) r24.data_source.data['y'] = qt.psii / np.amax(qt.psiiinit) r11.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r12.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r11.data_source.data['y'] = qt.Vx / np.amax(qt.Vx) for n in range(qt.tt): qt.fdtd_update() qt.update_plots(r12) # Plot final states r31.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r32.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r33.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r34.data_source.data['x'] = qt.lx / sc.value('Angstrom star') r31.data_source.data['y'] = qt.Vx / np.amax(qt.Vx) r32.data_source.data['y'] = qt.psimag / np.amax(qt.psimaginit) r33.data_source.data['y'] = qt.psir / np.amax(qt.psirinit) r34.data_source.data['y'] = qt.psii / np.amax(qt.psiiinit) # Setup callbacks startbutton.on_event(ButtonClick, run_qt_sim) doc.add_root(column(texttitle, textdesc, row(barrier_height, barrier_width, textdisp), row(electron_energy, psi_spread, startbutton), row(p1, column(p2, p3)), textrel))
class Module(pyl.Model): def startServer(self): print("Starting Server") self.session.loop_until_closed() # run forever def callback(self, event): print("ASDF") self.moduleData["/outputs/keypress"] = ord('q') def initialise(self, simData): #self.server = threading.Thread(target=self.startServer) #self.server.start() #time.sleep(5) self.curdoc = curdoc() self.session = push_session(self.curdoc) data_points = 200 time_step = simData["/simulation/time_step"] self.plot_time = deque() for i in range(data_points): self.plot_time.append((-data_points + i) * time_step) simData["/self/data_to_time"] = self.plot_time simData["/self/data_to_time"] = np.arange(data_points) for monitor in simData["/inputs/monitor"]: #simData["/self/data_to_plot/" + monitor] = deque() simData["/self/data_to_plot/" + monitor] = np.ones(data_points) #for i in range(data_points): # simData["/self/data_to_plot/" + monitor].append(i) #for monitor in simData["/inputs/monitor"]: # simData["/self/source"] = ColumnDataSource(data=dict(x=simData["/self/data_to_time"], y=simData["/self/data_to_plot/" + monitor])) simData["/self/update_plot"] = True simData["/self/updateRate"] = 0.001 # Set up plot # self.plot = figure(plot_height=400, plot_width=400, title="my sine wave", # tools="crosshair,pan,reset,save,wheel_zoom", # #x_range=[0, 4*np.pi], y_range=[-2.5, 2.5]) self.plot = [] for monitor in simData["/inputs/monitor"]: self.plot.append( figure(plot_height=400, plot_width=400, title=monitor, tools="crosshair,pan,reset,save,wheel_zoom")) #x_range=[0, 4*np.pi], y_range=[-2.5, 2.5]) for idx, monitor in enumerate(simData["/inputs/monitor"]): simData["/self/line/" + monitor] = self.plot[idx].line( x=simData["/self/data_to_time"], y=simData["/self/data_to_plot/" + monitor], line_width=3, line_alpha=0.6) #simData["/self/line/" + monitor] = self.plot.line(x=[0], y=[0], line_width=3, line_alpha=0.6) #self.line = self.plot.line(x=simData["/self/data_to_time"], y=simData["/self/data_to_plot/" + monitor], line_width=3, line_alpha=0.6) self.button = Button() self.button.on_event(ButtonClick, self.callback) self.box = widgetbox(self.button) self.PlotLayout = layout(self.plot, self.box) self.session.show(self.PlotLayout) self.t = [] self.y = {} for monitor in simData["/inputs/monitor"]: self.y[monitor] = [] def execute(self, simData): debug("Executing my Model {} Iteration {}".format( self.name, simData["/simulation/iteration"])) iteration = simData["/simulation/iteration"] time_step = simData["/simulation/time_step"] self.t.append(iteration * time_step) for idx, monitor in enumerate(simData["/inputs/monitor"]): self.y[monitor].append(simData["/inputs/signal" + str(idx + 1)]) if (iteration * time_step) % simData["/self/updateRate"] < time_step * 0.1: if (self.button.clicks != 0): print(self.button.clicks) if simData["/self/update_plot"]: for monitor in simData["/inputs/monitor"]: #self.t = np.arange(len(self.y[monitor])) simData["/self/line/" + monitor].data_source.stream( { 'x': self.t, 'y': self.y[monitor] }, 200) self.y[monitor] = [] self.session.force_roundtrip() self.t = []
def modify_doc(doc): p1 = figure(plot_width=500, plot_height=300, title='Histogram of Coin Toss Game simulation for Player 1', tools='', background_fill_color='#fafafa') r1 = p1.quad(top=[], bottom=0, left=[], right=[], fill_color="navy", line_color="white", alpha=0.5) lb1 = Label(x=120, y=120, x_units='screen', y_units='screen', text='', render_mode='css', background_fill_color='white', background_fill_alpha=0.5) lbwinloss1 = Label(x=200, y=90, x_units='screen', y_units='screen', text='', render_mode='css', background_fill_color='white', background_fill_alpha=0.5) p1.y_range.start = 0 p1.add_layout(lb1) p1.add_layout(lbwinloss1) p1.xaxis.axis_label = 'Number of tosses to reach endgame' p1.yaxis.axis_label = 'counts' p1.toolbar.logo = None p2 = figure(plot_width=500, plot_height=300, title='Histogram of Coin Toss Game simulation for Player 2', tools='', background_fill_color='#fafafa') r2 = p2.quad(top=[], bottom=0, left=[], right=[], fill_color="navy", line_color="white", alpha=0.5) lb2 = Label(x=120, y=120, x_units='screen', y_units='screen', text='', render_mode='css', background_fill_color='white', background_fill_alpha=0.5) lbwinloss2 = Label(x=200, y=90, x_units='screen', y_units='screen', text='', render_mode='css', background_fill_color='white', background_fill_alpha=0.5) p2.y_range.start = 0 p2.add_layout(lb2) p2.add_layout(lbwinloss2) p2.xaxis.axis_label = 'Number of tosses to reach endgame' p2.yaxis.axis_label = 'counts' p2.toolbar.logo = None number_of_games = Slider(title='Number of Games', value=500, start=1, end=5000, step=1) endgame1 = TextInput(value="HT", title='Player 1 Endgame:') endgame2 = TextInput(value="HH", title='Player 2 Endgame:') startbutton = Button(label='Start', button_type='success') texttitle = Div( text='''<b>BAYSIAN MIND: SIMULATING A COIN TOSSING GAME</b>''', width=1000) textdesc = Div( text= '''This app simulates a coin tossing game where two players pick a sequence of head/tail occurances. A coin is tossed until the chosen sequences occur and the game ends and the player who picked the endgame sequence that occurs first wins. So, the objective is to chose an endgame that will end the game with the least number of tosses. The app simulates a given number of coin toss games with the chosen endgame sequences. The average number of tosses required to win is computed and its distribution is plotted.''', width=1000) textrel = Div( text= '''Learn more about our Bayesian mind and how it affects technology, ethics, and society in <b>ES 28</b>''', width=1000) textdisp = Div( text= '''<b>Note: </b> Enter a sequence of Capital H's and T's to represent heads and tails, respectively. Please only enter Capitol H and T, entering any other letter will return an error and stop the app. Also, for a fair comparision the players should enter the same number of letters in their sequence''', width=600) def check_winner(c1, c2): if np.mean(c1.counter) < np.mean(c2.counter): lbwinloss1.text = 'You Win!' lbwinloss2.text = 'You lose!' lbwinloss1.text_color = 'green' lbwinloss2.text_color = 'red' else: lbwinloss1.text = 'You Lose!' lbwinloss2.text = 'You Win!' lbwinloss1.text_color = 'red' lbwinloss2.text_color = 'green' # Start the coin tossing game simulation def start_tossing(event): ng = number_of_games.value eg1 = endgame1.value eg2 = endgame2.value c1 = CoinToss(ng, eg1) c1.run() c1.plot_counts(r1, lb1) c2 = CoinToss(ng, eg2) c2.run() c2.plot_counts(r2, lb2) check_winner(c1, c2) # Setup callbacks startbutton.on_event(ButtonClick, start_tossing) # Setup layout and add to document doc.add_root( column(texttitle, textdesc, number_of_games, textdisp, row(endgame1, endgame2), startbutton, row(p1, p2), textrel))
# Button definition and actions def show_dataset(event): # source_table.data = (data_to_fill) # data_table.source.data = data_to_fill #update data update_dataset_lists(event) show_data_curves(event) showDataBtn = Button(label='Show the Sample DataSet', width=360, height=50, button_type="primary") showDataBtn.on_event(ButtonClick, show_dataset) # Add table table_title = Div(text='The dataset is listed here: ') table_output = widgetbox(table_title, data_table) #Add all things in a row param_inst_txt = Div(text='Specific all parameters here along with the dataset.'\ 'Click on \'show dataset\' will reveal a subset of the sample data. ', height = 50) inputs = widgetbox(select, kernelSelect, datasetSelect, width=400) data_table_top_right = widgetbox(data_table, showDataBtn, width=400) # Add illustration on Optimization: param_txt = Div(text='Specify Learning Task',
def modify_doc(doc): # Initializing arrays for plotting def InitPlotArrays(): timepoints.fill(np.nan) poscar1.fill(np.nan) poscar1_est.fill(np.nan) poscar1_meas.fill(np.nan) poscar2.fill(np.nan) car_sep.fill(np.nan) car2_acc.fill(np.nan) poscar2_kf.fill(np.nan) car_sep_kf.fill(np.nan) car2_acc_kf.fill(np.nan) noiserange.fill(np.nan) pdf_proc.fill(np.nan) pdf_meas.fill(np.nan) # Setup plots InitPlotArrays() # Adding legends p1 = figure(plot_width=300, plot_height=120, x_range=[-0.5, 20], y_range=[-1, 5]) colors = ['darkslategray', 'gold', 'crimson'] p1.rect([0.2, 0.2, 0.2], [4, 2, 0], width=1, height=1, color=colors, width_units='data', height_units='data') label1 = Label(x=1, y=3.3, x_units='data', y_units='data', text='Leading Car') label2 = Label(x=1, y=1.3, x_units='data', y_units='data', text='Following Car') label3 = Label(x=1, y=-0.7, x_units='data', y_units='data', text='Following Car with Kalman Filter') p1.add_layout(label1) p1.add_layout(label2) p1.add_layout(label3) p1.yaxis.visible = False p1.ygrid.visible = False p1.xaxis.visible = False p1.xgrid.visible = False p1.toolbar.logo = None p1.toolbar_location = None # Figure 1 p2 = figure(plot_width=400, plot_height=200, title='Noise Distributions') r21 = p2.line(noiserange, pdf_proc, line_color='seagreen', line_width=4, legend='Process') r22 = p2.line(noiserange, pdf_meas, line_color='greenyellow', line_width=4, legend='Measurement') p2.toolbar.logo = None p2.toolbar_location = None p2.legend.location = 'top_left' # Figure 2 p3 = figure(plot_width=1000, plot_height=150, x_axis_label='position', title='Car Following Animation', x_range=[0, dist_size], y_range=[-0.4, 0.4]) colors = ['darkslategray', 'gold', 'crimson'] r31 = p3.rect(x=[car1_initpos, car2_initpos, car2_initpos], y=[0.0, -0.2, 0.2], width=car_size, height=8, color=colors, width_units='data', height_units='screen') r32 = p3.line(x=[car1_initpos - car_size / 2, car1_initpos - car_size / 2], y=[-0.4, 0.4]) r33 = p3.line(x=[ car1_initpos + car_size / 2 - dist_sep, car1_initpos + car_size / 2 - dist_sep ], y=[-0.4, 0.4]) p3.yaxis.visible = False p3.ygrid.visible = False p3.toolbar.logo = None p3.toolbar_location = None # Figure 3 p4 = figure(plot_width=500, plot_height=400, x_axis_label='time', y_axis_label='position', title='Car Positions', x_range=[0, timesteps * dt], y_range=[0, dist_size]) r41 = p4.line(timepoints, poscar1, color='darkslategray', line_width=4) r42 = p4.line(timepoints, poscar1_meas, color='royalblue', legend='Measured position', line_width=4) r43 = p4.line(timepoints, poscar1_est, color='skyblue', legend='KF estimated position', line_width=4) r44 = p4.line(timepoints, poscar2, color='gold', line_width=4) r45 = p4.line(timepoints, poscar2_kf, color='crimson', line_width=4) p4.legend.location = 'bottom_right' p4.toolbar.logo = None p4.toolbar_location = None # Figure 4 p5 = figure(plot_width=500, plot_height=200, x_axis_label='time', y_axis_label='separation', title='Car Separations', x_range=[0, timesteps * dt], y_range=[0, 3 * dist_sep]) r51 = p5.line(timepoints, car_sep, color='gold', line_width=4) r52 = p5.line(timepoints, car_sep_kf, color='crimson', line_width=4) p5.toolbar.logo = None p5.toolbar_location = None # Figure 5 p6 = figure(plot_width=500, plot_height=200, x_axis_label='time', y_axis_label='acceleration', title='Following Car Accelerations', x_range=[0, timesteps * dt], y_range=[-car2_maxbrake / 2, car2_maxacc]) r61 = p6.line(timepoints, car2_acc, color='gold', line_width=4) r62 = p6.line(timepoints, car2_acc_kf, color='crimson', line_width=4) p6.toolbar.logo = None p6.toolbar_location = None # Setup widgets procnoise_slider = Slider(title='Process Noise', value=0.0, start=0.0, end=1.5, step=0.1) measnoise_slider = Slider(title='Measurement Noise', value=0.0, start=0.0, end=1.5, step=0.1) TextDisp = Div( text= '''<b>Note:</b> Wait for the plots to stop updating before hitting Start.''' ) TextDesc = Div( text= '''This simulation shows how Kalman Filtering can be used to improve autonomous car following. The red car uses a Kalman filter to filter out noise inherent in the detection of the car in the front. You can increase or decrease the noise level by dragging the sliders. The yellow car uses the raw sensor data. Both cars aim to achieve a fixed separation between itself and (vertical blue line in the Car Following Animation) the leading car. The plots below show car positions, separations, and accelarations.''', width=1000) textrel = Div( text= '''Learn more about this app works, Kalman filters, and their applications in <b>ES/AM 115</b> ''', width=1000) TextTitle = Div( text='''<b>KALMAN FILTER FOR AUTONOMOUS CAR FOLLOWING</b>''', width=1000) StartButton = Button(label='Start', button_type="success") #def RunCarFollowing(attr, old, new): def RunCarFollowing(event): # Get current widget values PN = procnoise_slider.value MN = measnoise_slider.value # Setup initial values InitPlotArrays() pos1real = car1_initpos pos2 = car2_initpos pos2_kf = car2_initpos vel2 = car2_initvel vel2_kf = car2_initvel acc2 = car2_initacc acc2_kf = car2_initacc tt = 0 realt = 0 # Update noise distributions nlim = max(PN, MN) global noiserange, pdf_proc, pdf_meas noiserange = np.linspace(-4 * nlim, 4 * nlim, timesteps) if PN == 0: pdf_proc = np.zeros(np.shape(noiserange)) else: pdf_proc = 1 / (PN * np.sqrt(2 * np.pi)) * np.exp(-noiserange**2 / (2 * PN**2)) if MN == 0: pdf_meas = np.zeros(np.shape(noiserange)) else: pdf_meas = 1 / (MN * np.sqrt(2 * np.pi)) * np.exp(-noiserange**2 / (2 * MN**2)) r21.data_source.data['x'] = noiserange r21.data_source.data['y'] = pdf_proc r22.data_source.data['x'] = noiserange r22.data_source.data['y'] = pdf_meas # Initialize Kalman Filter f = KalmanFilter(dim_x=2, dim_z=1) # initialize Kalman filter object f.x = np.array([ [car1_initpos], # position [car1_vel] ]) # velocity f.F = np.array([ [1.0, 1.0], # state transition matrix [0.0, 1.0] ]) f.H = np.array([[1.0, 0.0]]) # measurement function f.P = np.array([ [1000.0, 0.0], # apriori state covariance [0.0, 1000.0] ]) f.R = np.array([[5.0]]) # measurement noise covariance # Process noise if PN == 0: f.Q = np.zeros([2, 2]) else: f.Q = Q_discrete_white_noise(dim=2, dt=dt, var=PN**2) # Loop for updating positions for tt in range(timesteps): # Real position of leading car pos1real = pos1real + car1_vel * dt # Measurement of position of leading car with noise z = np.random.normal(pos1real, MN) # Kalman Filter predict and update steps f.predict( ) # predict next state using Kalman filter state propagation equation f.update(z) # add new measurement (z) to the Kalman filter # Following car update without Kalman Filter dx = z - pos2 err = (dx - dist_sep) / dist_sep if err > 1.0: err = 1.0 # Acceleration model if err > 0: acc2 = err * car2_maxacc else: acc2 = err * car2_maxbrake vel2 = vel2 + acc2 * dt # crash protection if vel2 < 0: vel2 = 0 acc2 = 0 # update position pos2 = pos2 + vel2 * dt + 0.5 * acc2 * dt**2 # Following car update with Kalman Filter dx_kf = f.x[0, 0] - pos2_kf err_kf = (dx_kf - dist_sep) / dist_sep if err_kf > 1.0: err_kf = 1.0 # Acceleration model if err_kf > 0: acc2_kf = err_kf * car2_maxacc else: acc2_kf = err_kf * car2_maxbrake vel2_kf = vel2_kf + acc2_kf * dt # crash protection if vel2_kf < 0: vel2_kf = 0 acc2_kf = 0 # update position pos2_kf = pos2_kf + vel2_kf * dt + 0.5 * acc2_kf * dt**2 # Update arrays for plotting global timepoints, poscar1, poscar2, poscar1_est, car_sep timepoints[tt] = tt * dt poscar1[tt] = pos1real poscar1_est[tt] = f.x[0, 0] poscar1_meas[tt] = z poscar2[tt] = pos2 poscar2_kf[tt] = pos2_kf car_sep[tt] = pos1real - pos2 car_sep_kf[tt] = pos1real - pos2_kf car2_acc[tt] = acc2 car2_acc_kf[tt] = acc2_kf # Update plots (both cars) #first row r31.data_source.data['x'] = [pos1real, pos2, pos2_kf] r32.data_source.data['x'] = [ pos1real - car_size / 2, pos1real - car_size / 2 ] r33.data_source.data['x'] = [ pos1real + car_size / 2 - dist_sep, pos1real + car_size / 2 - dist_sep ] #second row r41.data_source.data['x'] = timepoints r41.data_source.data['y'] = poscar1 r42.data_source.data['x'] = timepoints r42.data_source.data['y'] = poscar1_meas r43.data_source.data['x'] = timepoints r43.data_source.data['y'] = poscar1_est r44.data_source.data['x'] = timepoints r44.data_source.data['y'] = poscar2 r45.data_source.data['x'] = timepoints r45.data_source.data['y'] = poscar2_kf r51.data_source.data['x'] = timepoints r51.data_source.data['y'] = car_sep r52.data_source.data['x'] = timepoints r52.data_source.data['y'] = car_sep_kf r61.data_source.data['x'] = timepoints r61.data_source.data['y'] = car2_acc r62.data_source.data['x'] = timepoints r62.data_source.data['y'] = car2_acc_kf # # Update plots (only car without KF) # #first row # r31.data_source.data['x'] = [pos1real, pos2, 0] # r32.data_source.data['x'] = [pos1real - car_size / 2, pos1real - car_size / 2] # r33.data_source.data['x'] = [pos1real + car_size / 2 - dist_sep, pos1real + car_size / 2 - dist_sep] # #second row # r41.data_source.data['x'] = timepoints # r41.data_source.data['y'] = poscar1 # r42.data_source.data['x'] = timepoints # r42.data_source.data['y'] = poscar1_meas # r44.data_source.data['x'] = timepoints # r44.data_source.data['y'] = poscar2 # r51.data_source.data['x'] = timepoints # r51.data_source.data['y'] = car_sep # r61.data_source.data['x'] = timepoints # r61.data_source.data['y'] = car2_acc time.sleep(0.05) # Setup callbacks StartButton.on_event(ButtonClick, RunCarFollowing) # Setup layout and add to document wInputs = widgetbox(procnoise_slider, measnoise_slider, TextDisp, StartButton) doc.add_root( column(TextTitle, TextDesc, row(p1, p2, wInputs), p3, row(p4, column(p5, p6)), textrel))
# Neighbors Select neighbors_select = df['State'].unique().tolist() neighbors_select.append('Select value ...') neighbors_select = Select(title='Neighboring States', options=neighbors_select, value='Select value ...') neighbors_select.on_change('value', lambda attr, old, new: update()) # Download button download_button_table1 = Button(label="Export as CSV", button_type="success") download_button_table1.callback = CustomJS( args=dict(source=source), code=open('custom_js/download_states_overview.js').read()) reset_button_table1 = Button(label='Reset Table', button_type='primary') reset_button_table1.on_event(ButtonClick, reset_overview_table) # DataTable2 ================ # # State Select state_select = df2['State'].unique().tolist() state_select.append('All') state_select = Select(title='State', options=state_select, value='All') state_select.on_change('value', lambda attr, old, new: update()) # Funding Select funding_select = df2['FundingDescription'].unique().tolist() funding_select.append('N/A') funding_select.append('Select value ...') funding_select = Select(title='Funding', options=funding_select,
def modify_doc(doc): # Setup plots p1 = figure(plot_width=400, plot_height=300, x_axis_label='time', x_range=[0, timesteps * samplingtime], y_range=[-maxsetpoint, maxsetpoint], title='PID controller input and output') p2 = figure(plot_width=400, plot_height=300, x_axis_label='time', x_range=[0, timesteps * samplingtime], title='PID controller error') r1 = p1.line(timepoints, setpoints, line_color='cornflowerblue', legend='input', line_width=2) r2 = p1.line(timepoints, outputs, line_color='indianred', legend='output', line_width=2) r3 = p2.line(timepoints, errors, line_color='indigo', legend='error', line_width=2) p1.legend.location = 'top_left' p2.legend.location = 'top_left' # Setup widgets Kp = Slider(title='Kp', value=0.75, start=0.0, end=1.5, step=0.15) Ki = Slider(title='Ki', value=0.5, start=0.0, end=1.0, step=0.1) Kd = Slider(title='Kd', value=0.05, start=0.0, end=0.1, step=0.01) InputFunction = Select(title='Input Function', value='step', options=['noise', 'step', 'square', 'sine']) TextDisp = Div( text= '''<b>Note:</b> Wait for the plots to stop updating before hitting Start.''' ) StartButton = Button(label='Start', button_type='success') def RunPID(event): # Get current widget values kp = Kp.value ki = Ki.value kd = Kd.value inputfunc = InputFunction.value # Create PID class object pid = PID(kp, ki, kd) pid.initialize() for nn in range(1, timesteps, 1): # Inputs if inputfunc == 'noise': # null input if nn > 30: pid.setpoint = 0.5 * np.random.randn() if inputfunc == 'step': # step function if nn > 30: pid.setpoint = maxsetpoint elif inputfunc == 'square': # square wave if nn > 30: pid.setpoint = maxsetpoint * np.sign( np.sin(4 * np.pi * (nn - 30) / timesteps)) elif inputfunc == 'sine': # sine wave if nn > 30: pid.setpoint = maxsetpoint * np.sin(4 * np.pi * (nn - 30) / timesteps) # Outputs if nn > 30: pid.processval = pid.processval + (pid.controlvar - (1.0 / nn)) pid.controlLoop() global outputs outputs[nn] = pid.processval global timepoints timepoints[nn] = nn * samplingtime global setpoints setpoints[nn] = pid.setpoint global errors errors[nn] = pid.error # Update plots r1.data_source.data['x'] = timepoints r1.data_source.data['y'] = setpoints r2.data_source.data['x'] = timepoints r2.data_source.data['y'] = outputs r3.data_source.data['x'] = timepoints r3.data_source.data['y'] = errors # Setup callbacks StartButton.on_event(ButtonClick, RunPID) # Setup layout and add to document wInputs = widgetbox(InputFunction, Kp, Ki, Kd, TextDisp, StartButton) doc.add_root(row(wInputs, p1, p2, width=1000))
class BokehScript: def __init__(self, argv): args = docopt(__doc__, argv=argv) self._args = check_input(args) self._path = Path(args.get("<peaklist>")) self._data_path = args.get("<data>") self.read_config() self._peakipy_data = LoadData( self._path, self._data_path, dims=self.dims, verbose=True ) # check dataframe is usable self.peakipy_data.check_data_frame() # make temporary paths self.make_temp_files() self.make_data_source() self.setup_radii_sliders() self.setup_save_buttons() self.setup_quit_button() self.setup_plot() def init(self, doc): """ initialise the bokeh app """ doc.add_root( column( self.intro_div, row(column(self.p, self.doc_link), column(self.data_table, self.tabs)), sizing_mode="stretch_both", ) ) doc.title = "peakipy: Edit Fits" @property def args(self): return self._args @property def path(self): return self._path @property def data_path(self): return self._data_path @property def peakipy_data(self): return self._peakipy_data def make_temp_files(self): # Temp files self.TEMP_PATH = Path("tmp") self.TEMP_PATH.mkdir(parents=True, exist_ok=True) self.TEMP_OUT_CSV = self.TEMP_PATH / Path("tmp_out.csv") self.TEMP_INPUT_CSV = self.TEMP_PATH / Path("tmp.csv") self.TEMP_OUT_PLOT = self.TEMP_PATH / Path("plots") self.TEMP_OUT_PLOT.mkdir(parents=True, exist_ok=True) def make_data_source(self): # make datasource self.source = ColumnDataSource() self.source.data = ColumnDataSource.from_df(self.peakipy_data.df) return self.source def read_config(self): # read dims from config config_path = Path("peakipy.config") if config_path.exists(): try: config = json.load(open(config_path)) print(f"Using config file with --dims={config.get('--dims')}") dims = config.get("--dims", [0, 1, 2]) self._dims = ",".join(str(i) for i in dims) self.thres = config.get("--thres") except json.decoder.JSONDecodeError: print( Fore.RED + "Your peakipy.config file is corrupted - maybe your JSON is not correct..." ) print(Fore.RED + "Not using it.") self._dims = self.args.get("--dims") self.thres = False else: # get dim numbers from commandline self._dims = self.args.get("--dims") self.thres = False self.dims = [int(i) for i in self._dims.split(",")] def setup_radii_sliders(self): # configure sliders for setting radii self.slider_X_RADIUS = Slider( title="X_RADIUS - ppm", start=0.001, end=0.200, value=0.040, step=0.001, format="0[.]000", ) self.slider_Y_RADIUS = Slider( title="Y_RADIUS - ppm", start=0.010, end=2.000, value=0.400, step=0.001, format="0[.]000", ) self.slider_X_RADIUS.on_change( "value", lambda attr, old, new: self.slider_callback_x(attr, old, new) ) self.slider_Y_RADIUS.on_change( "value", lambda attr, old, new: self.slider_callback_y(attr, old, new) ) def setup_save_buttons(self): # save file self.savefilename = TextInput( title="Save file as (.csv)", placeholder="edited_peaks.csv" ) self.button = Button(label="Save", button_type="success") self.button.on_event(ButtonClick, self.save_peaks) def setup_quit_button(self): # Quit button self.exit_button = Button(label="Quit", button_type="warning") self.exit_button.on_event(ButtonClick, self.exit_edit_peaks) def setup_plot(self): """" code to setup the bokeh plots """ # make bokeh figure tools = [ "tap", "box_zoom", "lasso_select", "box_select", "wheel_zoom", "pan", "reset", ] self.p = figure( x_range=(self.peakipy_data.f2_ppm_0, self.peakipy_data.f2_ppm_1), y_range=(self.peakipy_data.f1_ppm_0, self.peakipy_data.f1_ppm_1), x_axis_label=f"{self.peakipy_data.f2_label} - ppm", y_axis_label=f"{self.peakipy_data.f1_label} - ppm", tools=tools, active_drag="pan", active_scroll="wheel_zoom", active_tap=None, ) if not self.thres: self.thres = threshold_otsu(self.peakipy_data.data[0]) self.contour_start = self.thres # contour level start value self.contour_num = 20 # number of contour levels self.contour_factor = 1.20 # scaling factor between contour levels cl = self.contour_start * self.contour_factor ** np.arange(self.contour_num) if len(cl) > 1 and np.min(np.diff(cl)) <= 0.0: print(f"Setting contour levels to np.abs({cl})") cl = np.abs(cl) self.extent = ( self.peakipy_data.f2_ppm_0, self.peakipy_data.f2_ppm_1, self.peakipy_data.f1_ppm_0, self.peakipy_data.f1_ppm_1, ) self.spec_source = get_contour_data( self.peakipy_data.data[0], cl, extent=self.extent, cmap=viridis ) # negative contours self.spec_source_neg = get_contour_data( self.peakipy_data.data[0] * -1.0, cl, extent=self.extent, cmap=autumn ) self.p.multi_line( xs="xs", ys="ys", line_color="line_color", source=self.spec_source ) self.p.multi_line( xs="xs", ys="ys", line_color="line_color", source=self.spec_source_neg ) # contour_num = Slider(title="contour number", value=20, start=1, end=50,step=1) # contour_start = Slider(title="contour start", value=100000, start=1000, end=10000000,step=1000) self.contour_start = TextInput( value="%.2e" % self.thres, title="Contour level:", width=100 ) # contour_factor = Slider(title="contour factor", value=1.20, start=1., end=2.,step=0.05) self.contour_start.on_change("value", self.update_contour) # for w in [contour_num,contour_start,contour_factor]: # w.on_change("value",update_contour) # plot mask outlines el = self.p.ellipse( x="X_PPM", y="Y_PPM", width="X_DIAMETER_PPM", height="Y_DIAMETER_PPM", source=self.source, fill_color="color", fill_alpha=0.1, line_dash="dotted", line_color="red", ) self.p.add_tools( HoverTool( tooltips=[ ("Index", "$index"), ("Assignment", "@ASS"), ("CLUSTID", "@CLUSTID"), ("RADII", "@X_RADIUS_PPM{0.000}, @Y_RADIUS_PPM{0.000}"), ( f"{self.peakipy_data.f2_label},{self.peakipy_data.f1_label}", "$x{0.000} ppm, $y{0.000} ppm", ), ], mode="mouse", # add renderers renderers=[el], ) ) # p.toolbar.active_scroll = "auto" # draw border around spectrum area spec_border_x = [ self.peakipy_data.f2_ppm_min, self.peakipy_data.f2_ppm_min, self.peakipy_data.f2_ppm_max, self.peakipy_data.f2_ppm_max, self.peakipy_data.f2_ppm_min, ] spec_border_y = [ self.peakipy_data.f1_ppm_min, self.peakipy_data.f1_ppm_max, self.peakipy_data.f1_ppm_max, self.peakipy_data.f1_ppm_min, self.peakipy_data.f1_ppm_min, ] self.p.line( spec_border_x, spec_border_y, line_width=1, line_color="black", line_dash="dotted", line_alpha=0.5, ) self.p.circle(x="X_PPM", y="Y_PPM", source=self.source, color="color") # plot cluster numbers self.p.text( x="X_PPM", y="Y_PPM", text="CLUSTID", text_color="color", source=self.source, text_font_size="8pt", text_font_style="bold", ) self.p.on_event(DoubleTap, self.peak_pick_callback) self.pos_neg_contour_dic = {0: "pos/neg", 1: "pos", 2: "neg"} self.pos_neg_contour_radiobutton = RadioButtonGroup( labels=[ self.pos_neg_contour_dic[i] for i in self.pos_neg_contour_dic.keys() ], active=0, ) self.pos_neg_contour_radiobutton.on_change("active", self.update_contour) # call fit_peaks self.fit_button = Button(label="Fit selected cluster", button_type="primary") # lineshape selection self.lineshapes = { 0: "PV", 1: "V", 2: "G", 3: "L", 4: "PV_PV", # 5: "PV_L", # 6: "PV_G", # 7: "G_L", } self.radio_button_group = RadioButtonGroup( labels=[self.lineshapes[i] for i in self.lineshapes.keys()], active=0 ) self.ls_div = Div( text="""Choose lineshape you wish to fit. This can be Voigt (V), pseudo-Voigt (PV), Gaussian (G), Lorentzian (L). PV_PV fits a PV lineshape with independent "fraction" parameters for the direct and indirect dimensions""" ) self.clust_div = Div( text="""If you want to adjust how the peaks are automatically clustered then try changing the width/diameter/height (integer values) of the structuring element used during the binary dilation step (you can also remove it by selecting 'None'). Increasing the size of the structuring element will cause peaks to be more readily incorporated into clusters. Be sure to save your peak list before doing this as any manual edits will be lost.""" ) self.intro_div = Div( text="""<h2>peakipy - interactive fit adjustment </h2> """ ) self.doc_link = Div( text="<h3><a href='https://j-brady.github.io/peakipy/build/usage/instructions.html', target='_blank'> ℹ️ click here for documentation</a></h3>" ) self.fit_reports = "" self.fit_reports_div = Div(text="", height=400, style={"overflow": "scroll"}) # Plane selection self.select_planes_list = [ f"{i}" for i in range(self.peakipy_data.data.shape[self.peakipy_data.planes]) ] self.select_plane = Select( title="Select plane:", value=self.select_planes_list[0], options=self.select_planes_list, ) self.select_planes_dic = { f"{i}": i for i in range(self.peakipy_data.data.shape[self.peakipy_data.planes]) } self.select_plane.on_change("value", self.update_contour) self.checkbox_group = CheckboxGroup( labels=["fit current plane only"], active=[] ) # not sure this is needed selected_df = self.peakipy_data.df.copy() self.fit_button.on_event(ButtonClick, self.fit_selected) columns = [ TableColumn(field="ASS", title="Assignment"), TableColumn(field="CLUSTID", title="Cluster", editor=IntEditor()), TableColumn( field="X_PPM", title=f"{self.peakipy_data.f2_label}", editor=NumberEditor(step=0.0001), formatter=NumberFormatter(format="0.0000"), ), TableColumn( field="Y_PPM", title=f"{self.peakipy_data.f1_label}", editor=NumberEditor(step=0.0001), formatter=NumberFormatter(format="0.0000"), ), TableColumn( field="X_RADIUS_PPM", title=f"{self.peakipy_data.f2_label} radius (ppm)", editor=NumberEditor(step=0.0001), formatter=NumberFormatter(format="0.0000"), ), TableColumn( field="Y_RADIUS_PPM", title=f"{self.peakipy_data.f1_label} radius (ppm)", editor=NumberEditor(step=0.0001), formatter=NumberFormatter(format="0.0000"), ), TableColumn( field="XW_HZ", title=f"{self.peakipy_data.f2_label} LW (Hz)", editor=NumberEditor(step=0.01), formatter=NumberFormatter(format="0.00"), ), TableColumn( field="YW_HZ", title=f"{self.peakipy_data.f1_label} LW (Hz)", editor=NumberEditor(step=0.01), formatter=NumberFormatter(format="0.00"), ), TableColumn( field="VOL", title="Volume", formatter=NumberFormatter(format="0.0") ), TableColumn( field="include", title="Include", editor=SelectEditor(options=["yes", "no"]), ), TableColumn(field="MEMCNT", title="MEMCNT", editor=IntEditor()), ] self.data_table = DataTable( source=self.source, columns=columns, editable=True, fit_columns=True ) # callback for adding # source.selected.on_change('indices', callback) self.source.selected.on_change("indices", self.select_callback) # Document layout fitting_controls = column( row( column(self.slider_X_RADIUS, self.slider_Y_RADIUS), column( row( widgetbox(self.contour_start, self.pos_neg_contour_radiobutton) ), widgetbox(self.fit_button), ), ), row( column(widgetbox(self.ls_div), widgetbox(self.radio_button_group)), column(widgetbox(self.select_plane), widgetbox(self.checkbox_group)), ), ) # reclustering tab self.struct_el = Select( title="Structuring element:", value="disk", options=["square", "disk", "rectangle", "None", "mask_method"], width=100, ) self.struct_el_size = TextInput( value="3", title="Size(width/radius or width,height for rectangle):", width=100, ) self.recluster = Button(label="Re-cluster", button_type="warning") self.recluster.on_event(ButtonClick, self.recluster_peaks) # edit_fits tabs fitting_layout = fitting_controls log_layout = self.fit_reports_div recluster_layout = row( self.clust_div, column( self.contour_start, self.struct_el, self.struct_el_size, self.recluster ), ) save_layout = column(self.savefilename, self.button, self.exit_button) fitting_tab = Panel(child=fitting_layout, title="Peak fitting") log_tab = Panel(child=log_layout, title="Log") recluster_tab = Panel(child=recluster_layout, title="Re-cluster peaks") save_tab = Panel(child=save_layout, title="Save edited peaklist") self.tabs = Tabs( tabs=[fitting_tab, log_tab, recluster_tab, save_tab], sizing_mode="scale_both", ) def recluster_peaks(self, event): if self.struct_el.value == "mask_method": self.struc_size = tuple( [float(i) for i in self.struct_el_size.value.split(",")] ) print(self.struc_size) self.peakipy_data.mask_method(overlap=self.struc_size[0]) else: self.struc_size = tuple( [int(i) for i in self.struct_el_size.value.split(",")] ) print(self.struc_size) self.peakipy_data.clusters( thres=eval(self.contour_start.value), struc_el=self.struct_el.value, struc_size=self.struc_size, ) # update data source self.source.data = ColumnDataSource.from_df(self.peakipy_data.df) return self.peakipy_data.df def update_memcnt(self): for ind, group in self.peakipy_data.df.groupby("CLUSTID"): self.peakipy_data.df.loc[group.index, "MEMCNT"] = len(group) # set cluster colors (set to black if singlet peaks) self.peakipy_data.df["color"] = self.peakipy_data.df.apply( lambda x: Category20[20][int(x.CLUSTID) % 20] if x.MEMCNT > 1 else "black", axis=1, ) # change color of excluded peaks include_no = self.peakipy_data.df.include == "no" self.peakipy_data.df.loc[include_no, "color"] = "ghostwhite" # update source data self.source.data = ColumnDataSource.from_df(self.peakipy_data.df) return self.peakipy_data.df def fit_selected(self, event): selectionIndex = self.source.selected.indices current = self.peakipy_data.df.iloc[selectionIndex] self.peakipy_data.df.loc[ selectionIndex, "X_RADIUS_PPM" ] = self.slider_X_RADIUS.value self.peakipy_data.df.loc[ selectionIndex, "Y_RADIUS_PPM" ] = self.slider_Y_RADIUS.value self.peakipy_data.df.loc[selectionIndex, "X_DIAMETER_PPM"] = ( current["X_RADIUS_PPM"] * 2.0 ) self.peakipy_data.df.loc[selectionIndex, "Y_DIAMETER_PPM"] = ( current["Y_RADIUS_PPM"] * 2.0 ) selected_df = self.peakipy_data.df[ self.peakipy_data.df.CLUSTID.isin(list(current.CLUSTID)) ] selected_df.to_csv(self.TEMP_INPUT_CSV) lineshape = self.lineshapes[self.radio_button_group.active] if self.checkbox_group.active == []: print(Fore.YELLOW + "Using LS = ", lineshape) fit_command = f"peakipy fit {self.TEMP_INPUT_CSV} {self.data_path} {self.TEMP_OUT_CSV} --lineshape={lineshape} --dims={self._dims}" plot_command = f"peakipy check {self.TEMP_OUT_CSV} {self.data_path} -l -i -s --outname={self.TEMP_OUT_PLOT / Path('tmp.pdf')}" else: plane_index = self.select_plane.value print(Fore.YELLOW + "Using LS = ", lineshape) print(Fore.YELLOW + f"Only fitting plane {plane_index}") fit_command = f"peakipy fit {self.TEMP_INPUT_CSV} {self.data_path} {self.TEMP_OUT_CSV} --lineshape={lineshape} --dims={self._dims} --plane={plane_index}" plot_command = f"peakipy check {self.TEMP_OUT_CSV} {self.data_path} -l -i -s --outname={self.TEMP_OUT_PLOT / Path('tmp.pdf')} --plane={plane_index}" print(Fore.BLUE + fit_command) self.fit_reports += fit_command + "<br>" stdout = check_output(fit_command.split(" ")) self.fit_reports += stdout.decode() + "<br><hr><br>" self.fit_reports = self.fit_reports.replace("\n", "<br>") self.fit_reports_div.text = log_div % (log_style, self.fit_reports) # plot data os.system(plot_command) def save_peaks(self, event): if self.savefilename.value: to_save = Path(self.savefilename.value) else: to_save = Path(self.savefilename.placeholder) if to_save.exists(): shutil.copy(f"{to_save}", f"{to_save}.bak") print(f"Making backup {to_save}.bak") print(Fore.GREEN + f"Saving peaks to {to_save}") if to_save.suffix == ".csv": self.peakipy_data.df.to_csv(to_save, float_format="%.4f", index=False) else: self.peakipy_data.df.to_pickle(to_save) def select_callback(self, attrname, old, new): # print(Fore.RED + "Calling Select Callback") # selectionIndex = self.source.selected.indices # current = self.peakipy_data.df.iloc[selectionIndex] for col in self.peakipy_data.df.columns: self.peakipy_data.df.loc[:, col] = self.source.data[col] # self.source.data = ColumnDataSource.from_df(self.peakipy_data.df) # update memcnt self.update_memcnt() # print(Fore.YELLOW + "Finished Calling Select Callback") def peak_pick_callback(self, event): # global so that df is updated globally x_radius_ppm = 0.035 y_radius_ppm = 0.35 x_radius = x_radius_ppm * self.peakipy_data.pt_per_ppm_f2 y_radius = y_radius_ppm * self.peakipy_data.pt_per_ppm_f1 x_diameter_ppm = x_radius_ppm * 2.0 y_diameter_ppm = y_radius_ppm * 2.0 clustid = self.peakipy_data.df.CLUSTID.max() + 1 index = self.peakipy_data.df.INDEX.max() + 1 x_ppm = event.x y_ppm = event.y x_axis = self.peakipy_data.uc_f2.f(x_ppm, "ppm") y_axis = self.peakipy_data.uc_f1.f(y_ppm, "ppm") xw_hz = 20.0 yw_hz = 20.0 xw = xw_hz * self.peakipy_data.pt_per_hz_f2 yw = yw_hz * self.peakipy_data.pt_per_hz_f1 assignment = f"test_peak_{index}_{clustid}" height = self.peakipy_data.data[0][int(y_axis), int(x_axis)] volume = height print( Fore.BLUE + f"""Adding peak at {assignment}: {event.x:.3f},{event.y:.3f}""" ) new_peak = { "INDEX": index, "X_PPM": x_ppm, "Y_PPM": y_ppm, "HEIGHT": height, "VOL": volume, "XW_HZ": xw_hz, "YW_HZ": yw_hz, "X_AXIS": int(np.floor(x_axis)), # integers "Y_AXIS": int(np.floor(y_axis)), # integers "X_AXISf": x_axis, "Y_AXISf": y_axis, "XW": xw, "YW": yw, "ASS": assignment, "X_RADIUS_PPM": x_radius_ppm, "Y_RADIUS_PPM": y_radius_ppm, "X_RADIUS": x_radius, "Y_RADIUS": y_radius, "CLUSTID": clustid, "MEMCNT": 1, "X_DIAMETER_PPM": x_diameter_ppm, "Y_DIAMETER_PPM": y_diameter_ppm, "Edited": True, "include": "yes", "color": "black", } self.peakipy_data.df = self.peakipy_data.df.append(new_peak, ignore_index=True) self.update_memcnt() def slider_callback_x(self, attrname, old, new): selectionIndex = self.source.selected.indices current = self.peakipy_data.df.iloc[selectionIndex] self.peakipy_data.df.loc[selectionIndex, "X_RADIUS"] = ( self.slider_X_RADIUS.value * self.peakipy_data.pt_per_ppm_f2 ) self.peakipy_data.df.loc[ selectionIndex, "X_RADIUS_PPM" ] = self.slider_X_RADIUS.value self.peakipy_data.df.loc[selectionIndex, "X_DIAMETER_PPM"] = ( current["X_RADIUS_PPM"] * 2.0 ) self.peakipy_data.df.loc[selectionIndex, "X_DIAMETER"] = ( current["X_RADIUS"] * 2.0 ) # set edited rows to True self.peakipy_data.df.loc[selectionIndex, "Edited"] = True self.source.data = ColumnDataSource.from_df(self.peakipy_data.df) def slider_callback_y(self, attrname, old, new): selectionIndex = self.source.selected.indices current = self.peakipy_data.df.iloc[selectionIndex] self.peakipy_data.df.loc[selectionIndex, "Y_RADIUS"] = ( self.slider_Y_RADIUS.value * self.peakipy_data.pt_per_ppm_f1 ) self.peakipy_data.df.loc[ selectionIndex, "Y_RADIUS_PPM" ] = self.slider_Y_RADIUS.value self.peakipy_data.df.loc[selectionIndex, "Y_DIAMETER_PPM"] = ( current["Y_RADIUS_PPM"] * 2.0 ) self.peakipy_data.df.loc[selectionIndex, "Y_DIAMETER"] = ( current["Y_RADIUS"] * 2.0 ) # set edited rows to True self.peakipy_data.df.loc[selectionIndex, "Edited"] = True self.source.data = ColumnDataSource.from_df(self.peakipy_data.df) # def slider_callback(self, attrname, old, new, dim="X"): # # selectionIndex = self.source.selected.indices # current = self.peakipy_data.df.iloc[selectionIndex] # self.peakipy_data.df.loc[selectionIndex, f"{dim}_RADIUS"] = ( # self.slider_Y_RADIUS.value * self.peakipy_data.pt_per_ppm_f1 # ) # self.peakipy_data.df.loc[ # selectionIndex, f"{dim}_RADIUS_PPM" # ] = self.slider_Y_RADIUS.value # # self.peakipy_data.df.loc[selectionIndex, f"{dim}_DIAMETER_PPM"] = ( # current[f"{dim}_RADIUS_PPM"] * 2.0 # ) # self.peakipy_data.df.loc[selectionIndex, f"{dim}_DIAMETER"] = ( # current[f"{dim}_RADIUS"] * 2.0 # ) # # set edited rows to True # self.peakipy_data.df.loc[selectionIndex, "Edited"] = True # selected_df = df[df.CLUSTID.isin(list(current.CLUSTID))] # print(list(selected_df)) # self.source.data = ColumnDataSource.from_df(self.peakipy_data.df) # def slider_callback_x(self, attrname, old, new): # # self.slider_callback(attrname, old, new, dim="X") # # def slider_callback_y(self, attrname, old, new): # # self.slider_callback(attrname, old, new, dim="Y") def update_contour(self, attrname, old, new): new_cs = eval(self.contour_start.value) cl = new_cs * self.contour_factor ** np.arange(self.contour_num) if len(cl) > 1 and np.min(np.diff(cl)) <= 0.0: print(f"Setting contour levels to np.abs({cl})") cl = np.abs(cl) plane_index = self.select_planes_dic[self.select_plane.value] pos_neg = self.pos_neg_contour_dic[self.pos_neg_contour_radiobutton.active] if pos_neg == "pos/neg": self.spec_source.data = get_contour_data( self.peakipy_data.data[plane_index], cl, extent=self.extent, cmap=viridis, ).data self.spec_source_neg.data = get_contour_data( self.peakipy_data.data[plane_index] * -1.0, cl, extent=self.extent, cmap=autumn, ).data elif pos_neg == "pos": self.spec_source.data = get_contour_data( self.peakipy_data.data[plane_index], cl, extent=self.extent, cmap=viridis, ).data self.spec_source_neg.data = get_contour_data( self.peakipy_data.data[plane_index] * 0.0, cl, extent=self.extent, cmap=autumn, ).data elif pos_neg == "neg": self.spec_source.data = get_contour_data( self.peakipy_data.data[plane_index] * 0.0, cl, extent=self.extent, cmap=viridis, ).data self.spec_source_neg.data = get_contour_data( self.peakipy_data.data[plane_index] * -1.0, cl, extent=self.extent, cmap=autumn, ).data # print("Value of checkbox",checkbox_group.active) def exit_edit_peaks(self, event): sys.exit()