def __init__(self, analyser): """ Creates and manages the Gui for RangeAnalysis """ self.analyser = analyser self.fig = self.make_fig() init_start = self.analyser.x.min() * 1.1 init_end = self.analyser.x.max() * 0.9 span_kwargs = dict(dimension='height', line_dash='dashed', line_width=3) self.start_span = Span(location=init_start, line_color='green', **span_kwargs) self.end_span = Span(location=init_end, line_color='red', **span_kwargs) self.range_slide = RangeSlider(start=self.analyser.x.min(), end=self.analyser.x.max(), step=self.analyser.dx, value=(init_start, init_end), width=self.fig.plot_width) self.start_connected = widgets.Button(label="start", button_type='success') self.end_connected = widgets.Button(label="end", button_type='success') self.setup_callbacks() self.app = self.make_app() self.doc = None
def __init__(self, analyser, analysis): self.analyser = analyser self.analysis = analysis self.label_input = TextInput(value=f'{analysis.short} 1') self.do_button = widgets.Button(label=f'Run {analysis.name}') self.do_button.on_click(self.run)
def layout_1t(self, team, tasks): self.total_1t(team, tasks) self.team_sel = bk_widgets.Select(title='Match', options=self.list_teams(), value=team) self.team_sel.on_change('value', self.team_callback) self.task_sel = bk_widgets.MultiSelect(title='Tasks', options=self.data.enum_tasks, size=40, value=tasks) btn = bk_widgets.Button(label='Update') btn.on_click(self.button_callback) col_layout = bk_layouts.column(self.team_sel, self.task_sel, btn) self.layout = bk_layouts.row(col_layout, self.pcplot) return self.layout
def layout_file_management(self): btn = bk_widgets.Button(label='Update graphs') btn.on_click(self.callback_button) self.layout = bk_layouts.row(btn) return self.layout
bmw.Select(value='st', options=hierarchy.columns.values.tolist(), id='map_subregtype')), ('year', bmw.Select(value=str(2050), options=[str(x) for x in years_full], id='year')), ('timeslice', bmw.Select(value='All timeslices', options=['All timeslices', 'H1', 'H2', 'H3'], id='timeslice')), ('scale_axes', bmw.RadioButtonGroup(labels=['Sync Axes', 'Scale Independently'], id='scale_axes')), ('rerender', bmw.Button(label='Re-render', button_type='success', id='rerender')), ('download', bmw.Button(label='Download CSV', button_type='success', id='download')), ('download_subreg', bmw.Button(label='Download Subregion CSV', button_type='success', id='download_subreg')), )) def initialize(): for scenario_name in scenarios: #build plots plot = { 'figure': bp.Figure(toolbar_location='right',
def tool_handler_2d(self, doc): from bokeh import events from bokeh.layouts import row, column, widgetbox, Spacer from bokeh.models import ColumnDataSource, widgets from bokeh.models.mappers import LinearColorMapper from bokeh.models.widgets.markups import Div from bokeh.plotting import figure arr = self.arr # Set up the data x_coords, y_coords = arr.coords[arr.dims[0]], arr.coords[arr.dims[1]] # Styling default_palette = self.default_palette if arr.S.is_subtracted: default_palette = cc.coolwarm error_alpha = 0.3 error_fill = '#3288bd' # Application Organization self.app_context.update({ 'data': arr, 'data_range': { 'x': (np.min(x_coords.values), np.max(x_coords.values)), 'y': (np.min(y_coords.values), np.max(y_coords.values)), }, 'show_stat_variation': False, 'color_mode': 'linear', }) def stats_patch_from_data(data, subsampling_rate=None): if subsampling_rate is None: subsampling_rate = int(min(data.values.shape[0] / 50, 5)) if subsampling_rate == 0: subsampling_rate = 1 x_values = data.coords[data.dims[0]].values[::subsampling_rate] values = data.values[::subsampling_rate] sq = np.sqrt(values) lower, upper = values - sq, values + sq return { 'x': np.append(x_values, x_values[::-1]), 'y': np.append(lower, upper[::-1]), } def update_stat_variation(plot_name, data): patch_data = stats_patch_from_data(data) if plot_name != 'right': # the right plot is on transposed axes plots[plot_name + '_marginal_err'].data_source.data = patch_data else: plots[plot_name + '_marginal_err'].data_source.data = { 'x': patch_data['y'], 'y': patch_data['x'], } figures, plots, app_widgets = self.app_context[ 'figures'], self.app_context['plots'], self.app_context['widgets'] if self.cursor_default is not None and len(self.cursor_default) == 2: self.cursor = self.cursor_default else: self.cursor = [ np.mean(self.app_context['data_range']['x']), np.mean(self.app_context['data_range']['y']) ] # try a sensible default # create the main inset plot main_image = arr prepped_main_image = self.prep_image(main_image) self.app_context['color_maps']['main'] = LinearColorMapper( default_palette, low=np.min(prepped_main_image), high=np.max(prepped_main_image), nan_color='black') main_tools = ["wheel_zoom", "tap", "reset", "save"] main_title = 'Bokeh Tool: WARNING Unidentified' try: main_title = "Bokeh Tool: %s" % arr.S.label[:60] except: pass figures['main'] = figure(tools=main_tools, plot_width=self.app_main_size, plot_height=self.app_main_size, min_border=10, min_border_left=50, toolbar_location='left', x_axis_location='below', y_axis_location='right', title=main_title, x_range=self.app_context['data_range']['x'], y_range=self.app_context['data_range']['y']) figures['main'].xaxis.axis_label = arr.dims[0] figures['main'].yaxis.axis_label = arr.dims[1] figures['main'].toolbar.logo = None figures['main'].background_fill_color = "#fafafa" plots['main'] = figures['main'].image( [prepped_main_image.T], x=self.app_context['data_range']['x'][0], y=self.app_context['data_range']['y'][0], dw=self.app_context['data_range']['x'][1] - self.app_context['data_range']['x'][0], dh=self.app_context['data_range']['y'][1] - self.app_context['data_range']['y'][0], color_mapper=self.app_context['color_maps']['main']) app_widgets['info_div'] = Div(text='', width=self.app_marginal_size, height=100) # Create the bottom marginal plot bottom_marginal = arr.sel(**dict([[arr.dims[1], self.cursor[1]]]), method='nearest') figures['bottom_marginal'] = figure( plot_width=self.app_main_size, plot_height=200, title=None, x_range=figures['main'].x_range, y_range=(np.min(bottom_marginal.values), np.max(bottom_marginal.values)), x_axis_location='above', toolbar_location=None, tools=[]) plots['bottom_marginal'] = figures['bottom_marginal'].line( x=bottom_marginal.coords[arr.dims[0]].values, y=bottom_marginal.values) plots['bottom_marginal_err'] = figures['bottom_marginal'].patch( x=[], y=[], color=error_fill, fill_alpha=error_alpha, line_color=None) # Create the right marginal plot right_marginal = arr.sel(**dict([[arr.dims[0], self.cursor[0]]]), method='nearest') figures['right_marginal'] = figure( plot_width=200, plot_height=self.app_main_size, title=None, y_range=figures['main'].y_range, x_range=(np.min(right_marginal.values), np.max(right_marginal.values)), y_axis_location='left', toolbar_location=None, tools=[]) plots['right_marginal'] = figures['right_marginal'].line( y=right_marginal.coords[arr.dims[1]].values, x=right_marginal.values) plots['right_marginal_err'] = figures['right_marginal'].patch( x=[], y=[], color=error_fill, fill_alpha=error_alpha, line_color=None) cursor_lines = self.add_cursor_lines(figures['main']) # Attach tools and callbacks toggle = widgets.Toggle(label="Show Stat. Variation", button_type="success", active=False) def set_show_stat_variation(should_show): self.app_context['show_stat_variation'] = should_show if should_show: main_image_data = arr update_stat_variation( 'bottom', main_image_data.sel(**dict([[arr.dims[1], self.cursor[1]]]), method='nearest')) update_stat_variation( 'right', main_image_data.sel(**dict([[arr.dims[0], self.cursor[0]]]), method='nearest')) plots['bottom_marginal_err'].visible = True plots['right_marginal_err'].visible = True else: plots['bottom_marginal_err'].visible = False plots['right_marginal_err'].visible = False toggle.on_click(set_show_stat_variation) scan_keys = [ 'x', 'y', 'z', 'pass_energy', 'hv', 'location', 'id', 'probe_pol', 'pump_pol' ] scan_info_source = ColumnDataSource({ 'keys': [k for k in scan_keys if k in arr.attrs], 'values': [ str(v) if isinstance(v, float) and np.isnan(v) else v for v in [arr.attrs[k] for k in scan_keys if k in arr.attrs] ], }) scan_info_columns = [ widgets.TableColumn(field='keys', title='Attr.'), widgets.TableColumn(field='values', title='Value'), ] POINTER_MODES = [ ( 'Cursor', 'cursor', ), ( 'Path', 'path', ), ] COLOR_MODES = [ ( 'Adaptive Hist. Eq. (Slow)', 'adaptive_equalization', ), # ('Histogram Eq.', 'equalization',), # not implemented ( 'Linear', 'linear', ), # ('Log', 'log',), # not implemented ] def on_change_color_mode(attr, old, new_color_mode): self.app_context['color_mode'] = new_color_mode if old is None or old != new_color_mode: right_image_data = arr.sel(**dict( [[arr.dims[0], self.cursor[0]]]), method='nearest') bottom_image_data = arr.sel(**dict( [[arr.dims[1], self.cursor[1]]]), method='nearest') main_image_data = arr prepped_right_image = self.prep_image(right_image_data) prepped_bottom_image = self.prep_image(bottom_image_data) prepped_main_image = self.prep_image(main_image_data) plots['right'].data_source.data = { 'image': [prepped_right_image] } plots['bottom'].data_source.data = { 'image': [prepped_bottom_image.T] } plots['main'].data_source.data = { 'image': [prepped_main_image.T] } update_main_colormap(None, None, main_color_range_slider.value) color_mode_dropdown = widgets.Dropdown(label='Color Mode', button_type='primary', menu=COLOR_MODES) color_mode_dropdown.on_change('value', on_change_color_mode) symmetry_point_name_input = widgets.TextInput( title='Symmetry Point Name', value="G") snap_checkbox = widgets.CheckboxButtonGroup(labels=['Snap Axes'], active=[]) place_symmetry_point_at_cursor_button = widgets.Button( label="Place Point", button_type="primary") def update_symmetry_points_for_display(): pass def place_symmetry_point(): cursor_dict = dict(zip(arr.dims, self.cursor)) skip_dimensions = {'eV', 'delay', 'cycle'} if 'symmetry_points' not in arr.attrs: arr.attrs['symmetry_points'] = {} snap_distance = { 'phi': 2, 'beta': 2, 'kx': 0.01, 'ky': 0.01, 'kz': 0.01, 'kp': 0.01, 'hv': 4, } cursor_dict = { k: v for k, v in cursor_dict.items() if k not in skip_dimensions } snapped = copy.copy(cursor_dict) if 'Snap Axes' in [ snap_checkbox.labels[i] for i in snap_checkbox.active ]: for axis, value in cursor_dict.items(): options = [ point[axis] for point in arr.attrs['symmetry_points'].values() if axis in point ] options = sorted(options, key=lambda x: np.abs(x - value)) if options and np.abs(options[0] - value) < snap_distance[axis]: snapped[axis] = options[0] arr.attrs['symmetry_points'][ symmetry_point_name_input.value] = snapped place_symmetry_point_at_cursor_button.on_click(place_symmetry_point) main_color_range_slider = widgets.RangeSlider( start=0, end=100, value=( 0, 100, ), title='Color Range (Main)') layout = row( column(figures['main'], figures['bottom_marginal']), column(figures['right_marginal'], Spacer(width=200, height=200)), column( widgetbox( widgets.Dropdown(label='Pointer Mode', button_type='primary', menu=POINTER_MODES)), widgets.Tabs(tabs=[ widgets.Panel(child=widgetbox( Div(text='<h2>Colorscale:</h2>'), color_mode_dropdown, main_color_range_slider, Div(text= '<h2 style="padding-top: 30px;">General Settings:</h2>' ), toggle, self._cursor_info, sizing_mode='scale_width'), title='Settings'), widgets.Panel(child=widgetbox( app_widgets['info_div'], Div(text= '<h2 style="padding-top: 30px; padding-bottom: 10px;">Scan Info</h2>' ), widgets.DataTable(source=scan_info_source, columns=scan_info_columns, width=400, height=400), sizing_mode='scale_width', width=400), title='Info'), widgets.Panel(child=widgetbox( Div(text='<h2>Preparation</h2>'), symmetry_point_name_input, snap_checkbox, place_symmetry_point_at_cursor_button, sizing_mode='scale_width'), title='Preparation'), ], width=400))) update_main_colormap = self.update_colormap_for('main') def on_click_save(event): save_dataset(arr) print(event) def click_main_image(event): self.cursor = [event.x, event.y] right_marginal_data = arr.sel(**dict( [[arr.dims[0], self.cursor[0]]]), method='nearest') bottom_marginal_data = arr.sel(**dict( [[arr.dims[1], self.cursor[1]]]), method='nearest') plots['bottom_marginal'].data_source.data = { 'x': bottom_marginal_data.coords[arr.dims[0]].values, 'y': bottom_marginal_data.values, } plots['right_marginal'].data_source.data = { 'y': right_marginal_data.coords[arr.dims[1]].values, 'x': right_marginal_data.values, } if self.app_context['show_stat_variation']: update_stat_variation('right', right_marginal_data) update_stat_variation('bottom', bottom_marginal_data) figures['bottom_marginal'].y_range.start = np.min( bottom_marginal_data.values) figures['bottom_marginal'].y_range.end = np.max( bottom_marginal_data.values) figures['right_marginal'].x_range.start = np.min( right_marginal_data.values) figures['right_marginal'].x_range.end = np.max( right_marginal_data.values) self.save_app() figures['main'].on_event(events.Tap, click_main_image) main_color_range_slider.on_change('value', update_main_colormap) doc.add_root(layout) doc.title = "Bokeh Tool" self.load_app() self.save_app()
from bokeh.io import show, curdoc from bokeh.models import widgets as wd from bokeh.layouts import widgetbox as wb, layout import random import time # Login btnLogin = wd.Button(label="Login") btnReset = wd.Button(label="Reset") name = wd.TextInput(title="Name", placeholder="enter name ....") pwd = wd.TextInput(title="Password", placeholder="enter password ....") # Study majors = wd.RadioButtonGroup(labels=["CS", "Stat", "Math", "EIE", "Energy", "HSS", "SME"]) text = wd.Paragraph(text="Press button to start .... ") answer = wd.Paragraph(text="") btnRandom = wd.Button(label="Choose For Me") login = layout( [ [ wb(name) ], [ wb(pwd) ], [ wb(btnLogin), wb(btnReset) ] # side by side ] ) major = layout( [ [ wb(majors, width=800) ], [ wb(text, btnRandom, answer) ] ] )
from bokeh.models import widgets from bokeh.io import show, curdoc from bokeh.layouts import widgetbox button = widgets.Button(label='Refresh') username = widgets.TextInput(title='Name', placeholder='enter your name...') school = widgets.Select(title='School', options=['SSE', 'SME', 'HSS']) def onClick(): print('hahaha') def onUserNameChange(attr, old, new): print(attr, old, new) def onSchoolChange(attr, old, new): print('school', old, new) button.on_click(onClick) username.on_change('value', onUserNameChange) school.on_change('value', onSchoolChange) # show(widgetbox(button, username, school)) curdoc().add_root(widgetbox(button, username, school))
def main() -> None: """dependencty walker のツリー情報を解析する。 """ FILEPATH = "hoge.txt" df = to_df(FILEPATH) df = df[df["legend2"] != "Missing Module"] np.random.seed(0) graph = nx.from_pandas_edgelist(df, "name", "parent", edge_attr=None, create_using=nx.DiGraph()) nx.set_node_attributes( graph, df.drop_duplicates(subset="name").set_index("name").to_dict("index")) # グラフデータを bokeh 用に変換 render = bkgraphs.from_networkx(graph, nx.spring_layout, scale=1, center=(0, 0)) render.node_renderer.glyph = bkmodels.Circle( size=8, fill_color=bkpalettes.Spectral4[0]) # グラフ初期設定 p = bkplotting.figure( tools=("pan,box_zoom,lasso_select,box_select,poly_select" ",tap,wheel_zoom,reset,save,zoom_in"), title="dependency link", x_range=(-1.1, 1.1), y_range=(-1.1, 1.1), ) tooltips = [ ("name", "@index"), ("legend1", "@legend1"), ("legend2", "@legend2"), ("legend3", "@legend3"), ] p.add_tools(bkmodels.HoverTool(tooltips=tooltips)) p.renderers.append(render) # データ表示データテーブル data_table = bkwidgets.DataTable( source=render.node_renderer.data_source, columns=[ bkwidgets.TableColumn(field=column, title=column) for column in ["index", "legend1", "legend2", "legend3"] ], fit_columns=True, ) dependency_source = bkmodels.ColumnDataSource(df) dependency_table = bkwidgets.DataTable( source=dependency_source, columns=[ bkwidgets.TableColumn(field=column, title=column) for column in ["name", "parent", "legend1", "legend2", "legend3"] ], fit_columns=True, ) # 依存関係の始点と終点を設定するテキストボックス target_text = bkwidgets.TextInput(value="None", title="Target Module") source_text = bkwidgets.TextInput(value="Input Module Name", title="Source Module") cutoff_text = bkwidgets.TextInput(value="3", title="Number of Cutoff") # 実行ボタン def execute_callback(event) -> None: nonlocal render nonlocal dependency_source np.random.seed(0) all_pathes = nx.all_simple_paths( graph, source=f"{source_text.value}", target=f"{target_text.value}", cutoff=int(f"{cutoff_text.value}"), ) pathes: Set = set() for path in all_pathes: pathes |= set(path) subgraph = graph.subgraph(pathes) render = bkgraphs.from_networkx(subgraph, nx.spring_layout, scale=1, center=(0, 0)) render.node_renderer.glyph = bkmodels.Circle( size=8, fill_color=bkpalettes.Spectral4[0]) p.renderers.clear() p.renderers.append(render) data_table.source = render.node_renderer.data_source x, y = zip(*render.layout_provider.graph_layout.values()) render.node_renderer.data_source.data["x"] = x render.node_renderer.data_source.data["y"] = y labels = bkmodels.LabelSet(x="x", y="y", text="index", source=render.node_renderer.data_source) p.renderers.append(labels) dependency_df = df[df["name"].isin(pathes) & df["parent"].isin(pathes)].drop_duplicates( subset=["name", "parent"]) dependency_source = bkmodels.ColumnDataSource(dependency_df) dependency_table.source = dependency_source execute_button = bkwidgets.Button(label="execute", button_type="success") execute_button.on_click(execute_callback) # 検索結果をクリアするボタン def clear_callback(event) -> None: np.random.seed(0) render = bkgraphs.from_networkx(graph, nx.spring_layout, scale=1, center=(0, 0)) render.node_renderer.glyph = bkmodels.Circle( size=8, fill_color=bkpalettes.Spectral4[0]) p.renderers.clear() p.renderers.append(render) # p.renderers.pop(0) data_table.source = render.node_renderer.data_source clear_button = bkwidgets.Button(label="clear", button_type="success") clear_button.on_click(clear_callback) # レイアウト execute_button_area = bklayouts.layout([[execute_button, clear_button]], sizing_mode="stretch_width") execute_area = bklayouts.layout( [ target_text, source_text, cutoff_text, execute_button_area, dependency_table ], sizing_mode="stretch_width", ) operation_area = bklayouts.layout([data_table, execute_area], sizing_mode="stretch_both") layout = bklayouts.layout([[p, operation_area]], sizing_mode="stretch_both") bkio.curdoc().add_root(layout)
def tool_handler(self, doc): from bokeh import events from bokeh.layouts import row, column, widgetbox from bokeh.models.mappers import LinearColorMapper from bokeh.models import widgets from bokeh.plotting import figure if len(self.arr.shape) != 2: raise AnalysisError( 'Cannot use mask tool on non image-like spectra') arr = self.arr x_coords, y_coords = arr.coords[arr.dims[0]], arr.coords[arr.dims[1]] default_palette = self.default_palette self.app_context.update({ 'region_options': [], 'regions': {}, 'data': arr, 'data_range': { 'x': (np.min(x_coords.values), np.max(x_coords.values)), 'y': (np.min(y_coords.values), np.max(y_coords.values)), }, }) self.cursor = [ np.mean(self.data_range['x']), np.mean(self.data_range['y']) ] self.color_maps['main'] = LinearColorMapper(default_palette, low=np.min(arr.values), high=np.max(arr.values), nan_color='black') main_tools = ["wheel_zoom", "tap", "reset"] main_title = 'Mask Tool: WARNING Unidentified' try: main_title = 'Mask Tool: {}'.format(arr.S.label[:60]) except: pass self.figures['main'] = figure( tools=main_tools, plot_width=self.app_main_size, plot_height=self.app_main_size, min_border=10, min_border_left=20, toolbar_location='left', x_axis_location='below', y_axis_location='right', title=main_title, x_range=self.data_range['x'], y_range=self.data_range['y'], ) self.figures['main'].xaxis.axis_label = arr.dims[0] self.figures['main'].yaxis.axis_label = arr.dims[1] self.plots['main'] = self.figures['main'].image( [np.asarray(arr.values.T)], x=self.data_range['x'][0], y=self.data_range['y'][0], dw=self.data_range['x'][1] - self.data_range['x'][0], dh=self.data_range['y'][1] - self.data_range['y'][0], color_mapper=self.color_maps['main']) self.add_cursor_lines(self.figures['main']) region_patches = self.figures['main'].patches(xs=[], ys=[], color='white', alpha=0.35, line_width=1) def add_point_to_region(): if self.active_region in self.regions: self.regions[self.active_region]['points'].append( list(self.cursor)) update_region_display() self.save_app() def click_main_image(event): self.cursor = [event.x, event.y] if self.pointer_mode == 'region': add_point_to_region() POINTER_MODES = [ ( 'Cursor', 'cursor', ), ( 'Region', 'region', ), ] def perform_mask(data=None, **kwargs): if data is None: data = arr data = normalize_to_spectrum(data) return apply_mask(data, self.app_context['mask'], **kwargs) self.app_context['perform_mask'] = perform_mask self.app_context['mask'] = None pointer_dropdown = widgets.Dropdown(label='Pointer Mode', button_type='primary', menu=POINTER_MODES) self.region_dropdown = widgets.Dropdown(label='Active Region', button_type='primary', menu=self.region_options) edge_mask_button = widgets.Button(label='Edge Mask') region_name_input = widgets.TextInput(placeholder='Region name...') add_region_button = widgets.Button(label='Add Region') clear_region_button = widgets.Button(label='Clear Region') remove_region_button = widgets.Button(label='Remove Region') main_color_range_slider = widgets.RangeSlider(start=0, end=100, value=( 0, 100, ), title='Color Range') def on_click_edge_mask(): if self.active_region in self.regions: old_points = self.regions[self.active_region]['points'] dims = [d for d in arr.dims if 'eV' != d] energy_index = arr.dims.index('eV') max_energy = np.max([p[energy_index] for p in old_points]) other_dim = dims[0] other_coord = arr.coords[other_dim].values min_other, max_other = np.min(other_coord), np.max(other_coord) min_e = np.min(arr.coords['eV'].values) if arr.dims.index('eV') == 0: before = [[min_e - 3, min_other - 1], [0, min_other - 1]] after = [[0, max_other + 1], [min_e - 3, max_other + 1]] else: before = [[min_other - 1, min_e - 3], [min_other - 1, 0]] after = [[max_other + 1, 0], [max_other + 1, min_e - 3]] self.regions[ self.active_region]['points'] = before + old_points + after self.app_context['mask'] = self.app_context['mask'] or {} self.app_context['mask']['fermi'] = max_energy update_region_display() self.save_app() def add_region(region_name): if region_name not in self.regions: self.region_options.append(( region_name, region_name, )) self.region_dropdown.menu = self.region_options self.regions[region_name] = { 'points': [], 'name': region_name, } if self.active_region is None: self.active_region = region_name self.save_app() def on_change_active_region(attr, old_region_id, region_id): self.app_context['active_region'] = region_id self.active_region = region_id self.save_app() def on_change_pointer_mode(attr, old_pointer_mode, pointer_mode): self.app_context['pointer_mode'] = pointer_mode self.pointer_mode = pointer_mode self.save_app() def update_region_display(): region_names = self.regions.keys() if self.app_context['mask'] is None: self.app_context['mask'] = {} self.app_context['mask'].update({ 'dims': arr.dims, 'polys': [r['points'] for r in self.regions.values()] }) region_patches.data_source.data = { 'xs': [[p[0] for p in self.regions[r]['points']] for r in region_names], 'ys': [[p[1] for p in self.regions[r]['points']] for r in region_names], } self.save_app() self.update_region_display = update_region_display def on_clear_region(): if self.active_region in self.regions: self.regions[self.active_region]['points'] = [] update_region_display() def on_remove_region(): if self.active_region in self.regions: del self.regions[self.active_region] new_region_options = [ b for b in self.region_options if b[0] != self.active_region ] self.region_dropdown.menu = new_region_options self.region_options = new_region_options self.active_region = None update_region_display() # Attach callbacks main_color_range_slider.on_change('value', self.update_colormap_for('main')) self.figures['main'].on_event(events.Tap, click_main_image) self.region_dropdown.on_change('value', on_change_active_region) pointer_dropdown.on_change('value', on_change_pointer_mode) add_region_button.on_click(lambda: add_region(region_name_input.value)) edge_mask_button.on_click(on_click_edge_mask) clear_region_button.on_click(on_clear_region) remove_region_button.on_click(on_remove_region) layout = row( column(self.figures['main']), column(*[ f for f in [ widgetbox( pointer_dropdown, self.region_dropdown, ), row( region_name_input, add_region_button, ), edge_mask_button if 'eV' in arr.dims else None, row( clear_region_button, remove_region_button, ), widgetbox( self._cursor_info, main_color_range_slider, ), ] if f is not None ])) doc.add_root(layout) doc.title = 'Mask Tool' self.load_app() self.save_app()
rows = select2() for row in rows: print(row['dept_name'], row['title']) def select3(title): tsql = "SELECT * FROM lgu.course where title like %s" print(tsql, title) with sqlConn.cursor(as_dict=Ture) as cursor: cursor.execute(tsql, title) rows = cursor.fetchall() for row in rows: print(row['dept_name'], row['title']) select3(title="bio%") button = wd.Button(label="Refresh") textbox = wd.TextInput(title="Name", value="", placeholder="enter name ....") def buttonClick(): print('button click') def textChange(attr, old, new): print(new) button.on_click(buttonClick) textbox.on_change("value", textChange) curdoc().add_root( wb(button, textbox) )
step=scStep) flSlider = widgets.Slider(title="Folding Frequency (Hz)", value=psr_dict['F0'] / 2, start=psr_dict['F0'] / 4, end=psr_dict['F0'] * 3, step=psr_dict['F0'] * .01) question1Group = widgets.RadioGroup(labels=[ "The plot would have 2 pulses with a larger Signal to Noise ratio", "The plot would have 1 pulse with a larger Signal to Noise ratio", "The plot would have 1 pulse with the same Signal to Noise ratio" ], active=None) question1Button = widgets.Button(label='Submit answer', button_type='success') question2Group = widgets.RadioGroup(labels=[ "Lower frequencies arrive earlier than higher frequencies", "Higher frequencies arrive earlier than lower frequencies" ], active=None) question2Button = widgets.Button(label='Submit answer', button_type='success') question3Group = widgets.RadioGroup(labels=["t > 1", "t = 1", "t < 1"], active=None) question3Button = widgets.Button(label='Submit answer', button_type='success') question4Group = widgets.RadioGroup(labels=[ "The pulse would have a lower peak with a 'tail' before the peak", "The pulse would have a lower peak with a 'tail' after the peak",
def build_widgets(df_source, cols, defaults, init_load=False, init_config={}): ''' Use a dataframe and its columns to set widget options. Widget values may be set by URL parameters via init_config. Args: df_source (pandas dataframe): Dataframe of the csv source. cols (dict): Keys are categories of columns of df_source, and values are a list of columns of that category. defaults (dict): Keys correspond to widgets, and values (str) are the default values of those widgets. init_load (boolean, optional): If this is the initial page load, then this will be True, else False. init_config (dict): Initial widget configuration passed via URL. Returns: wdg (ordered dict): Dictionary of bokeh.model.widgets. ''' #Add widgets wdg = collections.OrderedDict() wdg['data'] = bmw.TextInput(title='Data Source (required)', value=defaults['data_source'], css_classes=['wdgkey-data']) wdg['x_dropdown'] = bmw.Div(text='X-Axis (required)', css_classes=['x-dropdown']) wdg['x'] = bmw.Select(title='X-Axis (required)', value=defaults['x'], options=['None'] + cols['all'], css_classes=['wdgkey-x', 'x-drop']) wdg['x_group'] = bmw.Select(title='Group X-Axis By', value=defaults['x_group'], options=['None'] + cols['seriesable'], css_classes=['wdgkey-x_group', 'x-drop']) wdg['y_dropdown'] = bmw.Div(text='Y-Axis (required)', css_classes=['y-dropdown']) wdg['y'] = bmw.Select(title='Y-Axis (required)', value=defaults['y'], options=['None'] + cols['all'], css_classes=['wdgkey-y', 'y-drop']) wdg['y_agg'] = bmw.Select(title='Y-Axis Aggregation', value='Sum', options=AGGREGATIONS, css_classes=['wdgkey-y_agg', 'y-drop']) wdg['series_dropdown'] = bmw.Div(text='Series', css_classes=['series-dropdown']) wdg['series'] = bmw.Select(title='Separate Series By', value=defaults['series'], options=['None'] + cols['seriesable'], css_classes=['wdgkey-series', 'series-drop']) wdg['series_legend'] = bmw.Div(text='', css_classes=['series-drop']) wdg['explode_dropdown'] = bmw.Div(text='Explode', css_classes=['explode-dropdown']) wdg['explode'] = bmw.Select(title='Explode By', value=defaults['explode'], options=['None'] + cols['seriesable'], css_classes=['wdgkey-explode', 'explode-drop']) wdg['explode_group'] = bmw.Select(title='Group Exploded Charts By', value=defaults['explode_group'], options=['None'] + cols['seriesable'], css_classes=['wdgkey-explode_group', 'explode-drop']) wdg['filters'] = bmw.Div(text='Filters', css_classes=['filters-dropdown']) for j, col in enumerate(cols['filterable']): val_list = [str(i) for i in sorted(df_source[col].unique().tolist())] wdg['heading_filter_'+str(j)] = bmw.Div(text=col, css_classes=['filter-head']) wdg['filter_'+str(j)] = bmw.CheckboxGroup(labels=val_list, active=list(range(len(val_list))), css_classes=['wdgkey-filter_'+str(j), 'filter']) wdg['update'] = bmw.Button(label='Update Filters', button_type='success', css_classes=['filters-update']) wdg['adjustments'] = bmw.Div(text='Plot Adjustments', css_classes=['adjust-dropdown']) wdg['chart_type'] = bmw.Select(title='Chart Type', value=defaults['chart_type'], options=CHARTTYPES, css_classes=['wdgkey-chart_type', 'adjust-drop']) wdg['plot_width'] = bmw.TextInput(title='Plot Width (px)', value=str(PLOT_WIDTH), css_classes=['wdgkey-plot_width', 'adjust-drop']) wdg['plot_height'] = bmw.TextInput(title='Plot Height (px)', value=str(PLOT_HEIGHT), css_classes=['wdgkey-plot_height', 'adjust-drop']) wdg['plot_title'] = bmw.TextInput(title='Plot Title', value='', css_classes=['wdgkey-plot_title', 'adjust-drop']) wdg['plot_title_size'] = bmw.TextInput(title='Plot Title Font Size', value=str(PLOT_FONT_SIZE), css_classes=['wdgkey-plot_title_size', 'adjust-drop']) wdg['opacity'] = bmw.TextInput(title='Opacity (0-1)', value=str(OPACITY), css_classes=['wdgkey-opacity', 'adjust-drop']) wdg['x_scale'] = bmw.TextInput(title='X Scale', value=str(X_SCALE), css_classes=['wdgkey-x_scale', 'adjust-drop']) wdg['x_min'] = bmw.TextInput(title='X Min', value='', css_classes=['wdgkey-x_min', 'adjust-drop']) wdg['x_max'] = bmw.TextInput(title='X Max', value='', css_classes=['wdgkey-x_max', 'adjust-drop']) wdg['x_title'] = bmw.TextInput(title='X Title', value='', css_classes=['wdgkey-x_title', 'adjust-drop']) wdg['x_title_size'] = bmw.TextInput(title='X Title Font Size', value=str(PLOT_FONT_SIZE), css_classes=['wdgkey-x_title_size', 'adjust-drop']) wdg['x_major_label_size'] = bmw.TextInput(title='X Labels Font Size', value=str(PLOT_AXIS_LABEL_SIZE), css_classes=['wdgkey-x_major_label_size', 'adjust-drop']) wdg['x_major_label_orientation'] = bmw.TextInput(title='X Labels Degrees', value=str(PLOT_LABEL_ORIENTATION), css_classes=['wdgkey-x_major_label_orientation', 'adjust-drop']) wdg['y_scale'] = bmw.TextInput(title='Y Scale', value=str(Y_SCALE), css_classes=['wdgkey-y_scale', 'adjust-drop']) wdg['y_min'] = bmw.TextInput(title='Y Min', value='', css_classes=['wdgkey-y_min', 'adjust-drop']) wdg['y_max'] = bmw.TextInput(title='Y Max', value='', css_classes=['wdgkey-y_max', 'adjust-drop']) wdg['y_title'] = bmw.TextInput(title='Y Title', value='', css_classes=['wdgkey-y_title', 'adjust-drop']) wdg['y_title_size'] = bmw.TextInput(title='Y Title Font Size', value=str(PLOT_FONT_SIZE), css_classes=['wdgkey-y_title_size', 'adjust-drop']) wdg['y_major_label_size'] = bmw.TextInput(title='Y Labels Font Size', value=str(PLOT_AXIS_LABEL_SIZE), css_classes=['wdgkey-y_major_label_size', 'adjust-drop']) wdg['circle_size'] = bmw.TextInput(title='Circle Size (Dot Only)', value=str(CIRCLE_SIZE), css_classes=['wdgkey-circle_size', 'adjust-drop']) wdg['bar_width'] = bmw.TextInput(title='Bar Width (Bar Only)', value=str(BAR_WIDTH), css_classes=['wdgkey-bar_width', 'adjust-drop']) wdg['line_width'] = bmw.TextInput(title='Line Width (Line Only)', value=str(LINE_WIDTH), css_classes=['wdgkey-line_width', 'adjust-drop']) wdg['download'] = bmw.Button(label='Download csv', button_type='success') wdg['export_config'] = bmw.Div(text='Export Config to URL', css_classes=['export-config', 'bk-bs-btn', 'bk-bs-btn-success']) #use init_config (from 'widgets' parameter in URL query string) to configure widgets. if init_load: for key in init_config: if key in wdg: if hasattr(wdg[key], 'value'): wdg[key].value = str(init_config[key]) elif hasattr(wdg[key], 'active'): wdg[key].active = init_config[key] #Add update functions for widgets wdg['data'].on_change('value', update_data) wdg['update'].on_click(update_plots) wdg['download'].on_click(download) for name in wdg_col: wdg[name].on_change('value', update_wdg_col) for name in wdg_non_col: wdg[name].on_change('value', update_wdg) return wdg
def tool_handler(self, doc): from bokeh.layouts import row, column, widgetbox from bokeh.models.mappers import LinearColorMapper from bokeh.models import widgets from bokeh.plotting import figure if len(self.arr.shape) != 2: raise AnalysisError( 'Cannot use the band tool on non image-like spectra') arr = self.arr x_coords, y_coords = arr.coords[arr.dims[0]], arr.coords[arr.dims[1]] default_palette = self.default_palette self.app_context.update({ 'bands': {}, 'center_float': None, 'data': arr, 'data_range': { 'x': (np.min(x_coords.values), np.max(x_coords.values)), 'y': (np.min(y_coords.values), np.max(y_coords.values)), }, 'direction_normal': True, 'fit_mode': 'mdc', }) figures, plots, app_widgets = self.app_context['figures'], self.app_context['plots'], \ self.app_context['widgets'] self.cursor = [ np.mean(self.data_range['x']), np.mean(self.data_range['y']) ] self.color_maps['main'] = LinearColorMapper(default_palette, low=np.min(arr.values), high=np.max(arr.values), nan_color='black') main_tools = ["wheel_zoom", "tap", "reset"] main_title = 'Band Tool: WARNING Unidentified' try: main_title = 'Band Tool: {}'.format(arr.S.label[:60]) except: pass figures['main'] = figure(tools=main_tools, plot_width=self.app_main_size, plot_height=self.app_main_size, min_border=10, min_border_left=50, toolbar_location='left', x_axis_location='below', y_axis_location='right', title=main_title, x_range=self.data_range['x'], y_range=self.data_range['y']) figures['main'].xaxis.axis_label = arr.dims[0] figures['main'].yaxis.axis_label = arr.dims[1] figures['main'].toolbar.logo = None figures['main'].background_fill_color = "#fafafa" plots['main'] = figures['main'].image( [arr.values.T], x=self.app_context['data_range']['x'][0], y=self.app_context['data_range']['y'][0], dw=self.app_context['data_range']['x'][1] - self.app_context['data_range']['x'][0], dh=self.app_context['data_range']['y'][1] - self.app_context['data_range']['y'][0], color_mapper=self.app_context['color_maps']['main']) # add lines self.add_cursor_lines(figures['main']) band_lines = figures['main'].multi_line(xs=[], ys=[], line_color='white', line_width=1) def append_point_to_band(): cursor = self.cursor if self.active_band in self.app_context['bands']: self.app_context['bands'][self.active_band]['points'].append( list(cursor)) update_band_display() def click_main_image(event): self.cursor = [event.x, event.y] if self.pointer_mode == 'band': append_point_to_band() update_main_colormap = self.update_colormap_for('main') POINTER_MODES = [ ( 'Cursor', 'cursor', ), ( 'Band', 'band', ), ] FIT_MODES = [ ( 'EDC', 'edc', ), ( 'MDC', 'mdc', ), ] DIRECTIONS = [ ( 'From Bottom/Left', 'forward', ), ('From Top/Right', 'reverse'), ] BAND_TYPES = [( 'Lorentzian', 'Lorentzian', ), ( 'Voigt', 'Voigt', ), ( 'Gaussian', 'Gaussian', )] band_classes = { 'Lorentzian': band.Band, 'Gaussian': band.BackgroundBand, 'Voigt': band.VoigtBand, } self.app_context['band_options'] = [] def pack_bands(): packed_bands = {} for band_name, band_description in self.app_context['bands'].items( ): if not band_description['points']: raise AnalysisError('Band {} is empty.'.format(band_name)) stray = None try: stray = float(band_description['center_float']) except (KeyError, ValueError, TypeError): try: stray = float(self.app_context['center_float']) except Exception: pass packed_bands[band_name] = { 'name': band_name, 'band': band_classes.get(band_description['type'], band.Band), 'dims': self.arr.dims, 'params': { 'amplitude': { 'min': 0 }, }, 'points': band_description['points'], } if stray is not None: packed_bands[band_name]['params']['stray'] = stray return packed_bands def fit(override_data=None): packed_bands = pack_bands() dims = list(self.arr.dims) if 'eV' in dims: dims.remove('eV') angular_direction = dims[0] if isinstance(override_data, xr.Dataset): override_data = normalize_to_spectrum(override_data) return fit_patterned_bands( override_data if override_data is not None else self.arr, packed_bands, fit_direction='eV' if self.app_context['fit_mode'] == 'edc' else angular_direction, direction_normal=self.app_context['direction_normal']) self.app_context['pack_bands'] = pack_bands self.app_context['fit'] = fit self.pointer_dropdown = widgets.Dropdown(label='Pointer Mode', button_type='primary', menu=POINTER_MODES) self.direction_dropdown = widgets.Dropdown(label='Fit Direction', button_type='primary', menu=DIRECTIONS) self.band_dropdown = widgets.Dropdown( label='Active Band', button_type='primary', menu=self.app_context['band_options']) self.fit_mode_dropdown = widgets.Dropdown(label='Mode', button_type='primary', menu=FIT_MODES) self.band_type_dropdown = widgets.Dropdown(label='Band Type', button_type='primary', menu=BAND_TYPES) self.band_name_input = widgets.TextInput(placeholder='Band name...') self.center_float_widget = widgets.TextInput( placeholder='Center Constraint') self.center_float_copy = widgets.Button(label='Copy to all...') self.add_band_button = widgets.Button(label='Add Band') self.clear_band_button = widgets.Button(label='Clear Band') self.remove_band_button = widgets.Button(label='Remove Band') self.main_color_range_slider = widgets.RangeSlider(start=0, end=100, value=( 0, 100, ), title='Color Range') def add_band(band_name): if band_name not in self.app_context['bands']: self.app_context['band_options'].append(( band_name, band_name, )) self.band_dropdown.menu = self.app_context['band_options'] self.app_context['bands'][band_name] = { 'type': 'Lorentzian', 'points': [], 'name': band_name, 'center_float': None, } if self.active_band is None: self.active_band = band_name self.save_app() def on_copy_center_float(): for band_name in self.app_context['bands'].keys(): self.app_context['bands'][band_name][ 'center_float'] = self.app_context['center_float'] self.save_app() def on_change_active_band(attr, old_band_id, band_id): self.app_context['active_band'] = band_id self.active_band = band_id def on_change_pointer_mode(attr, old_pointer_mode, pointer_mode): self.app_context['pointer_mode'] = pointer_mode self.pointer_mode = pointer_mode def set_center_float_value(attr, old_value, new_value): self.app_context['center_float'] = new_value if self.active_band in self.app_context['bands']: self.app_context['bands'][ self.active_band]['center_float'] = new_value self.save_app() def set_fit_direction(attr, old_direction, new_direction): self.app_context['direction_normal'] = new_direction == 'forward' self.save_app() def set_fit_mode(attr, old_mode, new_mode): self.app_context['fit_mode'] = new_mode self.save_app() def set_band_type(attr, old_type, new_type): if self.active_band in self.app_context['bands']: self.app_context['bands'][self.active_band]['type'] = new_type self.save_app() def update_band_display(): band_names = self.app_context['bands'].keys() band_lines.data_source.data = { 'xs': [[p[0] for p in self.app_context['bands'][b]['points']] for b in band_names], 'ys': [[p[1] for p in self.app_context['bands'][b]['points']] for b in band_names], } self.save_app() self.update_band_display = update_band_display def on_clear_band(): if self.active_band in self.app_context['bands']: self.app_context['bands'][self.active_band]['points'] = [] update_band_display() def on_remove_band(): if self.active_band in self.app_context['bands']: del self.app_context['bands'][self.active_band] new_band_options = [ b for b in self.app_context['band_options'] if b[0] != self.active_band ] self.band_dropdown.menu = new_band_options self.app_context['band_options'] = new_band_options self.active_band = None update_band_display() # Attach callbacks self.main_color_range_slider.on_change('value', update_main_colormap) figures['main'].on_event(events.Tap, click_main_image) self.band_dropdown.on_change('value', on_change_active_band) self.pointer_dropdown.on_change('value', on_change_pointer_mode) self.add_band_button.on_click( lambda: add_band(self.band_name_input.value)) self.clear_band_button.on_click(on_clear_band) self.remove_band_button.on_click(on_remove_band) self.center_float_copy.on_click(on_copy_center_float) self.center_float_widget.on_change('value', set_center_float_value) self.direction_dropdown.on_change('value', set_fit_direction) self.fit_mode_dropdown.on_change('value', set_fit_mode) self.band_type_dropdown.on_change('value', set_band_type) layout = row( column(figures['main']), column( widgetbox( self.pointer_dropdown, self.band_dropdown, self.fit_mode_dropdown, self.band_type_dropdown, self.direction_dropdown, ), row( self.band_name_input, self.add_band_button, ), row( self.clear_band_button, self.remove_band_button, ), row(self.center_float_widget, self.center_float_copy), widgetbox( self._cursor_info, self.main_color_range_slider, ))) doc.add_root(layout) doc.title = 'Band Tool' self.load_app() self.save_app()
def __init__(self, data_source): self.update_button = bk_widgets.Button(label='Update graphs') self.layout = None self.data_source = data_source
try: return pymssql.connect(**attr) except Exception as e: print(e) quit() # Here are UI Controls widgets GroupLetters = wd.RadioButtonGroup(labels=list(string.ascii_uppercase), active=-1) dept_input = wd.TextInput(value="", title="Department", placeholder="Seach department") title_input = wd.TextInput(value="", title="Title", placeholder="Serach title") options = wd.RadioGroup(labels=['and', 'or'], active=0, width=100, inline=True) button_refresh = wd.Button(label="Refresh") Group_choices = wd.RadioButtonGroup( name="Title", labels=['Begins with ...', '... contains ...', '... ends with'], active=1) Department_choices = wd.RadioButtonGroup( name="Department", labels=['Begins with ...', '... contains ...', '... ends with'], active=1) Text_Instruction = wd.Paragraph(text="Option") # Data used in Tab1 columns = [ wd.TableColumn(field="id", title="Course ID"), wd.TableColumn(field="title", title="Title"), wd.TableColumn(field="dept", title="Department"),
def refreshByButton(new): letter = btnGroupLetters.labels[new] rows = fetchRows( "select * from lgu.course where title like '{}%'".format(letter)) updateCourseData(rows) btnGroupLetters.on_click(refreshByButton) # filter by text filtr = ['begins with...', '...contains...', '...ends with'] btnGroupTitle = wd.RadioButtonGroup(labels=filtr, active=1) btnGroupDept = wd.RadioButtonGroup(labels=filtr, active=1) refresh = wd.Button(label='Refresh') title_input = wd.TextInput(value='', title='Title:', placeholder='') dept_input = wd.TextInput(value='', title='Department:', placeholder='') optionGroup = wd.RadioGroup(labels=['and', 'or'], active=0, width=100, inline=True) def refreshByFilter(): conj = optionGroup.labels[optionGroup.active] title, dept = title_input.value, dept_input.value titleCondition = "title like '{}'".format( [title + '%', '%' + title + '%', '%' + title][btnGroupTitle.active]) deptCondition = "dept_name like '{}'".format(
def tool_handler(self, doc): from bokeh import events from bokeh.layouts import row, column, widgetbox from bokeh.models.mappers import LinearColorMapper from bokeh.models import widgets, warnings from bokeh.plotting import figure if len(self.arr.shape) != 2: raise AnalysisError( 'Cannot use path tool on non image-like spectra') arr = self.arr x_coords, y_coords = arr.coords[arr.dims[0]], arr.coords[arr.dims[1]] default_palette = self.default_palette self.app_context.update({ 'path_options': [], 'active_path': None, 'paths': {}, 'data': arr, 'data_range': { 'x': (np.min(x_coords.values), np.max(x_coords.values)), 'y': (np.min(y_coords.values), np.max(y_coords.values)), }, }) self.cursor = [ np.mean(self.data_range['x']), np.mean(self.data_range['y']) ] self.color_maps['main'] = LinearColorMapper(default_palette, low=np.min(arr.values), high=np.max(arr.values), nan_color='black') main_tools = ["wheel_zoom", "tap", "reset"] main_title = 'Path Tool: WARNING Unidentified' try: main_title = 'Path Tool: {}'.format(arr.S.label[:60]) except: pass self.figures['main'] = figure( tools=main_tools, plot_width=self.app_main_size, plot_height=self.app_main_size, min_border=10, min_border_left=20, toolbar_location='left', x_axis_location='below', y_axis_location='right', title=main_title, x_range=self.data_range['x'], y_range=self.data_range['y'], ) self.figures['main'].xaxis.axis_label = arr.dims[0] self.figures['main'].yaxis.axis_label = arr.dims[1] self.plots['main'] = self.figures['main'].image( [np.asarray(arr.values.T)], x=self.data_range['x'][0], y=self.data_range['y'][0], dw=self.data_range['x'][1] - self.data_range['x'][0], dh=self.data_range['y'][1] - self.data_range['y'][0], color_mapper=self.color_maps['main']) self.plots['paths'] = self.figures['main'].multi_line( xs=[], ys=[], line_color='white', line_width=2) self.add_cursor_lines(self.figures['main']) def add_point_to_path(): if self.active_path in self.paths: self.paths[self.active_path]['points'].append(list( self.cursor)) update_path_display() self.save_app() def click_main_image(event): self.cursor = [event.x, event.y] if self.pointer_mode == 'path': add_point_to_path() POINTER_MODES = [ ( 'Cursor', 'cursor', ), ( 'Path', 'path', ), ] def convert_to_xarray(): """ For each of the paths, we will create a dataset which has an index dimension, and datavariables for each of the coordinate dimensions :return: """ def convert_single_path_to_xarray(points): vars = { d: np.array([p[i] for p in points]) for i, d in enumerate(self.arr.dims) } coords = { 'index': np.array(range(len(points))), } vars = { k: xr.DataArray(v, coords=coords, dims=['index']) for k, v in vars.items() } return xr.Dataset(data_vars=vars, coords=coords) return { path['name']: convert_single_path_to_xarray(path['points']) for path in self.paths.values() } def select(data=None, **kwargs): if data is None: data = self.arr if len(self.paths) > 1: warnings.warn('Only using first path.') return select_along_path(path=list( convert_to_xarray().items())[0][1], data=data, **kwargs) self.app_context['to_xarray'] = convert_to_xarray self.app_context['select'] = select pointer_dropdown = widgets.Dropdown(label='Pointer Mode', button_type='primary', menu=POINTER_MODES) self.path_dropdown = widgets.Dropdown(label='Active Path', button_type='primary', menu=self.path_options) path_name_input = widgets.TextInput(placeholder='Path name...') add_path_button = widgets.Button(label='Add Path') clear_path_button = widgets.Button(label='Clear Path') remove_path_button = widgets.Button(label='Remove Path') main_color_range_slider = widgets.RangeSlider(start=0, end=100, value=( 0, 100, ), title='Color Range') def add_path(path_name): if path_name not in self.paths: self.path_options.append(( path_name, path_name, )) self.path_dropdown.menu = self.path_options self.paths[path_name] = { 'points': [], 'name': path_name, } if self.active_path is None: self.active_path = path_name self.save_app() def on_change_active_path(attr, old_path_id, path_id): self.debug_text = path_id self.app_context['active_path'] = path_id self.active_path = path_id self.save_app() def on_change_pointer_mode(attr, old_pointer_mode, pointer_mode): self.app_context['pointer_mode'] = pointer_mode self.pointer_mode = pointer_mode self.save_app() def update_path_display(): self.plots['paths'].data_source.data = { 'xs': [[point[0] for point in p['points']] for p in self.paths.values()], 'ys': [[point[1] for point in p['points']] for p in self.paths.values()], } self.save_app() self.update_path_display = update_path_display def on_clear_path(): if self.active_path in self.paths: self.paths[self.active_path]['points'] = [] update_path_display() def on_remove_path(): if self.active_path in self.paths: del self.paths[self.active_path] new_path_options = [ b for b in self.path_options if b[0] != self.active_path ] self.path_dropdown.menu = new_path_options self.path_options = new_path_options self.active_path = None update_path_display() # Attach callbacks main_color_range_slider.on_change('value', self.update_colormap_for('main')) self.figures['main'].on_event(events.Tap, click_main_image) self.path_dropdown.on_change('value', on_change_active_path) pointer_dropdown.on_change('value', on_change_pointer_mode) add_path_button.on_click(lambda: add_path(path_name_input.value)) clear_path_button.on_click(on_clear_path) remove_path_button.on_click(on_remove_path) layout = row( column(self.figures['main']), column( widgetbox( pointer_dropdown, self.path_dropdown, ), row( path_name_input, add_path_button, ), row( clear_path_button, remove_path_button, ), widgetbox( self._cursor_info, main_color_range_slider, ), self.debug_div, )) doc.add_root(layout) doc.title = 'Path Tool' self.load_app() self.save_app()