class BokehPlot(object): def __init__(self, device, points_list, *, title='My title', show_notes=True, update_data=True): self.device = device if len(points_list) < 3: raise ValueError("Provide at least 3 objects to the chart") self.points_list = points_list self.title = title self.units = {} self.show_notes = show_notes self.lst = self.points_list self.multi_states = self.device.multi_states self.binary_states = self.device.binary_states self.analog_units = self.device.analog_units plot = self.build_plot() self.device.properties.network.bokeh_document.add_plot( plot, infos=self.device.properties) #curdoc().add_root(plot) if update_data: self.device.properties.network.bokeh_document.add_periodic_callback( self.update_data, 100) print('Chart created, please reload your web page to see changes') # Get data def read_lst(self): df = self.device[self.lst] try: df = df.fillna(method='ffill').fillna(method='bfill').replace( ['inactive', 'active'], [0, 1]) except TypeError: df = df.fillna(method='ffill').fillna(method='bfill') df = df.reset_index() df['name'] = 'nameToReplace' df['units'] = 'waiting for refresh' df['time_s'] = df['index'].apply(str) return df def read_notes(self): notes_df = self.device.notes.reset_index() notes_df['value'] = -5 notes_df['desc'] = 'Notes' notes_df['time_s'] = notes_df['index'].apply(str) return notes_df def build_plot(self): df = self.read_lst() notes_df = self.read_notes() TOOLS = "pan,box_zoom,wheel_zoom,save,reset" self.p = Figure(x_axis_type="datetime", x_axis_label="Time", y_axis_label="Numeric Value", title=self.title, tools=TOOLS, plot_width=700, plot_height=600, toolbar_location='above') if self.show_notes: self.notes_source = ColumnDataSource( data=dict(x=notes_df['index'], y=notes_df['value'], time=notes_df['time_s'], desc=notes_df['desc'], units=notes_df[0])) self.p.asterisk( 'x', 'y', source=self.notes_source, name='Notes', #color = "#%06x" % random.randint(0x000000, 0x777777), legend='Notes', size=40) self.p.legend.location = 'top_left' self.p.extra_y_ranges = { "bool": Range1d(start=0, end=1.1), "enum": Range1d(start=0, end=10) } self.p.add_layout(LinearAxis(y_range_name="bool", axis_label="Binary"), 'left') self.p.add_layout( LinearAxis(y_range_name="enum", axis_label="Enumerated"), 'right') self.p.legend.location = "bottom_left" hover = HoverTool(tooltips=[ ('name', '@desc'), ('value', '@y'), ('units', '@units'), ('time', '@time'), ]) self.p.add_tools(hover) self.sources = {} if len(self.lst) <= 10: color_mapper = dict(zip(self.lst, d3['Category10'][len(self.lst)])) else: # This would be a very loaded trend... color_mapper = dict(zip(self.lst, Spectral6[:len(self.lst)])) for each in self.lst: try: df['name'] = df['name'].replace( 'nameToReplace', ('%s / %s' % (each, self.device[each]['description']))) except TypeError: continue self.sources[each] = ColumnDataSource(data=dict(x=df['index'], y=df[each], time=df['time_s'], name=df['name'], units=df['units'])) if each in self.binary_states: self.p.circle( 'x', 'y', source=self.sources[each], name=each, color=color_mapper[each], legend=("%s/%s (OFF-ON)" % (each, self.device[each]['description'])), y_range_name="bool", size=10) elif each in self.multi_states: self.p.diamond( 'x', 'y', source=self.sources[each], name=each, color=color_mapper[each], legend=("%s/%s (%s)" % (each, self.device[each]['description'], self.device[each].properties.units_state)), y_range_name="enum", size=20) else: self.p.line( 'x', 'y', source=self.sources[each], name=each, color=color_mapper[each], legend=("%s/%s (%s)" % (each, self.device[each]['description'], self.device[each].properties.units_state)), line_width=2) if self.show_notes: columns = [ TableColumn(field="x", title="Date", formatter=DateFormatter(format='yy-mm-dd')), TableColumn(field="units", title="Notes"), ] data_table = DataTable(source=self.notes_source, columns=columns) return (self.p, data_table) else: return (self.p, None) def update_data(self): if self.device.properties.network._started: df = self.read_lst() for renderer in self.p.renderers: name = renderer.name glyph_renderer = renderer new_data = {} if name in self.points_list: df['name'] = ('%s / %s' % (name, self.device[name]['description'])) new_data['x'] = df['index'] new_data['y'] = df[name] new_data['desc'] = df['name'] new_data['time'] = df['time_s'] if name in self.multi_states: new_data['units'] = [ self.multi_states[name][int(math.fabs(x - 1))] for x in df[name] ] elif name in self.binary_states: new_data['y'] = df[name] new_data['units'] = [ self.binary_states[name][int(x / 1)] for x in df[name] ] else: df['units'] = self.analog_units[name] new_data['units'] = df['units'] glyph_renderer.data_source.data = new_data elif name == 'Notes': notes_df = self.read_notes() new_data['x'] = notes_df['index'] new_data['y'] = notes_df['value'] new_data['desc'] = notes_df['desc'] new_data['units'] = notes_df[0] new_data['time'] = notes_df['time_s'] glyph_renderer.data_source.data = new_data
def plot_waveform_bokeh(filename,waveform_list,metadata_list,station_lat_list,\ station_lon_list, event_lat, event_lon, boundary_data, style_parameter): xlabel_fontsize = style_parameter['xlabel_fontsize'] # map_station_location_bokeh = ColumnDataSource(data=dict(map_lat_list=station_lat_list,\ map_lon_list=station_lon_list)) dot_default_index = 0 selected_dot_on_map_bokeh = ColumnDataSource(data=dict(lat=[station_lat_list[dot_default_index]],\ lon=[station_lon_list[dot_default_index]],\ index=[dot_default_index])) map_view = Figure(plot_width=style_parameter['map_view_plot_width'], \ plot_height=style_parameter['map_view_plot_height'], \ y_range=[style_parameter['map_view_lat_min'],\ style_parameter['map_view_lat_max']], x_range=[style_parameter['map_view_lon_min'],\ style_parameter['map_view_lon_max']], tools=style_parameter['map_view_tools'],\ title=style_parameter['map_view_title']) # ------------------------------ # add boundaries to map view # country boundaries map_view.multi_line(boundary_data['country']['longitude'],\ boundary_data['country']['latitude'],color='gray',\ line_width=2, level='underlay', nonselection_line_alpha=1.0,\ nonselection_line_color='gray') # marine boundaries map_view.multi_line(boundary_data['marine']['longitude'],\ boundary_data['marine']['latitude'],color='gray',\ level='underlay', nonselection_line_alpha=1.0,\ nonselection_line_color='gray') # shoreline boundaries map_view.multi_line(boundary_data['shoreline']['longitude'],\ boundary_data['shoreline']['latitude'],color='gray',\ line_width=2, nonselection_line_alpha=1.0, level='underlay', nonselection_line_color='gray') # state boundaries map_view.multi_line(boundary_data['state']['longitude'],\ boundary_data['state']['latitude'],color='gray',\ level='underlay', nonselection_line_alpha=1.0,\ nonselection_line_color='gray') # map_view.triangle('map_lon_list', 'map_lat_list', source=map_station_location_bokeh, \ line_color='gray', size=style_parameter['marker_size'], fill_color='black',\ selection_color='black', selection_line_color='gray',\ selection_fill_alpha=1.0,\ nonselection_fill_alpha=1.0, nonselection_fill_color='black',\ nonselection_line_color='gray', nonselection_line_alpha=1.0) map_view.triangle('lon','lat', source=selected_dot_on_map_bokeh,\ size=style_parameter['selected_marker_size'], line_color='black',fill_color='red') map_view.asterisk([event_lon], [event_lat], size=style_parameter['event_marker_size'], line_width=3, line_color='red', \ fill_color='red') # change style map_view.title.text_font_size = style_parameter['title_font_size'] map_view.title.align = 'center' map_view.title.text_font_style = 'normal' map_view.xaxis.axis_label = style_parameter['map_view_xlabel'] map_view.xaxis.axis_label_text_font_style = 'normal' map_view.xaxis.axis_label_text_font_size = xlabel_fontsize map_view.xaxis.major_label_text_font_size = xlabel_fontsize map_view.yaxis.axis_label = style_parameter['map_view_ylabel'] map_view.yaxis.axis_label_text_font_style = 'normal' map_view.yaxis.axis_label_text_font_size = xlabel_fontsize map_view.yaxis.major_label_text_font_size = xlabel_fontsize map_view.xgrid.grid_line_color = None map_view.ygrid.grid_line_color = None map_view.toolbar.logo = None map_view.toolbar_location = 'above' map_view.toolbar_sticky = False # -------------------------------------------------------- max_waveform_length = 0 max_waveform_amp = 0 ncurve = len(waveform_list) for a_sta in waveform_list: for a_trace in a_sta: if len(a_trace) > max_waveform_length: max_waveform_length = len(a_trace) if np.max(np.abs(a_trace)) > max_waveform_amp: max_waveform_amp = np.max(np.abs(a_trace)) # plotting_list = [] for a_sta in waveform_list: temp = [] for a_trace in a_sta: if len(a_trace) < max_waveform_length: a_trace = np.append(a_trace,np.zeros([(max_waveform_length-len(a_trace)),1])) temp.append(list(a_trace)) plotting_list.append(temp) # time_list = [] for ista in range(len(plotting_list)): a_sta = plotting_list[ista] temp = [] for itr in range(len(a_sta)): a_trace = a_sta[itr] delta = metadata_list[ista][itr]['delta'] time = list(np.arange(len(a_trace))*delta) temp.append(time) # time_list.append(temp) # reftime_label_list = [] channel_label_list = [] for ista in range(len(metadata_list)): temp_ref = [] temp_channel = [] a_sta = metadata_list[ista] for a_trace in a_sta: temp_ref.append('Starting from '+a_trace['starttime']) temp_channel.append(a_trace['network']+'_'+a_trace['station']+'_'+a_trace['channel']) reftime_label_list.append(temp_ref) channel_label_list.append(temp_channel) # -------------------------------------------------------- curve_fig01 = Figure(plot_width=style_parameter['curve_plot_width'], plot_height=style_parameter['curve_plot_height'], \ y_range=(-max_waveform_amp*1.05,max_waveform_amp*1.05), \ x_range=(0,max_waveform_length),\ tools=['save','box_zoom','ywheel_zoom','xwheel_zoom','reset','crosshair','pan']) # curve_index = 0 select_curve_data = plotting_list[dot_default_index][curve_index] select_curve_time = time_list[dot_default_index][curve_index] selected_curve_data_bokeh01 = ColumnDataSource(data=dict(time=select_curve_time,amp=select_curve_data)) select_reftime_label = reftime_label_list[dot_default_index][curve_index] selected_reftime_label_bokeh01 = ColumnDataSource(data=dict(x=[style_parameter['curve_reftime_label_x']],\ y=[style_parameter['curve_reftime_label_y']],\ label=[select_reftime_label])) select_channel_label = channel_label_list[dot_default_index][curve_index] selected_channel_label_bokeh01 = ColumnDataSource(data=dict(x=[style_parameter['curve_channel_label_x']],\ y=[style_parameter['curve_channel_label_y']],\ label=[select_channel_label])) all_curve_data_bokeh = ColumnDataSource(data=dict(t=time_list, amp=plotting_list)) all_reftime_label_bokeh = ColumnDataSource(data=dict(label=reftime_label_list)) all_channel_label_bokeh = ColumnDataSource(data=dict(label=channel_label_list)) # plot waveform curve_fig01.line('time','amp', source=selected_curve_data_bokeh01,\ line_color='black') # add refference time as a label curve_fig01.text('x', 'y', 'label', source=selected_reftime_label_bokeh01) # add channel label curve_fig01.text('x', 'y', 'label', source=selected_channel_label_bokeh01) # change style curve_fig01.title.text_font_size = style_parameter['title_font_size'] curve_fig01.title.align = 'center' curve_fig01.title.text_font_style = 'normal' curve_fig01.xaxis.axis_label = style_parameter['curve_xlabel'] curve_fig01.xaxis.axis_label_text_font_style = 'normal' curve_fig01.xaxis.axis_label_text_font_size = xlabel_fontsize curve_fig01.xaxis.major_label_text_font_size = xlabel_fontsize curve_fig01.yaxis.axis_label = style_parameter['curve_ylabel'] curve_fig01.yaxis.axis_label_text_font_style = 'normal' curve_fig01.yaxis.axis_label_text_font_size = xlabel_fontsize curve_fig01.yaxis.major_label_text_font_size = xlabel_fontsize curve_fig01.toolbar.logo = None curve_fig01.toolbar_location = 'above' curve_fig01.toolbar_sticky = False # -------------------------------------------------------- curve_fig02 = Figure(plot_width=style_parameter['curve_plot_width'], plot_height=style_parameter['curve_plot_height'], \ y_range=(-max_waveform_amp*1.05,max_waveform_amp*1.05), \ x_range=(0,max_waveform_length),\ tools=['save','box_zoom','ywheel_zoom','xwheel_zoom','reset','crosshair','pan']) # curve_index = 1 select_curve_data = plotting_list[dot_default_index][curve_index] select_curve_time = time_list[dot_default_index][curve_index] selected_curve_data_bokeh02 = ColumnDataSource(data=dict(time=select_curve_time,amp=select_curve_data)) select_channel_label = channel_label_list[dot_default_index][curve_index] selected_channel_label_bokeh02 = ColumnDataSource(data=dict(x=[style_parameter['curve_channel_label_x']],\ y=[style_parameter['curve_channel_label_y']],\ label=[select_channel_label])) # plot waveform curve_fig02.line('time','amp', source=selected_curve_data_bokeh02,\ line_color='black') # add channel label curve_fig02.text('x', 'y', 'label', source=selected_channel_label_bokeh02) # change style curve_fig02.title.text_font_size = style_parameter['title_font_size'] curve_fig02.title.align = 'center' curve_fig02.title.text_font_style = 'normal' curve_fig02.xaxis.axis_label = style_parameter['curve_xlabel'] curve_fig02.xaxis.axis_label_text_font_style = 'normal' curve_fig02.xaxis.axis_label_text_font_size = xlabel_fontsize curve_fig02.xaxis.major_label_text_font_size = xlabel_fontsize curve_fig02.yaxis.axis_label = style_parameter['curve_ylabel'] curve_fig02.yaxis.axis_label_text_font_style = 'normal' curve_fig02.yaxis.axis_label_text_font_size = xlabel_fontsize curve_fig02.yaxis.major_label_text_font_size = xlabel_fontsize curve_fig02.toolbar.logo = None curve_fig02.toolbar_location = 'above' curve_fig02.toolbar_sticky = False # -------------------------------------------------------- curve_fig03 = Figure(plot_width=style_parameter['curve_plot_width'], plot_height=style_parameter['curve_plot_height'], \ y_range=(-max_waveform_amp*1.05,max_waveform_amp*1.05), \ x_range=(0,max_waveform_length),\ tools=['save','box_zoom','ywheel_zoom','xwheel_zoom','reset','crosshair','pan']) # curve_index = 2 select_curve_data = plotting_list[dot_default_index][curve_index] select_curve_time = time_list[dot_default_index][curve_index] selected_curve_data_bokeh03 = ColumnDataSource(data=dict(time=select_curve_time,amp=select_curve_data)) select_channel_label = channel_label_list[dot_default_index][curve_index] selected_channel_label_bokeh03 = ColumnDataSource(data=dict(x=[style_parameter['curve_channel_label_x']],\ y=[style_parameter['curve_channel_label_y']],\ label=[select_channel_label])) # plot waveform curve_fig03.line('time','amp', source=selected_curve_data_bokeh03,\ line_color='black') # add channel label curve_fig03.text('x', 'y', 'label', source=selected_channel_label_bokeh03) # change style curve_fig03.title.text_font_size = style_parameter['title_font_size'] curve_fig03.title.align = 'center' curve_fig03.title.text_font_style = 'normal' curve_fig03.xaxis.axis_label = style_parameter['curve_xlabel'] curve_fig03.xaxis.axis_label_text_font_style = 'normal' curve_fig03.xaxis.axis_label_text_font_size = xlabel_fontsize curve_fig03.xaxis.major_label_text_font_size = xlabel_fontsize curve_fig03.yaxis.axis_label = style_parameter['curve_ylabel'] curve_fig03.yaxis.axis_label_text_font_style = 'normal' curve_fig03.yaxis.axis_label_text_font_size = xlabel_fontsize curve_fig03.yaxis.major_label_text_font_size = xlabel_fontsize curve_fig03.toolbar.logo = None curve_fig03.toolbar_location = 'above' curve_fig03.toolbar_sticky = False # -------------------------------------------------------- map_station_location_js = CustomJS(args=dict(selected_dot_on_map_bokeh=selected_dot_on_map_bokeh,\ map_station_location_bokeh=map_station_location_bokeh,\ selected_curve_data_bokeh01=selected_curve_data_bokeh01,\ selected_curve_data_bokeh02=selected_curve_data_bokeh02,\ selected_curve_data_bokeh03=selected_curve_data_bokeh03,\ selected_channel_label_bokeh01=selected_channel_label_bokeh01,\ selected_channel_label_bokeh02=selected_channel_label_bokeh02,\ selected_channel_label_bokeh03=selected_channel_label_bokeh03,\ selected_reftime_label_bokeh01=selected_reftime_label_bokeh01,\ all_reftime_label_bokeh=all_reftime_label_bokeh,\ all_channel_label_bokeh=all_channel_label_bokeh,\ all_curve_data_bokeh=all_curve_data_bokeh), code=""" var inds = cb_obj.indices selected_dot_on_map_bokeh.data['index'] = [inds] var new_loc = map_station_location_bokeh.data selected_dot_on_map_bokeh.data['lat'] = [new_loc['map_lat_list'][inds]] selected_dot_on_map_bokeh.data['lon'] = [new_loc['map_lon_list'][inds]] selected_dot_on_map_bokeh.change.emit() selected_curve_data_bokeh01.data['t'] = all_curve_data_bokeh.data['t'][inds][0] selected_curve_data_bokeh01.data['amp'] = all_curve_data_bokeh.data['amp'][inds][0] selected_curve_data_bokeh01.change.emit() selected_curve_data_bokeh02.data['t'] = all_curve_data_bokeh.data['t'][inds][1] selected_curve_data_bokeh02.data['amp'] = all_curve_data_bokeh.data['amp'][inds][1] selected_curve_data_bokeh02.change.emit() selected_curve_data_bokeh03.data['t'] = all_curve_data_bokeh.data['t'][inds][2] selected_curve_data_bokeh03.data['amp'] = all_curve_data_bokeh.data['amp'][inds][2] selected_curve_data_bokeh03.change.emit() selected_reftime_label_bokeh01.data['label'] = [all_reftime_label_bokeh.data['label'][inds][0]] selected_reftime_label_bokeh01.change.emit() selected_channel_label_bokeh01.data['label'] = [all_channel_label_bokeh.data['label'][inds][0]] selected_channel_label_bokeh01.change.emit() selected_channel_label_bokeh02.data['label'] = [all_channel_label_bokeh.data['label'][inds][1]] selected_channel_label_bokeh02.change.emit() selected_channel_label_bokeh03.data['label'] = [all_channel_label_bokeh.data['label'][inds][2]] selected_channel_label_bokeh03.change.emit() """) # map_station_location_bokeh.selected.js_on_change('indices', map_station_location_js) # curve_slider_callback = CustomJS(args=dict(selected_dot_on_map_bokeh=selected_dot_on_map_bokeh,\ map_station_location_bokeh=map_station_location_bokeh,\ selected_curve_data_bokeh01=selected_curve_data_bokeh01,\ selected_curve_data_bokeh02=selected_curve_data_bokeh02,\ selected_curve_data_bokeh03=selected_curve_data_bokeh03,\ selected_channel_label_bokeh01=selected_channel_label_bokeh01,\ selected_channel_label_bokeh02=selected_channel_label_bokeh02,\ selected_channel_label_bokeh03=selected_channel_label_bokeh03,\ selected_reftime_label_bokeh01=selected_reftime_label_bokeh01,\ all_reftime_label_bokeh=all_reftime_label_bokeh,\ all_channel_label_bokeh=all_channel_label_bokeh,\ all_curve_data_bokeh=all_curve_data_bokeh),code=""" var inds = Math.round(cb_obj.value) selected_dot_on_map_bokeh.data['index'] = [inds] var new_loc = map_station_location_bokeh.data selected_dot_on_map_bokeh.data['lat'] = [new_loc['map_lat_list'][inds]] selected_dot_on_map_bokeh.data['lon'] = [new_loc['map_lon_list'][inds]] selected_dot_on_map_bokeh.change.emit() selected_curve_data_bokeh01.data['t'] = all_curve_data_bokeh.data['t'][inds][0] selected_curve_data_bokeh01.data['amp'] = all_curve_data_bokeh.data['amp'][inds][0] selected_curve_data_bokeh01.change.emit() selected_curve_data_bokeh02.data['t'] = all_curve_data_bokeh.data['t'][inds][1] selected_curve_data_bokeh02.data['amp'] = all_curve_data_bokeh.data['amp'][inds][1] selected_curve_data_bokeh02.change.emit() selected_curve_data_bokeh03.data['t'] = all_curve_data_bokeh.data['t'][inds][2] selected_curve_data_bokeh03.data['amp'] = all_curve_data_bokeh.data['amp'][inds][2] selected_curve_data_bokeh03.change.emit() selected_reftime_label_bokeh01.data['label'] = [all_reftime_label_bokeh.data['label'][inds][0]] selected_reftime_label_bokeh01.change.emit() selected_channel_label_bokeh01.data['label'] = [all_channel_label_bokeh.data['label'][inds][0]] selected_channel_label_bokeh01.change.emit() selected_channel_label_bokeh02.data['label'] = [all_channel_label_bokeh.data['label'][inds][1]] selected_channel_label_bokeh02.change.emit() selected_channel_label_bokeh03.data['label'] = [all_channel_label_bokeh.data['label'][inds][2]] selected_channel_label_bokeh03.change.emit() """) curve_slider = Slider(start=0, end=ncurve-1, value=style_parameter['curve_default_index'], \ step=1, title=style_parameter['curve_slider_title'], width=style_parameter['map_view_plot_width'],\ height=50, callback=curve_slider_callback) # ============================== # annotating text annotating_fig01 = Div(text=style_parameter['annotating_html01'], \ width=style_parameter['annotation_plot_width'], height=style_parameter['annotation_plot_height']) annotating_fig02 = Div(text=style_parameter['annotating_html02'],\ width=style_parameter['annotation_plot_width'], height=style_parameter['annotation_plot_height']) # ============================== output_file(filename,title=style_parameter['html_title'],mode=style_parameter['library_source']) # left_fig = Column(curve_slider, map_view, annotating_fig01, width=style_parameter['left_column_width'] ) right_fig = Column(curve_fig01, curve_fig02, curve_fig03, annotating_fig02, width=style_parameter['right_column_width']) layout = Row(left_fig, right_fig) save(layout)
class BokehPlot(object): def __init__(self, device, points_list, *, title='My title', show_notes=True, update_data=True): self.device = device self.points_list = points_list self.title = title self.units = {} self.show_notes = show_notes self.lst = self.points_list self.multi_states = self.device.multi_states self.binary_states = self.device.binary_states self.analog_units = self.device.analog_units plot = self.build_plot() self.device.properties.network.bokeh_document.add_plot(plot) if update_data: self.device.properties.network.bokeh_document.add_periodic_callback( self.update_data, 100) print('Chart created, please reload your web page to see changes') # Get data def read_lst(self): df = self.device[self.lst] try: df = df.fillna(method='ffill').fillna(method='bfill').replace( ['inactive', 'active'], [0, 1]) except TypeError: df = df.fillna(method='ffill').fillna(method='bfill') df = df.reset_index() df['name'] = 'nameToReplace' df['units'] = 'waiting for refresh' df['time_s'] = df['index'].apply(str) return df def read_notes(self): notes_df = self.device.notes.reset_index() notes_df['value'] = -5 notes_df['desc'] = 'Notes' notes_df['time_s'] = notes_df['index'].apply(str) return notes_df def build_plot(self): df = self.read_lst() notes_df = self.read_notes() TOOLS = "hover,resize,save,pan,box_zoom,wheel_zoom,reset" #plot_width=800, plot_height=600, self.p = Figure(x_axis_type="datetime", title=self.title, tools=TOOLS) if self.show_notes: self.notes_source = ColumnDataSource( data=dict(x=notes_df['index'], y=notes_df['value'], time=notes_df['time_s'], desc=notes_df['desc'], units=notes_df[0])) self.p.asterisk('x', 'y', source=self.notes_source, name='Notes', color="#%06x" % random.randint(0x000000, 0x777777), legend='Notes', size=40) self.p.legend.location = 'top_left' self.p.extra_y_ranges = { "bool": Range1d(start=0, end=1.1), "enum": Range1d(start=0, end=10) } self.p.add_layout(LinearAxis(y_range_name="bool"), 'left') self.p.add_layout(LinearAxis(y_range_name="enum"), 'right') hover = self.p.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([ ('name', '@desc'), ('value', '@y'), ('units', '@units'), ('time', '@time'), ]) self.sources = {} for each in self.lst: try: df['name'] = df['name'].replace( 'nameToReplace', ('%s / %s' % (each, self.device[each]['description']))) except TypeError: continue self.sources[each] = ColumnDataSource(data=dict(x=df['index'], y=df[each], time=df['time_s'], name=df['name'], units=df['units'])) if each in self.binary_states: self.p.circle('x', 'y', source=self.sources[each], name=each, color="#%06x" % random.randint(0x000000, 0x777777), legend=each, y_range_name="bool", size=10) elif each in self.multi_states: self.p.diamond('x', 'y', source=self.sources[each], name=each, color="#%06x" % random.randint(0x000000, 0x777777), legend=each, y_range_name="enum", size=20) else: self.p.line('x', 'y', source=self.sources[each], name=each, color="#%06x" % random.randint(0x000000, 0x777777), legend=each, line_width=2) return self.p def update_data(self): if self.device.properties.network._started: df = self.read_lst() for renderer in self.p.renderers: name = renderer.name if name in self.points_list: glyph_renderer = renderer df['name'] = ('%s / %s' % (name, self.device[name]['description'])) glyph_renderer.data_source.data['x'] = df['index'] glyph_renderer.data_source.data['y'] = df[name] glyph_renderer.data_source.data['desc'] = df['name'] glyph_renderer.data_source.data['time'] = df['time_s'] if name in self.multi_states: glyph_renderer.data_source.data['units'] = [ self.multi_states[name][int(math.fabs(x - 1))] for x in df[name] ] elif name in self.binary_states: glyph_renderer.data_source.data['y'] = df[name] glyph_renderer.data_source.data['units'] = [ self.binary_states[name][int(x / 1)] for x in df[name] ] else: df['units'] = self.analog_units[name] glyph_renderer.data_source.data['units'] = df['units'] elif name == 'Notes': notes_df = self.read_notes() glyph_renderer = renderer glyph_renderer.data_source.data['x'] = notes_df['index'] glyph_renderer.data_source.data['y'] = notes_df['value'] glyph_renderer.data_source.data['desc'] = notes_df['desc'] glyph_renderer.data_source.data['units'] = notes_df[0] glyph_renderer.data_source.data['time'] = notes_df[ 'time_s']
a_rad = 2.7 * rv['mstar'] rv_syms = p1.circle(rv['semi'] / a_rad, rv['msini'] * mjup, color='red', fill_alpha=0.4, line_alpha=1., size=8) # microlens ulens = Table.read( '/Users/tumlinson/Dropbox/LUVOIR_STDT/luvoir_simtools/planetspace/ulens.dat', format='ascii', names=['name', 'msini', 'semi', 'mstar']) a_rad = 2.7 * ulens['mstar'] ulens_syms = p1.asterisk(ulens['semi'] / a_rad, ulens['msini'] * mjup, color='green', size=8) # imaging ulens = Table.read( '/Users/tumlinson/Dropbox/LUVOIR_STDT/luvoir_simtools/planetspace/imaging.dat', format='ascii', names=['name', 'msini', 'semi', 'mstar']) a_rad = 2.7 * ulens['mstar'] ulens_syms = p1.square(ulens['semi'] / a_rad, ulens['msini'] * mjup, fill_alpha=0.4, line_alpha=0.9, color='purple', size=8)
class BokehPlot(object): def __init__(self, device, points_list, *, title = 'My title', show_notes = True, update_data = True): self.device = device self.points_list = points_list self.title = title self.units = {} self.show_notes = show_notes self.lst = self.points_list self.multi_states = self.device.multi_states self.binary_states = self.device.binary_states self.analog_units = self.device.analog_units plot = self.build_plot() self.device.properties.network.bokeh_document.add_plot(plot) if update_data: self.device.properties.network.bokeh_document.add_periodic_callback(self.update_data, 100) print('Chart created, please reload your web page to see changes') # Get data def read_lst(self): df = self.device[self.lst] try: df = df.fillna(method='ffill').fillna(method='bfill').replace(['inactive', 'active'], [0, 1]) except TypeError: df = df.fillna(method='ffill').fillna(method='bfill') df = df.reset_index() df['name'] = 'nameToReplace' df['units'] = 'waiting for refresh' df['time_s'] = df['index'].apply(str) return df def read_notes(self): notes_df = self.device.notes.reset_index() notes_df['value'] = -5 notes_df['desc'] = 'Notes' notes_df['time_s'] = notes_df['index'].apply(str) return notes_df def build_plot(self): df = self.read_lst() notes_df = self.read_notes() TOOLS = "hover,resize,save,pan,box_zoom,wheel_zoom,reset" #plot_width=800, plot_height=600, self.p = Figure(x_axis_type="datetime", title = self.title, tools = TOOLS) if self.show_notes: self.notes_source = ColumnDataSource( data=dict( x = notes_df['index'], y = notes_df['value'], time = notes_df['time_s'], desc = notes_df['desc'], units = notes_df[0] ) ) self.p.asterisk('x', 'y', source = self.notes_source, name = 'Notes', color = "#%06x" % random.randint(0x000000, 0x777777), legend='Notes', size = 40) self.p.legend.location = 'top_left' self.p.extra_y_ranges = {"bool": Range1d(start=0, end=1.1), "enum": Range1d(start=0, end=10)} self.p.add_layout(LinearAxis(y_range_name="bool"), 'left') self.p.add_layout(LinearAxis(y_range_name="enum"), 'right') hover = self.p.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([ ('name', '@desc'), ('value', '@y'), ('units', '@units'), ('time', '@time'), ]) self.sources = {} for each in self.lst: try: df['name'] = df['name'].replace('nameToReplace', ('%s / %s' % (each, self.device[each]['description']))) except TypeError: continue self.sources[each] = ColumnDataSource( data=dict( x = df['index'], y = df[each], time = df['time_s'], name = df['name'], units = df['units'] ) ) if each in self.binary_states: self.p.circle('x', 'y', source = self.sources[each], name = each, color = "#%06x" % random.randint(0x000000, 0x777777), legend=each, y_range_name="bool", size = 10) elif each in self.multi_states: self.p.diamond('x', 'y', source = self.sources[each], name = each, color = "#%06x" % random.randint(0x000000, 0x777777), legend=each, y_range_name="enum", size = 20) else: self.p.line('x', 'y', source = self.sources[each], name = each, color = "#%06x" % random.randint(0x000000, 0x777777), legend=each, line_width = 2) return self.p def update_data(self): if self.device.properties.network._started: df = self.read_lst() for renderer in self.p.renderers: name = renderer.name if name in self.points_list: glyph_renderer = renderer df['name'] = ('%s / %s' % (name, self.device[name]['description'])) glyph_renderer.data_source.data['x'] = df['index'] glyph_renderer.data_source.data['y'] = df[name] glyph_renderer.data_source.data['desc'] = df['name'] glyph_renderer.data_source.data['time'] = df['time_s'] if name in self.multi_states: glyph_renderer.data_source.data['units'] = [self.multi_states[name][int(math.fabs(x-1))] for x in df[name]] elif name in self.binary_states: glyph_renderer.data_source.data['y'] = df[name] glyph_renderer.data_source.data['units'] = [self.binary_states[name][int(x/1)] for x in df[name]] else: df['units'] = self.analog_units[name] glyph_renderer.data_source.data['units'] = df['units'] elif name == 'Notes': notes_df = self.read_notes() glyph_renderer = renderer glyph_renderer.data_source.data['x'] = notes_df['index'] glyph_renderer.data_source.data['y'] = notes_df['value'] glyph_renderer.data_source.data['desc'] = notes_df['desc'] glyph_renderer.data_source.data['units'] = notes_df[0] glyph_renderer.data_source.data['time'] = notes_df['time_s']