def create_alpha_diversity_tab(): img_shannon = '<img src="plot_shannon.png" />' img_shannon_diff = '<img src="plot_shannon_diff.png" />' div_plot_shannon = Div(text=img_shannon) source = ColumnDataSource(data=dict( active=[img_shannon, img_shannon_diff])) checkbox_callback = CustomJS(args=dict(source=source), code=""" if(this.active.length > 0) { div_plot_shannon.text = source.data['active'][1]; } else { div_plot_shannon.text = source.data['active'][0]; } """) checkbox_group = CheckboxGroup( labels=["Absolute differences to gold standard"], active=[], width=300, css_classes=['bk-checkbox-shannon']) checkbox_group.js_on_click(checkbox_callback) checkbox_callback.args["div_plot_shannon"] = div_plot_shannon shannon_column = column(checkbox_group, div_plot_shannon, responsive=True, css_classes=[ 'bk-shannon-plots', 'bk-width-auto', 'bk-width-auto-main' ]) shannon_panel = Panel(child=shannon_column, title='Shannon') tabs_plots = Tabs(tabs=[shannon_panel], css_classes=['bk-tabs-margin', 'bk-tabs-margin-lr']) return tabs_plots
dropdown_disabled.on_click( lambda value: print('dropdown_disabled: %s' % value)) dropdown_disabled.js_on_click( CustomJS( code="console.log('dropdown_disabled: ' + this.value, this.toString())" )) #dropdown_split = Dropdown(label="Split button", button_type="danger", menu=menu, default_value="default") #dropdown_split.on_click(lambda value: print('dropdown_split: %s' % value)) #dropdown_split.js_on_click(CustomJS(code="console.log('dropdown_split: ' + this.value, this.toString())")) checkbox_group = CheckboxGroup(labels=["Option 1", "Option 2", "Option 3"], active=[0, 1]) checkbox_group.on_click(lambda value: print('checkbox_group: %s' % value)) checkbox_group.js_on_click( CustomJS( code="console.log('checkbox_group: ' + this.active, this.toString())")) radio_group = RadioGroup(labels=["Option 1", "Option 2", "Option 3"], active=0) radio_group.on_click(lambda value: print('radio_group: %s' % value)) radio_group.js_on_click( CustomJS( code="console.log('radio_group: ' + this.active, this.toString())")) checkbox_button_group = CheckboxButtonGroup( labels=["Option 1", "Option 2", "Option 3"], active=[0, 1]) checkbox_button_group.on_click( lambda value: print('checkbox_button_group: %s' % value)) checkbox_button_group.js_on_click( CustomJS( code=
args={ 'aline': aline, 'bline': bline }) callback2 = CustomJS(code="""cline.visible = false; // aline and etc.. are dline.visible = false; // passed in from args // cb_obj is injected in thanks to the callback if (cb_obj.active.includes(0)){cline.visible = true;} // 0 index box is aline if (cb_obj.active.includes(1)){dline.visible = true;} // 1 index box is bline """, args={ 'cline': cline, 'dline': dline }) checkboxes1.js_on_click(callback1) checkboxes2.js_on_click(callback2) layout1 = row(p1, checkboxes1) layout2 = row(p2, checkboxes2) layout = column(layout1, layout2) # output_file('BV2_DUT_sensors_134_sections.html') # show(column(p1, p2, checkboxes)) curdoc().add_root(layout) curdoc().title = "Temperatures_BV12" show(layout)
def DesnivelPositivoAcumulado(DatosBokeh, EjeX, MetricasAuxiliares): """ GRAFICO AREA | DESNIVEL POSITIVO ACUMULADO """ # Creacion del diccionario de metricas auxiliares DiccionarioVariables = ParametrosVariables(DatosBokeh) # Generacion del codigo JavaScript que habilita la visualizacion de metricas auxiliares CodigoJS = GeneracionCodigoJS(MetricasAuxiliares) # Asignacion de tamaño del punto en graficas discretas SizeCircle = FunctionSizeCircle(DatosBokeh) # Creacion de un grafica PLT = figure(width=1000, height=400, x_range=(DatosBokeh.data[EjeX].min(), DatosBokeh.data[EjeX].max()), y_range=(LimiteEjeY(DatosBokeh, 'DESNIVEL POSITIVO', 'Inferior'), LimiteEjeY(DatosBokeh, 'DESNIVEL POSITIVO', 'Superior')), tools='', toolbar_location=None) # Creacion del area bajo la linea de la metrica a partir del CDS Area = DatosBokeh.to_df().copy().reset_index()[[ EjeX, 'DesnivelPositivo[m]' ]].set_index(EjeX) Area.rename(columns={'DesnivelPositivo[m]': 'Area'}, inplace=True) AreaBottom = Area[::-1] AreaBottom['Area'] = 0 PLT.patch(x=hstack((AreaBottom.index, Area.index)), y=hstack((AreaBottom['Area'], Area['Area'])), color=Lavender[0], alpha=1, line_color=None) # Inclusion de datos PLT_Linea = PLT.line(EjeX, 'DesnivelPositivo[m]', source=DatosBokeh, color=Lavender[1], line_width=2, line_cap='round') PLT.add_tools( HoverTool(tooltips=[('', '@{DesnivelPositivo[m]}{int} m')], renderers=[PLT_Linea], mode='vline')) # Inclusion de lineas auxiliares ListadoMetricasAuxiliares = {} for Metrica in MetricasAuxiliares: if DiccionarioVariables[Metrica]['Tipo'] == 'circle': ListadoMetricasAuxiliares[ 'l' + str(MetricasAuxiliares.index(Metrica))] = PLT.circle( EjeX, DiccionarioVariables[Metrica]['Variable'].split('[', 1)[0] + DiccionarioVariables['DESNIVEL POSITIVO']['Sufijo'], source=DiccionarioVariables[Metrica]['CDS'], size=SizeCircle, line_color=DiccionarioVariables[Metrica]['Color'], color=DiccionarioVariables[Metrica]['Color'], **DiccionarioVariables[Metrica]['Propiedades']) elif DiccionarioVariables[Metrica]['Tipo'] == 'step': ListadoMetricasAuxiliares[ 'l' + str(MetricasAuxiliares.index(Metrica))] = PLT.step( EjeX, DiccionarioVariables[Metrica]['Variable'].split('[', 1)[0] + DiccionarioVariables['DESNIVEL POSITIVO']['Sufijo'], source=DiccionarioVariables[Metrica]['CDS'], color=DiccionarioVariables[Metrica]['Color'], **DiccionarioVariables[Metrica]['Propiedades']) else: ListadoMetricasAuxiliares[ 'l' + str(MetricasAuxiliares.index(Metrica))] = PLT.line( EjeX, DiccionarioVariables[Metrica]['Variable'].split('[', 1)[0] + DiccionarioVariables['DESNIVEL POSITIVO']['Sufijo'], source=DiccionarioVariables[Metrica]['CDS'], color=DiccionarioVariables[Metrica]['Color'], **DiccionarioVariables[Metrica]['Propiedades']) # Atributos PLT.title.text = 'DESNIVEL POSITIVO ACUMULADO' PLT.sizing_mode = 'fixed' PLT.yaxis.axis_label = 'Desnivel positivo acumulado [m]' PLT.yaxis.formatter = NumeralTickFormatter(format='0') PLT.grid.visible = False PLT.yaxis.minor_tick_line_color = None PLT.yaxis.major_label_overrides = FormateoEjes( DatosBokeh.data['DesnivelPositivo[m]'], 100, 1) # Asignacion de opciones de visualizacion del eje X if EjeX == 'Distancia[m]': PLT.xaxis.axis_label = 'Distancia' PLT.xaxis.formatter = NumeralTickFormatter(format='0') if DatosBokeh.data['Distancia[m]'].max() >= 4000: PLT.xaxis.ticker = SingleIntervalTicker(interval=1000) PLT.xaxis.major_label_overrides = FormateoEjes( DatosBokeh.data['Distancia[m]'], 1000, 1000, 0, 0) elif EjeX == 'TiempoActividad': PLT.xaxis.axis_label = 'Tiempo actividad' PLT.xaxis.formatter = DatetimeTickFormatter(hourmin='%H:%M:%S', minutes='%M:%S', seconds='%Ss') PLT.xaxis.ticker = DatetimeTicker() elif EjeX == 'TiempoTotal': PLT.xaxis.axis_label = 'Tiempo total' PLT.xaxis.formatter = DatetimeTickFormatter(hourmin='%H:%M:%S', minutes='%M:%S', seconds='%Ss') PLT.xaxis.ticker = DatetimeTicker() #Botones Botones = CheckboxGroup(labels=MetricasAuxiliares, active=[], width=100, height=380) ListadoMetricasAuxiliares['checkbox'] = Botones CodigoJSFrecuenciaCardiaca = CustomJS(code=CodigoJS, args=ListadoMetricasAuxiliares) Botones.js_on_click(CodigoJSFrecuenciaCardiaca) #Layout GridBotones = layout( [Spacer(width=100, height=25), Column(Botones, width=100, height=375)], sizing_mode='fixed', width=100, height=400) GridGrafica = gridplot([PLT, GridBotones], ncols=2, sizing_mode='stretch_width', toolbar_location=None, plot_width=1100, plot_height=400) return GridGrafica
def html_postages(coord=None, idx=None, veto=None, info=None, layer_list=None, BoxSize=40): plots = {} sources = [] layers = [] RA, DEC = coord[0], coord[1] scale_unit='pixscale' scale=0.262 boxsize = BoxSize #2*m*radius*3600 radius = BoxSize/(2 * 3600) size = int(round(boxsize/scale)) figsize = int(128) #print('BoxSize', boxsize) #print('Size', size) idx_list = idx #random.sample(list(idx), rows*cols) if info is None: info = {'RA':RA, 'DEC':DEC} if veto is None: veto = {'all':np.ones_like(RA, dtype=bool)} if layer_list is None: layer_list = ['dr9f-south', 'dr9f-south-model', 'dr9f-south-resid', 'dr9g-south', 'dr9g-south-model', 'dr9g-south-resid', 'dr9f-north', 'dr9f-north-model', 'dr9f-north-resid', 'dr9g-north', 'dr9g-north-model', 'dr9g-north-resid'] for idx in idx_list: RAidx = RA[idx] DECidx = DEC[idx] ramin, ramax = RAidx-radius, RAidx+radius decmin, decmax = DECidx-radius, DECidx+radius dra = (ramax - ramin)/40 ddec = (decmax - decmin)/40 mask = (RA > ramin + dra) & (RA < ramax - dra) & (DEC > decmin + ddec) & (DEC < decmax - ddec) TOOLTIPS = [] for key in info.keys(): TOOLTIPS.append((key, '@'+key)) p = figure(plot_width=2*figsize, plot_height=2*figsize, tooltips=TOOLTIPS, tools="tap, save, zoom_in, zoom_out, crosshair") p.axis.visible = False p.toolbar.logo = None p.toolbar_location = None #p.min_border = 0 layers2 = [] for layer in layer_list: source='https://www.legacysurvey.org/viewer-dev/jpeg-cutout/?ra=%.12f&dec=%.12f&%s=%g&layer=%s&size=%g' % (RAidx, DECidx, scale_unit, scale, layer, size) url='https://www.legacysurvey.org/viewer-dev?ra=%.12f&dec=%.12f&layer=%s&zoom=15' %(RAidx, DECidx, layer) imfig_source = ColumnDataSource(data=dict(url=[source], txt=[source])) image1 = ImageURL(url="url", x=0, y=1, w=size, h=size, anchor='bottom_left') img_source = p.add_glyph(imfig_source, image1) layers2.append(img_source) taptool = p.select(type=TapTool) taptool.callback = OpenURL(url=url) colors = ['green', 'red', 'blue', 'cyan', 'yellow'] circle_i = [] for color, key, val in zip(colors, veto.keys(), veto.values()): ravpix, decvpix = coordtopix(center=[RAidx, DECidx], coord=[RA[(mask) & (val)], DEC[(mask) & (val)]], size=size, scale=scale) data = {} data['x'] = ravpix data['y'] = decvpix for info_key, info_val in zip(info.keys(), info.values()): if isinstance(info_val[0], (bytes, bytearray)): data[info_key] = np.array(info_val)[(mask) & (val)].astype('U13') else: data[info_key] = np.array(info_val)[(mask) & (val)] sourceCirc = ColumnDataSource(data=data) circle = p.circle('x', 'y', source=sourceCirc, size=15, fill_color=None, line_color=color, line_width=3) circle_i.append(circle) lineh = Span(location=size/2, dimension='height', line_color='white', line_dash='solid', line_width=1) linew = Span(location=size/2, dimension='width', line_color='white', line_dash='solid', line_width=1) p.add_layout(lineh) p.add_layout(linew) p.background_fill_color = "black" #p.outline_line_width = 15 #p.outline_line_alpha = 0.7 p.xgrid.grid_line_color = None p.ygrid.grid_line_color = None plots[str(idx)] = p sources.append(circle_i) layers.append(layers2) checkbox = CheckboxGroup(labels=list(veto.keys()), active=list(np.arange(len(veto)))) iterable = [elem for part in [[('_'.join(['line',str(figid),str(lineid)]),line) for lineid,line in enumerate(elem)] for figid,elem in enumerate(sources)] for elem in part] checkbox_code = ''.join([elem[0]+'.visible=checkbox.active.includes('+elem[0].split('_')[-1]+');' for elem in iterable]) callback = CustomJS(args={key:value for key,value in iterable+[('checkbox',checkbox)]}, code=checkbox_code) # print('===== plots ======') # print(checkbox_code) # print('====') # print({key:value for key,value in iterable+[('checkbox',checkbox)]}) checkbox.js_on_click(callback) #script, div = components(plots) #print(div) radio = RadioGroup(labels=layer_list, active=len(layer_list)-1) iterable2 = [elem for part in [[('_'.join(['line',str(figid),str(lineid)]),line) for lineid,line in enumerate(elem)] for figid,elem in enumerate(layers)] for elem in part] # N = len(layer_list) text = [] for elem in iterable2[::N]: for n in range(N): text.append('%s%s.visible=false;' %(elem[0][:-1], str(n))) for n in range(N): if n == 0: text.append('if (cb_obj.active == 0) {%s%s.visible = true;}' %(elem[0][:-1], str(0))) if n != 0: text.append('else if (cb_obj.active == %s) {%s%s.visible = true;}' %(str(n), elem[0][:-1], str(n))) radiogroup_code = ''.join(text) callback2 = CustomJS(args={key:value for key,value in iterable2+[('radio',radio)]}, code=radiogroup_code) radio.js_on_change('active', callback2) # for key,val in zip(plots.keys(), plots.values()): # print(key, '\t', val) #script, div = components(plots) #controls = WidgetBox(radio, checkbox) #plots['controls'] = components(radio) #script_2, div_2 = components(controls) #print('===== plots ======') plots['checkbox'] = checkbox plots['radio'] = radio return components(plots)
def dash_line(x: str, y: str, data: pd.DataFrame, figsize: tuple = (1000, 400), title: str = None, x_axis_label: str = None, y_axis_label: str = None): """Create dashboard line plot Args: x (str): Column in x axis y (str): Column in y axis data (pd.DataFrame): Data frame contaning the above. It also must contain columns for the max, min and mean of y axis figsize (tuple, optional): Width and height of figure. Defaults to (1000, 400). title (str, optional): Figure title. Defaults to None. x_axis_label (str, optional): X-axis label. Defaults to None. y_axis_label (str, optional): Y-axis label. Defaults to None. Returns: bokeh object: Plotted figure References: [1] https://www.reddit.com/r/learnpython/comments/8ythxo/how_to_use_checkbox_in_bokeh_with_pandas/ Example: TODO: >>> show(dash_line()) """ # 1. Define variables y_max = f"{y}_max" y_min = f"{y}_min" y_mean = f"{y}_mean" title = title or f"{y} vs {x}" tools = "xwheel_pan, ywheel_pan, pan,wheel_zoom,xwheel_zoom,ywheel_zoom,box_zoom,reset,save" # 2. Instantiate plot object if np.issubdtype(data[x].dtype, np.datetime64): line = figure(x_axis_type="datetime", plot_width=figsize[0], plot_height=figsize[1], title=title, toolbar_location="above", tools=tools) else: line = figure(plot_width=figsize[0], plot_height=figsize[1], title=title, toolbar_location="above", tools=tools) ## 2.1. Add axes labels line.xaxis.axis_label = x or x_axis_label line.yaxis.axis_label = y or y_axis_label # 3. Add circles line.circle(x=x, y=y, source=data) # 4. Add hover tooltip ## 4.1. Format the tooltip tooltips = [(y, f"@{y}"), (x, f"@{x}")] hover = HoverTool(tooltips=tooltips) ## 4.2. Add the HoverTool to the figure line.add_tools(HoverTool(tooltips=tooltips)) # 5. Format figure ## 5.1. Remove grey frame line.outline_line_color = None ## 5.2. Remove axis line line.xaxis.axis_line_width = 0 line.yaxis.axis_line_width = 0 ## 5.3. Remove grid line.xgrid.grid_line_color = None line.ygrid.grid_line_color = None ## 5.4. Remove tick markers # line.xaxis.major_tick_line_color = None # turn off x-axis major ticks line.xaxis.minor_tick_line_color = None # turn off x-axis minor ticks # line.yaxis.major_tick_line_color = None # turn off y-axis major ticks line.yaxis.minor_tick_line_color = None # turn off y-axis minor ticks ## 5.5. Add text # mytext = Label(x=data[x].max(), y=data[y].iloc[-1], text=y) # line.add_layout(mytext) # 6. Create rendering objects for callback line_renderer = line.line(x=x, y=y, line_width=2, source=data) line_max = line.line(x=x, y=y_max, line_width=1, source=data, line_dash="dashed", line_alpha=0.25, line_color="black") line_mean = line.line(x=x, y=y_mean, line_width=1, source=data, line_dash="dotted", line_alpha=0.25, line_color="black") line_min = line.line(x=x, y=y_min, line_width=1, source=data, line_dash="dashed", line_alpha=0.25, line_color="black") # 7. Create checkbox callback. See [1] checkboxes = CheckboxGroup(labels=["max", "mean", "min"], active=[0, 1, 2]) callback = CustomJS( code="""line_max.visible = false; // same xline passed in from args line_mean.visible = false; line_min.visible = false; // cb_obj injected in by the callback if (cb_obj.active.includes(0)){line_max.visible = true;} if (cb_obj.active.includes(1)){line_mean.visible = true;} if (cb_obj.active.includes(2)){line_min.visible = true;} """, args={ 'line_max': line_max, 'line_mean': line_mean, 'line_min': line_min }) checkboxes.js_on_click(callback) return row(line, checkboxes)
toggle_active = Toggle(label="Toggle button (initially active)", button_type="success", active=True) toggle_active.js_on_click(CustomJS(code="console.log('toggle_active: ' + this.active, this.toString())")) menu = [("Item 1", "item_1_value"), ("Item 2", "item_2_value"), None, ("Item 3", "item_3_value")] dropdown = Dropdown(label="Dropdown button", button_type="warning", menu=menu) dropdown.js_on_click(CustomJS(code="console.log('dropdown: ' + this.value, this.toString())")) dropdown_disabled = Dropdown(label="Dropdown button (disabled)", button_type="warning", disabled=True, menu=menu) dropdown_disabled.js_on_click(CustomJS(code="console.log('dropdown_disabled: ' + this.value, this.toString())")) #dropdown_split = Dropdown(label="Split button", button_type="danger", menu=menu, default_value="default") #dropdown_split.js_on_click(CustomJS(code="console.log('dropdown_split: ' + this.value, this.toString())")) checkbox_group = CheckboxGroup(labels=["Option 1", "Option 2", "Option 3"], active=[0, 1]) checkbox_group.js_on_click(CustomJS(code="console.log('checkbox_group: ' + this.active, this.toString())")) radio_group = RadioGroup(labels=["Option 1", "Option 2", "Option 3"], active=0) radio_group.js_on_click(CustomJS(code="console.log('radio_group: ' + this.active, this.toString())")) checkbox_button_group = CheckboxButtonGroup(labels=["Option 1", "Option 2", "Option 3"], active=[0, 1]) checkbox_button_group.js_on_click(CustomJS(code="console.log('checkbox_button_group: ' + this.active, this.toString())")) radio_button_group = RadioButtonGroup(labels=["Option 1", "Option 2", "Option 3"], active=0) radio_button_group.js_on_click(CustomJS(code="console.log('radio_button_group: ' + this.active, this.toString())")) widget_box = WidgetBox(children=[ button, button_disabled, toggle_inactive, toggle_active, dropdown, dropdown_disabled, #dropdown_split, checkbox_group, radio_group,
if (cb_obj.active.includes(12)){jline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(13)){kline.visible = true;} if (cb_obj.active.includes(14)){kkline.visible = true;} // 1 index box is bline """, args={ 'aline': aline, 'bline': bline, 'cline': cline, 'ccline': ccline, 'dline': dline, 'ddline': ddline, 'eline': eline, 'fline': fline, 'gline': gline, 'ggline': ggline, 'hline': hline, 'iline': iline, 'jline': jline, 'kline': kline, 'kkline': kkline }) checkboxes.js_on_click(callback) layout = row(p1, checkboxes) # output_file('BV2_DUT_sensors_134_sections.html') # show(column(p1, p2, checkboxes)) curdoc().add_root(layout) curdoc().title = "BOKEH_TEMPLATE" show(layout)
class ViewerVIWidgets(object): """ Encapsulates Bokeh widgets, and related callbacks, used for VI """ def __init__(self, title, viewer_cds): self.vi_quality_labels = [ x["label"] for x in vi_flags if x["type"]=="quality" ] self.vi_issue_labels = [ x["label"] for x in vi_flags if x["type"]=="issue" ] self.vi_issue_slabels = [ x["shortlabel"] for x in vi_flags if x["type"]=="issue" ] self.js_files = get_resources('js') self.title = title self.vi_countdown_toggle = None #- List of fields to be recorded in output csv file, contains for each field: # [ field name (in VI file header), associated variable in viewer_cds.cds_metadata ] self.output_file_fields = [] for file_field in vi_file_fields: if file_field[1] in viewer_cds.cds_metadata.data.keys() : self.output_file_fields.append([file_field[0], file_field[1]]) def add_filename(self, username='******'): #- VI file name default_vi_filename = "desi-vi_"+self.title default_vi_filename += ("_"+username) default_vi_filename += ".csv" self.vi_filename_input = TextInput(value=default_vi_filename, title="VI file name:") def add_vi_issues(self, viewer_cds, widgets): #- Optional VI flags (issues) self.vi_issue_input = CheckboxGroup(labels=self.vi_issue_labels, active=[]) vi_issue_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"] vi_issue_code += """ var issues = [] for (var i=0; i<vi_issue_labels.length; i++) { if (vi_issue_input.active.indexOf(i) >= 0) issues.push(vi_issue_slabels[i]) } if (issues.length > 0) { cds_metadata.data['VI_issue_flag'][ifiberslider.value] = ( issues.join('') ) } else { cds_metadata.data['VI_issue_flag'][ifiberslider.value] = " " } autosave_vi_localStorage(output_file_fields, cds_metadata.data, title) cds_metadata.change.emit() """ self.vi_issue_callback = CustomJS( args=dict(cds_metadata = viewer_cds.cds_metadata, ifiberslider = widgets.ifiberslider, vi_issue_input = self.vi_issue_input, vi_issue_labels = self.vi_issue_labels, vi_issue_slabels = self.vi_issue_slabels, title = self.title, output_file_fields = self.output_file_fields), code = vi_issue_code ) self.vi_issue_input.js_on_click(self.vi_issue_callback) def add_vi_z(self, viewer_cds, widgets): ## TODO: z_tovi behaviour if with_vi_widget=False ..? #- Optional VI information on redshift self.vi_z_input = TextInput(value='', title="VI redshift:") vi_z_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"] vi_z_code += """ cds_metadata.data['VI_z'][ifiberslider.value]=vi_z_input.value autosave_vi_localStorage(output_file_fields, cds_metadata.data, title) cds_metadata.change.emit() """ self.vi_z_callback = CustomJS( args=dict(cds_metadata = viewer_cds.cds_metadata, ifiberslider = widgets.ifiberslider, vi_z_input = self.vi_z_input, title = self.title, output_file_fields=self.output_file_fields), code = vi_z_code ) self.vi_z_input.js_on_change('value', self.vi_z_callback) # Copy z value from redshift slider to VI self.z_tovi_button = Button(label='Copy z to VI') self.z_tovi_callback = CustomJS( args=dict(z_input=widgets.z_input, vi_z_input=self.vi_z_input), code=""" vi_z_input.value = z_input.value """) self.z_tovi_button.js_on_event('button_click', self.z_tovi_callback) def add_vi_spectype(self, viewer_cds, widgets): #- Optional VI information on spectral type self.vi_category_select = Select(value=' ', title="VI spectype:", options=([' '] + vi_spectypes)) # The default value set to ' ' as setting value='' does not seem to work well with Select. vi_category_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"] vi_category_code += """ if (vi_category_select.value == ' ') { cds_metadata.data['VI_spectype'][ifiberslider.value]='' } else { cds_metadata.data['VI_spectype'][ifiberslider.value]=vi_category_select.value } autosave_vi_localStorage(output_file_fields, cds_metadata.data, title) cds_metadata.change.emit() """ self.vi_category_callback = CustomJS( args=dict(cds_metadata=viewer_cds.cds_metadata, ifiberslider = widgets.ifiberslider, vi_category_select=self.vi_category_select, title=self.title, output_file_fields=self.output_file_fields), code=vi_category_code ) self.vi_category_select.js_on_change('value', self.vi_category_callback) def add_vi_comment(self, viewer_cds, widgets): #- Optional VI comment self.vi_comment_input = TextInput(value='', title="VI comment (see guidelines):") vi_comment_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"] vi_comment_code += """ var stored_comment = (vi_comment_input.value).replace(/./g, function(char){ if ( char==',' ) { return ';' } else if ( char.charCodeAt(0)<=127 ) { return char } else { var char_list = ['Å','α','β','γ','δ','λ'] var char_replace = ['Angstrom','alpha','beta','gamma','delta','lambda'] for (var i=0; i<char_list.length; i++) { if ( char==char_list[i] ) return char_replace[i] } return '?' } }) cds_metadata.data['VI_comment'][ifiberslider.value] = stored_comment autosave_vi_localStorage(output_file_fields, cds_metadata.data, title) cds_metadata.change.emit() """ self.vi_comment_callback = CustomJS( args=dict(cds_metadata = viewer_cds.cds_metadata, ifiberslider = widgets.ifiberslider, vi_comment_input = self.vi_comment_input, title=self.title, output_file_fields=self.output_file_fields), code=vi_comment_code ) self.vi_comment_input.js_on_change('value',self.vi_comment_callback) #- List of "standard" VI comment self.vi_std_comment_select = Select(value=" ", title="Standard comment:", options=([' '] + vi_std_comments)) vi_std_comment_code = """ if (vi_std_comment_select.value != ' ') { if (vi_comment_input.value != '') { vi_comment_input.value = vi_comment_input.value + " " + vi_std_comment_select.value } else { vi_comment_input.value = vi_std_comment_select.value } } """ self.vi_std_comment_callback = CustomJS( args = dict(vi_std_comment_select = self.vi_std_comment_select, vi_comment_input = self.vi_comment_input), code = vi_std_comment_code ) self.vi_std_comment_select.js_on_change('value', self.vi_std_comment_callback) def add_vi_quality(self, viewer_cds, widgets): #- Main VI quality widget self.vi_quality_input = RadioButtonGroup(labels=self.vi_quality_labels) vi_quality_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"] vi_quality_code += """ if ( vi_quality_input.active >= 0 ) { cds_metadata.data['VI_quality_flag'][ifiberslider.value] = vi_quality_labels[vi_quality_input.active] } else { cds_metadata.data['VI_quality_flag'][ifiberslider.value] = "-1" } autosave_vi_localStorage(output_file_fields, cds_metadata.data, title) cds_metadata.change.emit() """ self.vi_quality_callback = CustomJS( args = dict(cds_metadata = viewer_cds.cds_metadata, vi_quality_input = self.vi_quality_input, vi_quality_labels = self.vi_quality_labels, ifiberslider = widgets.ifiberslider, title=self.title, output_file_fields = self.output_file_fields), code=vi_quality_code ) self.vi_quality_input.js_on_click(self.vi_quality_callback) def add_vi_scanner(self, viewer_cds): #- VI scanner name self.vi_name_input = TextInput(value=(viewer_cds.cds_metadata.data['VI_scanner'][0]).strip(), title="Your name (3-letter acronym):") vi_name_code = self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"] vi_name_code += """ for (var i=0; i<(cds_metadata.data['VI_scanner']).length; i++) { cds_metadata.data['VI_scanner'][i]=vi_name_input.value } var newname = vi_filename_input.value var name_chunks = newname.split("_") newname = ( name_chunks.slice(0,name_chunks.length-1).join("_") ) + ("_"+vi_name_input.value+".csv") vi_filename_input.value = newname autosave_vi_localStorage(output_file_fields, cds_metadata.data, title) """ self.vi_name_callback = CustomJS( args = dict(cds_metadata = viewer_cds.cds_metadata, vi_name_input = self.vi_name_input, vi_filename_input = self.vi_filename_input, title=self.title, output_file_fields = self.output_file_fields), code=vi_name_code ) self.vi_name_input.js_on_change('value', self.vi_name_callback) def add_guidelines(self): #- Guidelines for VI flags vi_guideline_txt = "<B> VI guidelines </B>" vi_guideline_txt += "<BR /> <B> Classification flags: </B>" for flag in vi_flags : if flag['type'] == 'quality' : vi_guideline_txt += ("<BR />  [ "+flag['label']+" ] "+flag['description']) vi_guideline_txt += "<BR /> <B> Optional indications: </B>" for flag in vi_flags : if flag['type'] == 'issue' : vi_guideline_txt += ( "<BR />  [ " + flag['label'] + " (" + flag['shortlabel'] + ") ] " + flag['description'] ) vi_guideline_txt += "<BR /> <B> Comments: </B> <BR /> 100 characters max, avoid commas (automatically replaced by semi-columns), ASCII only." self.vi_guideline_div = Div(text=vi_guideline_txt) def add_vi_storage(self, viewer_cds, widgets): #- Save VI info to CSV file self.save_vi_button = Button(label="Download VI", button_type="success") save_vi_code = self.js_files["FileSaver.js"] + self.js_files["CSVtoArray.js"] + self.js_files["save_vi.js"] save_vi_code += """ download_vi_file(output_file_fields, cds_metadata.data, vi_filename_input.value) """ self.save_vi_callback = CustomJS( args = dict(cds_metadata = viewer_cds.cds_metadata, output_file_fields = self.output_file_fields, vi_filename_input = self.vi_filename_input), code=save_vi_code ) self.save_vi_button.js_on_event('button_click', self.save_vi_callback) #- Recover auto-saved VI data in browser self.recover_vi_button = Button(label="Recover auto-saved VI", button_type="default") recover_vi_code = self.js_files["CSVtoArray.js"] + self.js_files["recover_autosave_vi.js"] self.recover_vi_callback = CustomJS( args = dict(title=self.title, output_file_fields=self.output_file_fields, cds_metadata = viewer_cds.cds_metadata, ifiber = widgets.ifiberslider.value, vi_comment_input = self.vi_comment_input, vi_name_input=self.vi_name_input, vi_quality_input=self.vi_quality_input, vi_issue_input=self.vi_issue_input, vi_issue_slabels=self.vi_issue_slabels, vi_quality_labels=self.vi_quality_labels), code = recover_vi_code ) self.recover_vi_button.js_on_event('button_click', self.recover_vi_callback) #- Clear all auto-saved VI self.clear_vi_button = Button(label="Clear all auto-saved VI", button_type="default") self.clear_vi_callback = CustomJS( args = dict(), code = """ localStorage.clear() """ ) self.clear_vi_button.js_on_event('button_click', self.clear_vi_callback) def add_vi_table(self, viewer_cds): #- Show VI in a table vi_table_columns = [ TableColumn(field="VI_quality_flag", title="Flag", width=40), TableColumn(field="VI_issue_flag", title="Opt.", width=50), TableColumn(field="VI_z", title="VI z", width=50), TableColumn(field="VI_spectype", title="VI spectype", width=150), TableColumn(field="VI_comment", title="VI comment", width=200) ] self.vi_table = DataTable(source=viewer_cds.cds_metadata, columns=vi_table_columns, width=500) self.vi_table.height = 10 * self.vi_table.row_height def add_countdown(self, vi_countdown): #- VI countdown assert vi_countdown > 0 self.vi_countdown_callback = CustomJS(args=dict(vi_countdown=vi_countdown), code=""" if ( (cb_obj.label).includes('Start') ) { // Callback doesn't do anything after countdown started var countDownDate = new Date().getTime() + (1000 * 60 * vi_countdown); var countDownLoop = setInterval(function(){ var now = new Date().getTime(); var distance = countDownDate - now; if (distance<0) { cb_obj.label = "Time's up !"; clearInterval(countDownLoop); } else { var days = Math.floor(distance / (1000 * 60 * 60 * 24)); var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((distance % (1000 * 60)) / 1000); //var stuff = days + "d " + hours + "h " + minutes + "m " + seconds + "s "; var stuff = minutes + "m " + seconds + "s "; cb_obj.label = "Countdown: " + stuff; } }, 1000); } """) self.vi_countdown_toggle = Toggle(label='Start countdown ('+str(vi_countdown)+' min)', active=False, button_type="success") self.vi_countdown_toggle.js_on_change('active', self.vi_countdown_callback)
def ajax_getplot(x, y, y_bottom, ref_value): #fi,ff,y_bottom,ref_value,x,y): # En la ventana del plot graf = figure(tools="save", x_axis_label="Frequency [Hz]", y_axis_label='Power [dBm]', width=700, height=400, sizing_mode='stretch_width', x_range=(x[0], x[-1]), y_range=(float(y_bottom), float(ref_value))) graf.toolbar.logo = None graf.toolbar.active_drag = None graf.toolbar.active_scroll = None graf.yaxis.major_label_text_font_style = 'bold' graf.xaxis.major_label_text_font_style = 'bold' graf.xaxis.axis_label_text_font_style = 'bold' graf.yaxis.axis_label_text_font_style = 'bold' graf.xaxis[0].formatter.use_scientific = True graf.xaxis[0].ticker.desired_num_ticks = 15 graf.yaxis[0].ticker.desired_num_ticks = 10 graf.ygrid.grid_line_alpha = 0.4 graf.ygrid.grid_line_dash = [6, 4] graf.xgrid.grid_line_alpha = 0.4 graf.xgrid.grid_line_dash = [6, 4] # graf.ygrid.minor_grid_line_alpha = 0.1 # graf.ygrid.minor_grid_line_color = 'navy' # graf.xgrid.minor_grid_line_alpha = 0.1 graf.background_fill_color = "black" graf.border_fill_color = "black" graf.border_fill_alpha = 0 graf.xaxis.axis_line_color = "white" graf.yaxis.axis_line_color = "white" props = dict(line_width=4, line_alpha=0.7) # source for (marker_abs, markers [CANT_MARKERS]) source_markers = ColumnDataSource(data={}) # source for table of graf's markers source_table = ColumnDataSource() # strings for table of graf's markers source_table_share = ColumnDataSource( ) # only for share strings of table's rows between graf_adapter.js, checkbox_callback.js ################################################################################################################################################################# # # -------------------------------------------------------------------------------------- # button_height = 30 # button_width = 70 #SLIDER_WIDTH = 500 # px CHECKBOX_WIDTH = 100 # -------------------------------------------------------------------------------------- if x != 0 and y != 0: max_abs_y = max(y) max_abs_x = argmax(y) #x_npa=asarray(x) y_npa = asarray(y) x_axis = linspace(x[0], x[-1], len(x)) else: y_bottom = -100 ref_value = -60 y_npa = asarray([0, 0]) x_axis = [0, 0] max_abs_y = 0 max_abs_x = 0 ################################################################################################################################################################# # Sliders de marcadores # solicitar frecuencias al analizador sliders = [] if x[0] != x[-1]: step = (x[-1] - x[0]) / len(x) if step <= 0: step = 1 init = (max_abs_x * step) + x[0] for i in range(0, CANT_MARKERS): sliders.append( Slider(start=x[0], end=x[-1], value=init, step=step, title="MARKER " + str(i + 1))) else: for i in range(0, CANT_MARKERS): sliders.append( Slider(start=0, end=1, value=0, step=1, title="MARKER " + str(i + 1))) ################################################################################################################################################################# # Tablas de configuracion (las de solo lectura) source_set_an = ColumnDataSource() source_set_gen = ColumnDataSource() source_set_powm = ColumnDataSource() ################################################################################################################################################################# # preparo el marcador movil # ve posibilidad de agregar PointDrawTool de hovertools # http://docs.bokeh.org/en/1.0.0/docs/user_guide/tools.html#click-tap-tools graf.add_tools( HoverTool( tooltips=[ ('frec', '@x{0,0} Hz'), ('amp', '@y dBm'), # use @{ } for field names with spaces ], point_policy='follow_mouse', mode='vline')) with open("static/js/graf_adapter.js", "r") as f: code = f.read() adapter = CustomJS(args=dict(graf=graf, sliders=sliders, source_markers=source_markers, source_table=source_table, source_table_share=source_table_share, source_set_an=source_set_an, source_set_gen=source_set_gen, source_set_powm=source_set_powm), code=code) source = AjaxDataSource(data_url=request.url_root + 'data/', polling_interval=1000, mode='replace', adapter=adapter) source.data = dict(x=[], y=[], y_bottom=[], ref_value=[], start_freq=[], stop_freq=[]) #, power = [] ) # span = [], center_freq = [], demod_time = [], ref_level = [], # ANALIZADOR # lf_freq = [], lf_level = [], rf_freq = [], rf_level = [], fm_mod_freq = [], am_mod_freq = [],am_mod_index= [],fm_mod_index= [],pm_mod_index= [], power = []) # GENERADOR graf.line('x', 'y', source=source, line_color="cyan") ############################################################################### # maximos relativos max_rel_x = argrelextrema(y_npa, greater) #dato pasado a numpy array ############################################################################### # datos para la tabla de datos info = [] value = [] # tabla de datos source_table.data = dict(x_data=info, y_data=value) source_table_share.data = dict(x_data=info, y_data=value) #source_table = source columns = [ TableColumn(field="x_data", title="Information"), TableColumn(field="y_data", title="Value") ] data_table = DataTable(source=source_table, columns=columns, height=200, width=400) ############################################################################### set_div = Div(text="<b>Current Settings</b>") # tabla de valores seteados actualmente del analizador source_set_an.data = dict( configuration=[ "X scale", "Y scale", "Start freq", "Stop freq", "Span", "Center freq", "Ref level", "Demod time", "Demod type", "Input att", "Resolution BW", "Scale div", "Avg state", "Avg times" ], value=[ "LIN", "LOG", "0.0", "1.0", "1.0", "1.0", "0.0", "0.0", "FM", "10", "100000", "10.0", "WRITe", "1" ], ) columns_set_an = [ TableColumn(field="configuration", title="Analizer"), TableColumn(field="value", title="value"), ] info_table_an = DataTable(source=source_set_an, columns=columns_set_an, width=220, height=180) # tabla de valuees seteados actualmente en el generador source_set_gen.data = dict( configuration=[ "LF state", "LF freq", "LF level", "LF waveform", "RF state", "RF freq", "RF level", "AM state", "AM source", "AM mod freq", "AM mod index", "AM waveform", "Modulation type", "Modulation state", "FM mod freq", "FM mod index", "FM waveform", "PM mod freq", "PM mod index", "PM waveform" ], value=[ "OFF", "0.0", "0.0", "SINE", "0.0", "0.0", "0.0", "OFF", "INT", "0.0", "0.0", "SINE", "FM", "OFF", "0.0", "0.0", "SINE", "0.0", "0.0", "0.0" ], ) columns_set_gen = [ TableColumn(field="configuration", title="Generator"), TableColumn(field="value", title="value"), ] info_table_gen = DataTable(source=source_set_gen, columns=columns_set_gen, width=220, height=180) # tabla de valuees seteados actualmente en el generador source_set_powm.data = dict( configuration=["Duty cycle", "Average"], value=["50", "1"], ) columns_set_powm = [ TableColumn(field="configuration", title="Power meter"), TableColumn(field="value", title="value"), ] info_table_powm = DataTable(source=source_set_powm, columns=columns_set_powm, width=200, height=180) #source_table = source ############################################################################### ## cosas a graficar # source5 = ColumnDataSource(data=dict(x5=[x_axis[max_abs_x]], y5=[max_abs_y])) # source4 = ColumnDataSource(data=dict(x4=[x_axis[max_abs_x]], y4=[max_abs_y])) # source3 = ColumnDataSource(data=dict(x3=[x_axis[max_abs_x]], y3=[max_abs_y])) # source2 = ColumnDataSource(data=dict(x2=[x_axis[max_abs_x]], y2=[max_abs_y])) # source5 = ColumnDataSource(data=dict(x5=[], y5=[])) # source4 = ColumnDataSource(data=dict(x4=[], y4=[])) # source3 = ColumnDataSource(data=dict(x3=[], y3=[])) # source2 = ColumnDataSource(data=dict(x2=[], y2=[])) # marcadores moviles que arrancan en el absolute maximum # l5=graf.circle('x5', 'y5', source=source5, color="lawngreen", line_width=8, line_alpha=0.7 ) # l4=graf.circle('x4', 'y4', source=source4, color="lime", line_width=8, line_alpha=0.7) # l3=graf.circle('x3', 'y3', source=source3, color="yellow", line_width=8, line_alpha=0.7) # l2=graf.circle('x2', 'y2', source=source2, color="blue", line_width=8, line_alpha=0.7) # custom markers #markers_rel_dict = {} markers = [] colors = ["yellow", "red", "pink", "lime"] for i in range(0, CANT_MARKERS): x_label = 'x_mark_' + str(i + 1) y_label = 'y_mark_' + str(i + 1) source_markers.data[x_label] = [x_axis[max_abs_x]] source_markers.data[y_label] = [max_abs_y] markers.append( graf.circle(x_label, y_label, source=source_markers, color=colors[i], line_width=8, line_alpha=0.7)) #l1=graf.circle(x_axis[max_rel_x[0]] , y_npa[max_rel_x[0]], color="yellowgreen", **props) # max abs marker source_markers.data['x_abs'] = [x_axis[max_abs_x]] source_markers.data['y_abs'] = [max_abs_y] marker_abs = graf.circle(x='x_abs', y='y_abs', source=source_markers, color="red", line_width=8, line_alpha=0.7) #marker_abs=graf.circle(x_axis[max_abs_x],max_abs_y, color="green", **props) ############################################################################### # presentacion del maximo #maximo=str('%.2f' % max_abs_y)+"V @ "+str('%.2f' % x_axis[max_abs_x]+" rad") # presentacion de maximos relativos max_rel = ["a" for i in range(len(max_rel_x[0]))] for i in range(len((max_rel_x[0]))): max_rel[i] = (str('%.2f' % y_npa[max_rel_x[0][i]]) + "V @ " + str('%.2f' % x_axis[max_rel_x[0][i]] + " rad")) ############################################################################### # Sliders de marcadores #callback unico para todos los sliders with open("static/js/callback_sm.js", "r") as f: callback_sm_code = f.read() callback_sm = CustomJS(args=dict(source_table=source_table, source=source, source_markers=source_markers, sliders=sliders, markers=markers, graf=graf, props=props), code=callback_sm_code) for i in range(0, CANT_MARKERS): sliders[i].js_on_change('value', callback_sm) ############################################################################### # Acciones relativas a los checkbox checkbox_labels = ["Max. Abs"] # checkbox_labels = ["Max. Abs", "Max. Rel"] checkbox_preset = CheckboxGroup(labels=checkbox_labels, active=[], width=CHECKBOX_WIDTH) checkbox_mark = CheckboxGroup( labels=["Mark 1", "Mark 2", "Mark 3", "Mark 4"], active=[], width=CHECKBOX_WIDTH) #checkbox.active=[] <- indica los índices de los elementos "activados" (para activar el 1: [1], para activar el 0 y el 3: [0 3]) #checkbox.active=[] #checkbox.active[0]=False marker_abs.visible = False #checkbox.active[1]=False for i in range(0, CANT_MARKERS): markers[i].visible = False pass #checkbox_mark.active=[] #checkbox_mark.active[0]=False # marker[i].visible=False #checkbox_mark.active[1]=False # marker[i].visible=False #checkbox_mark.active[2]=False # marker[i].visible=False #checkbox_mark.active[3]=False # marker[i].visible=False ##---------------------------------------------------------------------------## with open("static/js/checkbox_callback.js", "r") as f: checkbox_code = f.read() cjs = CustomJS(args=dict(marker_abs=marker_abs, markers=markers, checkbox_preset=checkbox_preset, checkbox_mark=checkbox_mark, source_table=source_table, source=source, source_markers=source_markers, source_table_share=source_table_share, sliders=sliders), code=checkbox_code) checkbox_preset.js_on_click(cjs) checkbox_mark.js_on_click(cjs) ##---------------------------------------------------------------------------## sliders_col = column(sliders) # Ploteos layout_graf = gridplot([[graf]], sizing_mode='scale_width', toolbar_location="right") layout_widgets = widgetbox(row(checkbox_preset, checkbox_mark, sliders_col, data_table), sizing_mode='scale_width') layout_seteos = widgetbox(row(info_table_an, info_table_gen, info_table_powm), sizing_mode='scale_width') analyzer_layout = layout( [layout_graf, layout_widgets, set_div, layout_seteos], sizing_mode='scale_width') return components(analyzer_layout)
class ViewerWidgets(object): """ Encapsulates Bokeh widgets, and related callbacks, that are part of prospect's GUI. Except for VI widgets """ def __init__(self, plots, nspec): self.js_files = get_resources('js') self.navigation_button_width = 30 self.z_button_width = 30 self.plot_widget_width = (plots.plot_width+(plots.plot_height//2))//2 - 40 # used for widgets scaling #----- #- Ifiberslider and smoothing widgets # Ifiberslider's value controls which spectrum is displayed # These two widgets call update_plot(), later defined slider_end = nspec-1 if nspec > 1 else 0.5 # Slider cannot have start=end self.ifiberslider = Slider(start=0, end=slider_end, value=0, step=1, title='Spectrum (of '+str(nspec)+')') self.smootherslider = Slider(start=0, end=26, value=0, step=1.0, title='Gaussian Sigma Smooth') self.coaddcam_buttons = None self.model_select = None def add_navigation(self, nspec): #----- #- Navigation buttons self.prev_button = Button(label="<", width=self.navigation_button_width) self.next_button = Button(label=">", width=self.navigation_button_width) self.prev_callback = CustomJS( args=dict(ifiberslider=self.ifiberslider), code=""" if(ifiberslider.value>0 && ifiberslider.end>=1) { ifiberslider.value-- } """) self.next_callback = CustomJS( args=dict(ifiberslider=self.ifiberslider, nspec=nspec), code=""" if(ifiberslider.value<nspec-1 && ifiberslider.end>=1) { ifiberslider.value++ } """) self.prev_button.js_on_event('button_click', self.prev_callback) self.next_button.js_on_event('button_click', self.next_callback) def add_resetrange(self, viewer_cds, plots): #----- #- Axis reset button (superseeds the default bokeh "reset" self.reset_plotrange_button = Button(label="Reset X-Y range", button_type="default") reset_plotrange_code = self.js_files["adapt_plotrange.js"] + self.js_files["reset_plotrange.js"] self.reset_plotrange_callback = CustomJS(args = dict(fig=plots.fig, xmin=plots.xmin, xmax=plots.xmax, spectra=viewer_cds.cds_spectra), code = reset_plotrange_code) self.reset_plotrange_button.js_on_event('button_click', self.reset_plotrange_callback) def add_redshift_widgets(self, z, viewer_cds, plots): ## TODO handle "z" (same issue as viewerplots TBD) #----- #- Redshift / wavelength scale widgets z1 = np.floor(z*100)/100 dz = z-z1 self.zslider = Slider(start=-0.1, end=5.0, value=z1, step=0.01, title='Redshift rough tuning') self.dzslider = Slider(start=0.0, end=0.0099, value=dz, step=0.0001, title='Redshift fine-tuning') self.dzslider.format = "0[.]0000" self.z_input = TextInput(value="{:.4f}".format(z), title="Redshift value:") #- Observer vs. Rest frame wavelengths self.waveframe_buttons = RadioButtonGroup( labels=["Obs", "Rest"], active=0) self.zslider_callback = CustomJS( args=dict(zslider=self.zslider, dzslider=self.dzslider, z_input=self.z_input), code=""" // Protect against 1) recursive call with z_input callback; // 2) out-of-range zslider values (should never happen in principle) var z1 = Math.floor(parseFloat(z_input.value)*100) / 100 if ( (Math.abs(zslider.value-z1) >= 0.01) && (zslider.value >= -0.1) && (zslider.value <= 5.0) ){ var new_z = zslider.value + dzslider.value z_input.value = new_z.toFixed(4) } """) self.dzslider_callback = CustomJS( args=dict(zslider=self.zslider, dzslider=self.dzslider, z_input=self.z_input), code=""" var z = parseFloat(z_input.value) var z1 = Math.floor(z) / 100 var z2 = z-z1 if ( (Math.abs(dzslider.value-z2) >= 0.0001) && (dzslider.value >= 0.0) && (dzslider.value <= 0.0099) ){ var new_z = zslider.value + dzslider.value z_input.value = new_z.toFixed(4) } """) self.zslider.js_on_change('value', self.zslider_callback) self.dzslider.js_on_change('value', self.dzslider_callback) self.z_minus_button = Button(label="<", width=self.z_button_width) self.z_plus_button = Button(label=">", width=self.z_button_width) self.z_minus_callback = CustomJS( args=dict(z_input=self.z_input), code=""" var z = parseFloat(z_input.value) if(z >= -0.09) { z -= 0.01 z_input.value = z.toFixed(4) } """) self.z_plus_callback = CustomJS( args=dict(z_input=self.z_input), code=""" var z = parseFloat(z_input.value) if(z <= 4.99) { z += 0.01 z_input.value = z.toFixed(4) } """) self.z_minus_button.js_on_event('button_click', self.z_minus_callback) self.z_plus_button.js_on_event('button_click', self.z_plus_callback) self.zreset_button = Button(label='Reset to z_pipe') self.zreset_callback = CustomJS( args=dict(z_input=self.z_input, metadata=viewer_cds.cds_metadata, ifiberslider=self.ifiberslider), code=""" var ifiber = ifiberslider.value var z = metadata.data['Z'][ifiber] z_input.value = z.toFixed(4) """) self.zreset_button.js_on_event('button_click', self.zreset_callback) self.z_input_callback = CustomJS( args=dict(spectra = viewer_cds.cds_spectra, coaddcam_spec = viewer_cds.cds_coaddcam_spec, model = viewer_cds.cds_model, othermodel = viewer_cds.cds_othermodel, metadata = viewer_cds.cds_metadata, ifiberslider = self.ifiberslider, zslider = self.zslider, dzslider = self.dzslider, z_input = self.z_input, waveframe_buttons = self.waveframe_buttons, line_data = viewer_cds.cds_spectral_lines, lines = plots.speclines, line_labels = plots.specline_labels, zlines = plots.zoom_speclines, zline_labels = plots.zoom_specline_labels, overlap_waves = plots.overlap_waves, overlap_bands = plots.overlap_bands, fig = plots.fig ), code=""" var z = parseFloat(z_input.value) if ( z >=-0.1 && z <= 5.0 ) { // update zsliders only if needed (avoid recursive call) z_input.value = parseFloat(z_input.value).toFixed(4) var z1 = Math.floor(z*100) / 100 var z2 = z-z1 if ( Math.abs(z1-zslider.value) >= 0.01) zslider.value = parseFloat(parseFloat(z1).toFixed(2)) if ( Math.abs(z2-dzslider.value) >= 0.0001) dzslider.value = parseFloat(parseFloat(z2).toFixed(4)) } else { if (z_input.value < -0.1) z_input.value = (-0.1).toFixed(4) if (z_input.value > 5) z_input.value = (5.0).toFixed(4) } var line_restwave = line_data.data['restwave'] var ifiber = ifiberslider.value var waveshift_lines = (waveframe_buttons.active == 0) ? 1+z : 1 ; var waveshift_spec = (waveframe_buttons.active == 0) ? 1 : 1/(1+z) ; for(var i=0; i<line_restwave.length; i++) { lines[i].location = line_restwave[i] * waveshift_lines line_labels[i].x = line_restwave[i] * waveshift_lines zlines[i].location = line_restwave[i] * waveshift_lines zline_labels[i].x = line_restwave[i] * waveshift_lines } if (overlap_bands.length>0) { for (var i=0; i<overlap_bands.length; i++) { overlap_bands[i].left = overlap_waves[i][0] * waveshift_spec overlap_bands[i].right = overlap_waves[i][1] * waveshift_spec } } function shift_plotwave(cds_spec, waveshift) { var data = cds_spec.data var origwave = data['origwave'] var plotwave = data['plotwave'] if ( plotwave[0] != origwave[0] * waveshift ) { // Avoid redo calculation if not needed for (var j=0; j<plotwave.length; j++) { plotwave[j] = origwave[j] * waveshift ; } cds_spec.change.emit() } } for(var i=0; i<spectra.length; i++) { shift_plotwave(spectra[i], waveshift_spec) } if (coaddcam_spec) shift_plotwave(coaddcam_spec, waveshift_spec) // Update model wavelength array // NEW : don't shift model if othermodel is there if (othermodel) { var zref = othermodel.data['zref'][0] var waveshift_model = (waveframe_buttons.active == 0) ? (1+z)/(1+zref) : 1/(1+zref) ; shift_plotwave(othermodel, waveshift_model) } else if (model) { var zfit = 0.0 if(metadata.data['Z'] !== undefined) { zfit = metadata.data['Z'][ifiber] } var waveshift_model = (waveframe_buttons.active == 0) ? (1+z)/(1+zfit) : 1/(1+zfit) ; shift_plotwave(model, waveshift_model) } """) self.z_input.js_on_change('value', self.z_input_callback) self.waveframe_buttons.js_on_click(self.z_input_callback) self.plotrange_callback = CustomJS( args = dict( z_input=self.z_input, waveframe_buttons=self.waveframe_buttons, fig=plots.fig, ), code=""" var z = parseFloat(z_input.value) // Observer Frame if(waveframe_buttons.active == 0) { fig.x_range.start = fig.x_range.start * (1+z) fig.x_range.end = fig.x_range.end * (1+z) } else { fig.x_range.start = fig.x_range.start / (1+z) fig.x_range.end = fig.x_range.end / (1+z) } """ ) self.waveframe_buttons.js_on_click(self.plotrange_callback) # TODO: for record: is this related to waveframe bug? : 2 callbakcs for same click... def add_oii_widgets(self, plots): #------ #- Zoom on the OII doublet TODO mv js code to other file # TODO: is there another trick than using a cds to pass the "oii_saveinfo" ? # TODO: optimize smoothing for autozoom (current value: 0) cds_oii_saveinfo = ColumnDataSource( {'xmin':[plots.fig.x_range.start], 'xmax':[plots.fig.x_range.end], 'nsmooth':[self.smootherslider.value]}) self.oii_zoom_button = Button(label="OII-zoom", button_type="default") self.oii_zoom_callback = CustomJS( args = dict(z_input=self.z_input, fig=plots.fig, smootherslider=self.smootherslider, cds_oii_saveinfo=cds_oii_saveinfo), code = """ // Save previous setting (for the "Undo" button) cds_oii_saveinfo.data['xmin'] = [fig.x_range.start] cds_oii_saveinfo.data['xmax'] = [fig.x_range.end] cds_oii_saveinfo.data['nsmooth'] = [smootherslider.value] // Center on the middle of the redshifted OII doublet (vaccum) var z = parseFloat(z_input.value) fig.x_range.start = 3728.48 * (1+z) - 100 fig.x_range.end = 3728.48 * (1+z) + 100 // No smoothing (this implies a call to update_plot) smootherslider.value = 0 """) self.oii_zoom_button.js_on_event('button_click', self.oii_zoom_callback) self.oii_undo_button = Button(label="Undo OII-zoom", button_type="default") self.oii_undo_callback = CustomJS( args = dict(fig=plots.fig, smootherslider=self.smootherslider, cds_oii_saveinfo=cds_oii_saveinfo), code = """ fig.x_range.start = cds_oii_saveinfo.data['xmin'][0] fig.x_range.end = cds_oii_saveinfo.data['xmax'][0] smootherslider.value = cds_oii_saveinfo.data['nsmooth'][0] """) self.oii_undo_button.js_on_event('button_click', self.oii_undo_callback) def add_coaddcam(self, plots): #----- #- Highlight individual-arm or camera-coadded spectra coaddcam_labels = ["Camera-coadded", "Single-arm"] self.coaddcam_buttons = RadioButtonGroup(labels=coaddcam_labels, active=0) self.coaddcam_callback = CustomJS( args = dict(coaddcam_buttons = self.coaddcam_buttons, list_lines=[plots.data_lines, plots.noise_lines, plots.zoom_data_lines, plots.zoom_noise_lines], alpha_discrete = plots.alpha_discrete, overlap_bands = plots.overlap_bands, alpha_overlapband = plots.alpha_overlapband), code=""" var n_lines = list_lines[0].length for (var i=0; i<n_lines; i++) { var new_alpha = 1 if (coaddcam_buttons.active == 0 && i<n_lines-1) new_alpha = alpha_discrete if (coaddcam_buttons.active == 1 && i==n_lines-1) new_alpha = alpha_discrete for (var j=0; j<list_lines.length; j++) { list_lines[j][i].glyph.line_alpha = new_alpha } } var new_alpha = 0 if (coaddcam_buttons.active == 0) new_alpha = alpha_overlapband for (var j=0; j<overlap_bands.length; j++) { overlap_bands[j].fill_alpha = new_alpha } """ ) self.coaddcam_buttons.js_on_click(self.coaddcam_callback) def add_metadata_tables(self, viewer_cds, show_zcat=True, template_dicts=None, top_metadata=['TARGETID', 'EXPID']): """ Display object-related informations top_metadata: metadata to be highlighted in table_a Note: "short" CDS, with a single row, are used to fill these bokeh tables. When changing object, js code modifies these short CDS so that tables are updated. """ #- Sorted list of potential metadata: metadata_to_check = ['TARGETID', 'HPXPIXEL', 'TILEID', 'COADD_NUMEXP', 'COADD_EXPTIME', 'NIGHT', 'EXPID', 'FIBER', 'CAMERA', 'MORPHTYPE'] metadata_to_check += [ ('mag_'+x) for x in viewer_cds.phot_bands ] table_keys = [] for key in metadata_to_check: if key in viewer_cds.cds_metadata.data.keys(): table_keys.append(key) if 'NUM_'+key in viewer_cds.cds_metadata.data.keys(): for prefix in ['FIRST','LAST','NUM']: table_keys.append(prefix+'_'+key) if key in top_metadata: top_metadata.append(prefix+'_'+key) #- Table a: "top metadata" table_a_keys = [ x for x in table_keys if x in top_metadata ] self.shortcds_table_a, self.table_a = _metadata_table(table_a_keys, viewer_cds, table_width=600, shortcds_name='shortcds_table_a', selectable=True) #- Table b: Targeting information self.shortcds_table_b, self.table_b = _metadata_table(['Targeting masks'], viewer_cds, table_width=self.plot_widget_width, shortcds_name='shortcds_table_b', selectable=True) #- Table(s) c/d : Other information (imaging, etc.) remaining_keys = [ x for x in table_keys if x not in top_metadata ] if len(remaining_keys) > 7: table_c_keys = remaining_keys[0:len(remaining_keys)//2] table_d_keys = remaining_keys[len(remaining_keys)//2:] else: table_c_keys = remaining_keys table_d_keys = None self.shortcds_table_c, self.table_c = _metadata_table(table_c_keys, viewer_cds, table_width=self.plot_widget_width, shortcds_name='shortcds_table_c', selectable=False) if table_d_keys is None: self.shortcds_table_d, self.table_d = None, None else: self.shortcds_table_d, self.table_d = _metadata_table(table_d_keys, viewer_cds, table_width=self.plot_widget_width, shortcds_name='shortcds_table_d', selectable=False) #- Table z: redshift fitting information if show_zcat is not None : if template_dicts is not None : # Add other best fits fit_results = template_dicts[1] # Case of DeltaChi2 : compute it from Chi2s # The "DeltaChi2" in rr fits is between best fits for a given (spectype,subtype) # Convention: DeltaChi2 = -1 for the last fit. chi2s = fit_results['CHI2'][0] full_deltachi2s = np.zeros(len(chi2s))-1 full_deltachi2s[:-1] = chi2s[1:]-chi2s[:-1] cdsdata = dict(Nfit = np.arange(1,len(chi2s)+1), SPECTYPE = fit_results['SPECTYPE'][0], # [0:num_best_fits] (if we want to restrict... TODO?) SUBTYPE = fit_results['SUBTYPE'][0], Z = [ "{:.4f}".format(x) for x in fit_results['Z'][0] ], ZERR = [ "{:.4f}".format(x) for x in fit_results['ZERR'][0] ], ZWARN = fit_results['ZWARN'][0], CHI2 = [ "{:.1f}".format(x) for x in fit_results['CHI2'][0] ], DELTACHI2 = [ "{:.1f}".format(x) for x in full_deltachi2s ]) self.shortcds_table_z = ColumnDataSource(cdsdata, name='shortcds_table_z') columns_table_z = [ TableColumn(field=x, title=t, width=w) for x,t,w in [ ('Nfit','Nfit',5), ('SPECTYPE','SPECTYPE',70), ('SUBTYPE','SUBTYPE',60), ('Z','Z',50) , ('ZERR','ZERR',50), ('ZWARN','ZWARN',50), ('DELTACHI2','Δχ2(N+1/N)',70)] ] self.table_z = DataTable(source=self.shortcds_table_z, columns=columns_table_z, selectable=False, index_position=None, width=self.plot_widget_width) self.table_z.height = 3 * self.table_z.row_height else : self.shortcds_table_z, self.table_z = _metadata_table(viewer_cds.zcat_keys, viewer_cds, table_width=self.plot_widget_width, shortcds_name='shortcds_table_z', selectable=False) else : self.table_z = Div(text="Not available ") self.shortcds_table_z = None def add_specline_toggles(self, viewer_cds, plots): #----- #- Toggle lines self.speclines_button_group = CheckboxButtonGroup( labels=["Emission lines", "Absorption lines"], active=[]) self.majorline_checkbox = CheckboxGroup( labels=['Show only major lines'], active=[]) self.speclines_callback = CustomJS( args = dict(line_data = viewer_cds.cds_spectral_lines, lines = plots.speclines, line_labels = plots.specline_labels, zlines = plots.zoom_speclines, zline_labels = plots.zoom_specline_labels, lines_button_group = self.speclines_button_group, majorline_checkbox = self.majorline_checkbox), code=""" var show_emission = false var show_absorption = false if (lines_button_group.active.indexOf(0) >= 0) { // index 0=Emission in active list show_emission = true } if (lines_button_group.active.indexOf(1) >= 0) { // index 1=Absorption in active list show_absorption = true } for(var i=0; i<lines.length; i++) { if ( !(line_data.data['major'][i]) && (majorline_checkbox.active.indexOf(0)>=0) ) { lines[i].visible = false line_labels[i].visible = false zlines[i].visible = false zline_labels[i].visible = false } else if (line_data.data['emission'][i]) { lines[i].visible = show_emission line_labels[i].visible = show_emission zlines[i].visible = show_emission zline_labels[i].visible = show_emission } else { lines[i].visible = show_absorption line_labels[i].visible = show_absorption zlines[i].visible = show_absorption zline_labels[i].visible = show_absorption } } """ ) self.speclines_button_group.js_on_click(self.speclines_callback) self.majorline_checkbox.js_on_click(self.speclines_callback) def add_model_select(self, viewer_cds, template_dicts, num_approx_fits, with_full_2ndfit=True): #------ #- Select secondary model to display model_options = ['Best fit', '2nd best fit'] for i in range(1,1+num_approx_fits) : ith = 'th' if i==1 : ith='st' if i==2 : ith='nd' if i==3 : ith='rd' model_options.append(str(i)+ith+' fit (approx)') if with_full_2ndfit is False : model_options.remove('2nd best fit') for std_template in ['QSO', 'GALAXY', 'STAR'] : model_options.append('STD '+std_template) self.model_select = Select(value=model_options[0], title="Other model (dashed curve):", options=model_options) model_select_code = self.js_files["interp_grid.js"] + self.js_files["smooth_data.js"] + self.js_files["select_model.js"] self.model_select_callback = CustomJS( args = dict(ifiberslider = self.ifiberslider, model_select = self.model_select, fit_templates=template_dicts[0], cds_othermodel = viewer_cds.cds_othermodel, cds_model_2ndfit = viewer_cds.cds_model_2ndfit, cds_model = viewer_cds.cds_model, fit_results=template_dicts[1], std_templates=template_dicts[2], median_spectra = viewer_cds.cds_median_spectra, smootherslider = self.smootherslider, z_input = self.z_input, cds_metadata = viewer_cds.cds_metadata), code = model_select_code) self.model_select.js_on_change('value', self.model_select_callback) def add_update_plot_callback(self, viewer_cds, plots, vi_widgets, template_dicts): #----- #- Main js code to update plots update_plot_code = (self.js_files["adapt_plotrange.js"] + self.js_files["interp_grid.js"] + self.js_files["smooth_data.js"] + self.js_files["coadd_brz_cameras.js"] + self.js_files["update_plot.js"]) # TMP handling of template_dicts the_fit_results = None if template_dicts is None else template_dicts[1] # dirty self.update_plot_callback = CustomJS( args = dict( spectra = viewer_cds.cds_spectra, coaddcam_spec = viewer_cds.cds_coaddcam_spec, model = viewer_cds.cds_model, othermodel = viewer_cds.cds_othermodel, model_2ndfit = viewer_cds.cds_model_2ndfit, metadata = viewer_cds.cds_metadata, fit_results = the_fit_results, shortcds_table_z = self.shortcds_table_z, shortcds_table_a = self.shortcds_table_a, shortcds_table_b = self.shortcds_table_b, shortcds_table_c = self.shortcds_table_c, shortcds_table_d = self.shortcds_table_d, ifiberslider = self.ifiberslider, smootherslider = self.smootherslider, z_input = self.z_input, fig = plots.fig, imfig_source = plots.imfig_source, imfig_urls = plots.imfig_urls, model_select = self.model_select, vi_comment_input = vi_widgets.vi_comment_input, vi_std_comment_select = vi_widgets.vi_std_comment_select, vi_name_input = vi_widgets.vi_name_input, vi_quality_input = vi_widgets.vi_quality_input, vi_quality_labels = vi_widgets.vi_quality_labels, vi_issue_input = vi_widgets.vi_issue_input, vi_z_input = vi_widgets.vi_z_input, vi_category_select = vi_widgets.vi_category_select, vi_issue_slabels = vi_widgets.vi_issue_slabels ), code = update_plot_code ) self.smootherslider.js_on_change('value', self.update_plot_callback) self.ifiberslider.js_on_change('value', self.update_plot_callback)
def Zancada(DatosBokeh, EjeX, MetricasAuxiliares): """ GRAFICO DISCRETO | LONGITUD DE ZANCADA """ # Creacion del diccionario de metricas auxiliares DiccionarioVariables = ParametrosVariables(DatosBokeh) # Generacion del codigo JavaScript que habilita la visualizacion de metricas auxiliares CodigoJS = GeneracionCodigoJS(MetricasAuxiliares) # Asignacion de tamaño del punto en graficas discretas SizeCircle = FunctionSizeCircle(DatosBokeh) # Creacion de un grafica PLT = figure(width=1000, height=400, x_range=(DatosBokeh.data[EjeX].min(), DatosBokeh.data[EjeX].max()), y_range=(LimiteEjeY(DatosBokeh, 'LONGITUD ZANCADA', 'Inferior'), LimiteEjeY(DatosBokeh, 'LONGITUD ZANCADA', 'Superior')), tools='', toolbar_location=None) # Inclusion de datos PLT.circle(EjeX, 'LongitudZancada[m]', source=DatosBokeh, size=SizeCircle, line_color=transform( 'LongitudZancada[m]', LinearColorMapper(palette=PaletaColoresLinea, low=0.8, high=2)), color=transform( 'LongitudZancada[m]', LinearColorMapper(palette=PaletaColores, low=0.8, high=2)), fill_alpha=1) PLT_Linea = PLT.line(EjeX, 'LongitudZancada[m]', source=DatosBokeh, color='white', line_width=0, line_alpha=0) PLT.add_tools( HoverTool(tooltips=[('', '@{LongitudZancada[m]}{0,0.00} m')], renderers=[PLT_Linea], mode='vline')) # Inclusion de lineas auxiliares ListadoMetricasAuxiliares = {} for Metrica in MetricasAuxiliares: if DiccionarioVariables[Metrica]['Tipo'] == 'circle': ListadoMetricasAuxiliares[ 'l' + str(MetricasAuxiliares.index(Metrica))] = PLT.circle( EjeX, DiccionarioVariables[Metrica]['Variable'].split('[', 1)[0] + DiccionarioVariables['LONGITUD ZANCADA']['Sufijo'], source=DiccionarioVariables[Metrica]['CDS'], size=SizeCircle, line_color=DiccionarioVariables[Metrica]['Color'], color=DiccionarioVariables[Metrica]['Color'], **DiccionarioVariables[Metrica]['Propiedades']) elif DiccionarioVariables[Metrica]['Tipo'] == 'step': ListadoMetricasAuxiliares[ 'l' + str(MetricasAuxiliares.index(Metrica))] = PLT.step( EjeX, DiccionarioVariables[Metrica]['Variable'].split('[', 1)[0] + DiccionarioVariables['LONGITUD ZANCADA']['Sufijo'], source=DiccionarioVariables[Metrica]['CDS'], color=DiccionarioVariables[Metrica]['Color'], **DiccionarioVariables[Metrica]['Propiedades']) else: ListadoMetricasAuxiliares[ 'l' + str(MetricasAuxiliares.index(Metrica))] = PLT.line( EjeX, DiccionarioVariables[Metrica]['Variable'].split('[', 1)[0] + DiccionarioVariables['LONGITUD ZANCADA']['Sufijo'], source=DiccionarioVariables[Metrica]['CDS'], color=DiccionarioVariables[Metrica]['Color'], **DiccionarioVariables[Metrica]['Propiedades']) # Atributos PLT.title.text = 'LONGITUD DE ZANCADA' PLT.sizing_mode = 'fixed' PLT.yaxis.axis_label = 'Longitud de zancada [m]' PLT.yaxis.formatter = NumeralTickFormatter(format='0.0') PLT.grid.visible = False PLT.yaxis.minor_tick_line_color = None # Asignacion de opciones de visualizacion del eje X if EjeX == 'Distancia[m]': PLT.xaxis.axis_label = 'Distancia' PLT.xaxis.formatter = NumeralTickFormatter(format='0') if DatosBokeh.data['Distancia[m]'].max() >= 4000: PLT.xaxis.ticker = SingleIntervalTicker(interval=1000) PLT.xaxis.major_label_overrides = FormateoEjes( DatosBokeh.data['Distancia[m]'], 1000, 1000, 0, 0) elif EjeX == 'TiempoActividad': PLT.xaxis.axis_label = 'Tiempo actividad' PLT.xaxis.formatter = DatetimeTickFormatter(hourmin='%H:%M:%S', minutes='%M:%S', seconds='%Ss') PLT.xaxis.ticker = DatetimeTicker() elif EjeX == 'TiempoTotal': PLT.xaxis.axis_label = 'Tiempo total' PLT.xaxis.formatter = DatetimeTickFormatter(hourmin='%H:%M:%S', minutes='%M:%S', seconds='%Ss') PLT.xaxis.ticker = DatetimeTicker() #Botones Botones = CheckboxGroup(labels=MetricasAuxiliares, active=[], width=100, height=380) ListadoMetricasAuxiliares['checkbox'] = Botones CodigoJSFrecuenciaCardiaca = CustomJS(code=CodigoJS, args=ListadoMetricasAuxiliares) Botones.js_on_click(CodigoJSFrecuenciaCardiaca) #Layout GridBotones = layout( [Spacer(width=100, height=25), Column(Botones, width=100, height=375)], sizing_mode='fixed', width=100, height=400) GridGrafica = gridplot([PLT, GridBotones], ncols=2, sizing_mode='stretch_width', toolbar_location=None, plot_width=1100, plot_height=400) return GridGrafica
def make_interactive_plot(qr: np.array, pvals, disp_data_full: list, disp_inter_full: list, labels: dict) -> None: """ Create the interactive Bokeh plot as a standalone html web page :param qr: x-values for the points :type qr: np.array :param pvals: slider values :type pvals: list :param disp_data_full: list of arrays containing q vectors and eigenvalues for points :type disp_data_full: list :param disp_inter_full: list of arrays containing interpolated x and eigen values :type disp_inter_full: list :param labels: labels for the x-axis indicating special points :type labels: dict :return: None .. todo:: add output file name option """ # Plotting from bokeh.plotting import figure, output_file from bokeh.io import show, output_notebook, push_notebook from bokeh.models import ColumnDataSource, Panel, CustomJS, Circle, Line, Div, HoverTool from bokeh.models.widgets import CheckboxGroup, Slider, RangeSlider from bokeh.layouts import column, row from bokeh.application import Application nfiles = len(disp_data_full) neigvals = disp_inter_full[0].shape[1] - 1 # first column is x-values # Output file name (web page) output_file("disp_app.html") # Create the figure p = figure(title="Dispersion curves for FCC", y_range=(0, 2.25), x_range=(0, qr[-1] + 0.001), x_axis_label="q", y_axis_label="ω (THz)", plot_width=800) # Glyphs for points and lines (intepolation) raw_glyphs = [] inter_glyphs = [] # Make dictionaries for Bokeh ColumnDataSource draw = {"xraw": qr} dint = {"xint": disp_inter_full[0][:, 0]} for ip in range(nfiles): for ie in range(neigvals): ei = "e" + str(ip) + "_" + str(ie) draw[ei] = disp_data_full[ip][:, ie + 3] dint[ei] = disp_inter_full[ip][:, ie + 1] srcraw = ColumnDataSource(draw) srcint = ColumnDataSource(dint) # Build glyphs for each pressure point for ip in range(nfiles): lalpha = 0 for ie in range(neigvals): ei = "e" + str(ip) + "_" + str(ie) if ip == 0: lalpha = 1 raw_glyphs.append( Circle(x="xraw", y=ei, line_alpha=lalpha, fill_alpha=lalpha)) inter_glyphs.append(Line(x="xint", y=ei, line_alpha=lalpha)) p.add_glyph(srcraw, raw_glyphs[-1]) p.add_glyph(srcint, inter_glyphs[-1]) # Styling p.xaxis.ticker = list(labels.keys()) # SPqr p.xaxis.major_label_overrides = labels # Widgets EIGEN_LBLS = ["Eigen " + str(i + 1) for i in range(neigvals)] eigen_chkbx_grp = CheckboxGroup(labels=EIGEN_LBLS, active=[i for i in range(neigvals)]) slider = Slider(start=1, end=nfiles, value=1, step=1, title="Pressure series") #pvals = [''.join(re.findall(regex, f)) for f in onlylogfiles ] div = Div(text="Pressure = " + pvals[0] + " bar", name="pval") # Callbacks for widgets ## Slider Callback slider.js_on_change( "value", CustomJS(args=dict(glp=raw_glyphs, glq=inter_glyphs, neig=neigvals, lbl=div, vals=pvals, chkbx=eigen_chkbx_grp), code=""" var i; var eigs = chkbx.active for (i=0; i<glp.length; i=i+1){ if (i>=(this.value-1)*neig && i < this.value*neig){ if( eigs.includes(i%neig) ){ glp[i]["fill_alpha"] = 1; glp[i]["line_alpha"] = 1; glq[i]["line_alpha"] = 1; } else { glp[i]["fill_alpha"] = 0; glp[i]["line_alpha"] = 0; glq[i]["line_alpha"] = 0; } console.log(i,'YES') }else{ glp[i]["fill_alpha"] = 0; glp[i]["line_alpha"] = 0; glq[i]["line_alpha"] = 0; console.log(i,'NO') } } lbl["text"] = "Pressure = " + vals[this.value-1] + " bar" """)) ## Checkbox callback eigen_chkbx_grp.js_on_click( CustomJS(args=dict(glp=raw_glyphs, glq=inter_glyphs, neig=neigvals, sldr=slider), code=""" var actv = this.active var i console.log("sldr ",sldr.value) for (i=(sldr.value-1)*neig; i<sldr.value*neig; i=i+1){ console.log('i, i%neig res = ', i, i%neig, actv.includes(i%neig)) if (actv.includes(i%neig)){ glp[i]["fill_alpha"]=1; glp[i]["line_alpha"]=1; glq[i]["line_alpha"]=1; } else { glp[i]["fill_alpha"]=0; glp[i]["line_alpha"]=0; glq[i]["line_alpha"]=0; } } """)) ## Add hover widget hover = HoverTool(tooltips=[("ω (THz)", "$y")]) p.add_tools(hover) ## Make the layout layout = column(eigen_chkbx_grp, p, row(slider, div)) ## Make the webpage show(layout)
def plot_linechart_areas_short_term_migration(): wb = openpyxl.load_workbook( 'data/Short term migration.xlsx') # Import datasets ws = wb.get_sheet_by_name('Data') x = [] areas = [] y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12,y13,y14,y15,y16,y17,y18,y19,y20,y21,y22,y23,y24,y25,y26,y27,y28,y29,y30,y31,y32,y33,y34 = [],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[] #Rearrange data for column in range(2, 12): areas.append(ws.cell(row=row, column=1).value) x.append(ws.cell(row=5, column=column).value) y1.append(ws.cell(row=6, column=column).value) y2.append(ws.cell(row=7, column=column).value) y3.append(ws.cell(row=8, column=column).value) y4.append(ws.cell(row=9, column=column).value) y5.append(ws.cell(row=10, column=column).value) y6.append(ws.cell(row=11, column=column).value) y7.append(ws.cell(row=12, column=column).value) y8.append(ws.cell(row=13, column=column).value) y9.append(ws.cell(row=14, column=column).value) y10.append(ws.cell(row=15, column=column).value) y11.append(ws.cell(row=16, column=column).value) y12.append(ws.cell(row=17, column=column).value) y13.append(ws.cell(row=18, column=column).value) y14.append(ws.cell(row=19, column=column).value) y15.append(ws.cell(row=20, column=column).value) y16.append(ws.cell(row=21, column=column).value) y17.append(ws.cell(row=22, column=column).value) y18.append(ws.cell(row=23, column=column).value) y19.append(ws.cell(row=24, column=column).value) y20.append(ws.cell(row=25, column=column).value) y21.append(ws.cell(row=26, column=column).value) y22.append(ws.cell(row=27, column=column).value) y23.append(ws.cell(row=28, column=column).value) y24.append(ws.cell(row=29, column=column).value) y25.append(ws.cell(row=30, column=column).value) y26.append(ws.cell(row=31, column=column).value) y27.append(ws.cell(row=32, column=column).value) y28.append(ws.cell(row=33, column=column).value) y29.append(ws.cell(row=34, column=column).value) y30.append(ws.cell(row=35, column=column).value) y31.append(ws.cell(row=36, column=column).value) y32.append(ws.cell(row=37, column=column).value) y33.append(ws.cell(row=38, column=column).value) y34.append(ws.cell(row=39, column=column).value) p_areas = figure( plot_width=1000, plot_height=500, x_axis_label="dates", y_axis_label="Migration population", y_range=(0, 7000), tools="hover,pan,box_zoom,save,reset,undo,zoom_in,zoom_out,wheel_zoom", title="Areas of London short-term migration") #Create a new figure p2 = p_areas.line(x=x, y=y2, line_width=1, color="#000003", legend="City of London") #draw a line chart p3 = p_areas.line(x=x, y=y3, line_width=1, color="#140D35", legend="Barking and Dagenham") #draw a line chart p4 = p_areas.line(x=x, y=y4, line_width=1, color="#3B0F6F", legend="Barnet") #draw a line chart p5 = p_areas.line(x=x, y=y5, line_width=1, color="#63197F", legend="Bexley") #draw a line chart p6 = p_areas.line(x=x, y=y6, line_width=1, color="#8C2980", legend="Brent") #draw a line chart p7 = p_areas.line(x=x, y=y7, line_width=1, color="#B53679", legend="Bromley") #draw a line chart p8 = p_areas.line(x=x, y=y8, line_width=1, color="#DD4968", legend="Camden") #draw a line chart p9 = p_areas.line(x=x, y=y9, line_width=1, color="#F66E5B", legend="Croydon") #draw a line chart p10 = p_areas.line(x=x, y=y10, line_width=1, color="#FD9F6C", legend="Ealing") #draw a line chart p11 = p_areas.line(x=x, y=y11, line_width=1, color="#FDCD90", legend="Enfield") #draw a line chart p12 = p_areas.line(x=x, y=y12, line_width=1, color="#FBFCBF", legend="Greenwich") #draw a line chart p13 = p_areas.line(x=x, y=y13, line_width=1, color="#a6cee3", legend="Hackney") #draw a line chart p14 = p_areas.line(x=x, y=y14, line_width=1, color="#1f78b4", legend="Hammersmith and Fulham") #draw a line chart p15 = p_areas.line(x=x, y=y15, line_width=1, color="#b2df8a", legend="Haringey") #draw a line chart p16 = p_areas.line(x=x, y=y16, line_width=1, color="#33a02c", legend="Harrow") #draw a line chart p17 = p_areas.line(x=x, y=y17, line_width=1, color="#fb9a99", legend="Havering") #draw a line chart p18 = p_areas.line(x=x, y=y18, line_width=1, color="#e31a1c", legend="Hillingdon") #draw a line chart p19 = p_areas.line(x=x, y=y19, line_width=1, color="#fdbf6f", legend="Hounslow") #draw a line chart p20 = p_areas.line(x=x, y=y20, line_width=1, color="#ff7f00", legend="Islington") #draw a line chart p21 = p_areas.line(x=x, y=y21, line_width=1, color="#cab2d6", legend="Kensington and Chelsea") #draw a line chart p22 = p_areas.line(x=x, y=y22, line_width=1, color="#6a3d9a", legend="Kingston upon Thames") #draw a line chart p23 = p_areas.line(x=x, y=y23, line_width=1, color="#ffff99", legend="Lambeth") #draw a line chart p24 = p_areas.line(x=x, y=y24, line_width=1, color="#b15928", legend="Lewisham") #draw a line chart p25 = p_areas.line(x=x, y=y25, line_width=1, color="#e41a1c", legend="Merton") #draw a line chart p26 = p_areas.line(x=x, y=y26, line_width=1, color="#377eb8", legend="Newham") #draw a line chart p27 = p_areas.line(x=x, y=y27, line_width=1, color="#4daf4a", legend="Redbridge") #draw a line chart p28 = p_areas.line(x=x, y=y28, line_width=1, color="#984ea3", legend="Richmond upon Thames") #draw a line chart p29 = p_areas.line(x=x, y=y29, line_width=1, color="#ff7f00", legend="Southwark") #draw a line chart p30 = p_areas.line(x=x, y=y30, line_width=1, color="#ffff33", legend="Sutton") #draw a line chart p31 = p_areas.line(x=x, y=y31, line_width=1, color="#a65628", legend="Tower Hamlets") #draw a line chart p32 = p_areas.line(x=x, y=y32, line_width=1, color="#f781bf", legend="Waltham Forest") #draw a line chart p33 = p_areas.line(x=x, y=y33, line_width=1, color="#410967", legend="Wandsworth") #draw a line chart p34 = p_areas.line(x=x, y=y34, line_width=1, color="#6A176E", legend="Westminster") #draw a line chart #Set legend location adn legemd orientation p_areas.legend.location = "top_left" p_areas.legend.orientation = "horizontal" #Set callback function after click checkboxes display_event = CustomJS(code=""" p2.visible = false; p3.visible = false; p4.visible = false; p5.visible = false; p6.visible = false; p7.visible = false; p8.visible = false; p9.visible = false; p10.visible = false; p11.visible = false; p12.visible = false; p13.visible = false; p14.visible = false; p15.visible = false; p16.visible = false; p17.visible = false; p18.visible = false; p19.visible = false; p20.visible = false; p21.visible = false; p22.visible = false; p23.visible = false; p24.visible = false; p25.visible = false; p26.visible = false; p27.visible = false; p28.visible = false; p29.visible = false; p30.visible = false; p31.visible = false; p32.visible = false; p33.visible = false; p34.visible = false; if(cb_obj.active.includes(0)){ p2.visible = true; } if (cb_obj.active.includes(1)){ p3.visible = true; } if (cb_obj.active.includes(2)){ p4.visible = true; } if (cb_obj.active.includes(3)){ p5.visible = true; } if (cb_obj.active.includes(4)){ p6.visible = true; } if (cb_obj.active.includes(5)){ p7.visible = true; } if (cb_obj.active.includes(6)){ p8.visible = true; } if (cb_obj.active.includes(7)){ p9.visible = true; } if (cb_obj.active.includes(8)){ p10.visible = true; } if (cb_obj.active.includes(9)){ p11.visible = true; } if (cb_obj.active.includes(10)){ p12.visible = true; } if (cb_obj.active.includes(11)){ p13.visible = true; } if (cb_obj.active.includes(12)){ p14.visible = true; } if (cb_obj.active.includes(13)){ p15.visible = true; } if (cb_obj.active.includes(14)){ p16.visible = true; } if (cb_obj.active.includes(15)){ p17.visible = true; } if (cb_obj.active.includes(16)){ p18.visible = true; } if (cb_obj.active.includes(17)){ p19.visible = true; } if (cb_obj.active.includes(18)){ p20.visible = true; } if (cb_obj.active.includes(19)){ p21.visible = true; } if (cb_obj.active.includes(20)){ p22.visible = true; } if (cb_obj.active.includes(21)){ p23.visible = true; } if (cb_obj.active.includes(22)){ p24.visible = true; } if (cb_obj.active.includes(23)){ p25.visible = true; } if (cb_obj.active.includes(24)){ p26.visible = true; } if (cb_obj.active.includes(25)){ p27.visible = true; } if (cb_obj.active.includes(26)){ p28.visible = true; } if (cb_obj.active.includes(27)){ p29.visible = true; } if (cb_obj.active.includes(28)){ p30.visible = true; } if (cb_obj.active.includes(29)){ p31.visible = true; } if (cb_obj.active.includes(30)){ p32.visible = true; } if (cb_obj.active.includes(31)){ p33.visible = true; } if (cb_obj.active.includes(32)){ p34.visible = true; } """, args={ 'p2': p2, 'p3': p3, 'p4': p4, 'p5': p5, 'p6': p6, 'p7': p7, 'p8': p8, 'p9': p9, 'p10': p10, 'p11': p11, 'p12': p12, 'p13': p13, 'p14': p14, 'p15': p15, 'p16': p16, 'p17': p17, 'p18': p18, 'p19': p19, 'p20': p20, 'p21': p21, 'p22': p22, 'p23': p23, 'p24': p24, 'p25': p25, 'p26': p26, 'p27': p27, 'p28': p28, 'p29': p29, 'p30': p30, 'p31': p31, 'p32': p32, 'p33': p33, 'p34': p34 }) #Set widgets checkboxes selection_box = CheckboxGroup(labels=[ "City of London", "Barking and Dagenham", "Barnet", "Bexley", "Brent", "Bromley", "Camden", "Croydon", "Ealing", "Enfield", "Greenwich", "Hackney", "Hammersmith and Fulham", "Haringey", "Harrow", "Havering", "Hillingdon", "Hounslow", "Islington", "Kensington and Chelsea", "Kingston upon Thames", "Lambeth", "Lewisham", "Merton", "Newham", "Redbridge", "Richmond upon Thames", "Southwark", "Sutton", "Tower Hamlets", "Waltham Forest", "Wandsworth", "Westminster" ], active=[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 ]) selection_box.js_on_click(display_event) row_1 = [p_areas, selection_box] #Make selection boxes located besides line chart return row_1