def plot_bar_stack( p: Figure, source: ColumnDataSource, df: pd.DataFrame ) -> List[GlyphRenderer]: # Plot bar stack. measurements = list(df["Measurement"].unique()) n_measurements = len(measurements) color = list((Category20_20 * 2)[:n_measurements]) if "None" in measurements: color[measurements.index("None")] = "black" bar_stack = p.vbar_stack( **BAR_STACK_KWARGS, stackers=measurements, color=color, source=source, ) stack_hover = HoverTool( renderers=bar_stack, tooltips=STACK_HOVER_TOOLTIPS, ) p.add_tools(stack_hover) # Customize left y-axis range. p.y_range.start = 0 max_count = bar_stack[0].data_source.data["total"].max() + 1 p.y_range.end = max_count # Create a legend. kwargs = LEGEND_KWARGS.copy() if len(measurements) == 1: kwargs["location"] = (0, 250) legend = Legend( items=[ (measurement, [bar_stack[i]]) for i, measurement in enumerate(measurements) ], **kwargs, ) p.add_layout(legend, "right") return bar_stack
def update_plot(event): N, G, T, V, I, Vm, Im, I_N, datapoints = get_inputs() print('#' * 30) print('Updating the plot') print('#' * 30) updated_data = iv.iv_data(N, G, T, V, I, Vm, Im, I_N, datapoints) source.data = updated_data[0] source_translated.data = updated_data[1] res_source.data = updated_data[2] global status_param status_param = updated_data[3] print(status_param) if (status_param.success == True): print('Inside success') cite = Label(text='Successful Parameter Extraction', render_mode='css', text_color='white', border_line_color='green', background_fill_color='green') else: print('Inside fail') cite = Label(text='Parameter extraction not converging', render_mode='css', text_color='white', border_line_color='red', background_fill_color='red') error_plt = Figure( plot_width=100, plot_height=50, toolbar_location=None, ) error_plt.add_layout(cite) layout.children[2].children[1] = error_plt
def make_plot(src): # Blank plot with correct labels p = Figure( plot_width=1024, plot_height=768, x_axis_type="datetime", title="perfmon", output_backend="webgl", ) cm = plt.get_cmap("gist_rainbow") numlines = len(perfmon.columns) mypal = [cm(1.0 * i / numlines) for i in range(numlines)] mypal = list(map(lambda x: colors.rgb2hex(x), mypal)) col = 0 legenditems = [] for key in src.data.keys(): if key == "datetime": continue l = key + " " col = col + 1 cline = p.line( perfmon.index.values, perfmon[key], line_width=1, alpha=0.8, color=mypal[col], ) legenditems += [(key, [cline])] p.legend.click_policy = "hide" legend = Legend(items=legenditems, location=(0, 0)) p.add_layout(legend, "below") return p
def gen_cmatrix_legend(p: Figure) -> Figure: legend = Legend(items=[tuple((n, [r])) for n, r in zip(dashboard_constants.CMATRIX_CLASS_NAMES, p.renderers)], location="top_center", orientation="horizontal", click_policy='hide', border_line_alpha=0, background_fill_alpha=0) legend.label_text_color = '#003566' p.add_layout(legend, 'above') return p
def add_volume_bars(price: pd.DataFrame, p: Figure) -> Figure: # note that we set the y-range here to be 3 times the data range so that the volume bars appear in the bottom third p.extra_y_ranges = {"vol": Range1d(start=price.Volume.min(), end=price.Volume.max()*3)} # use bottom=price.Volume.min() to have bottom of bars clipped off. p.vbar(price.Date, w, top=price.Volume, y_range_name="vol") # https://bokeh.pydata.org/en/latest/docs/reference/models/formatters.html#bokeh.models.formatters.NumeralTickFormatter p.add_layout(LinearAxis(y_range_name="vol", formatter=NumeralTickFormatter(format='$0,0')), 'right') return p
def add_cumulative_axis(p: Figure, source: ColumnDataSource): # Create right y-axis for cumulative line. cumulative_top = source.data["cumulative"].max() * 1.1 p.extra_y_ranges = { "cumulative_y_range": Range1d(start=0, end=cumulative_top) } cumulative_axis = LinearAxis(**CUMULATIVE_AXIS_KWARGS) p.add_layout(cumulative_axis, "right")
def render_scatter( itmdt: Intermediate, plot_width: int, plot_height: int, palette: Sequence[str] ) -> Figure: """ Render scatter plot with a regression line and possible most influencial points """ # pylint: disable=too-many-locals df = itmdt["data"] xcol, ycol, *maybe_label = df.columns tooltips = [(xcol, f"@{{{xcol}}}"), (ycol, f"@{{{ycol}}}")] fig = Figure( plot_width=plot_width, plot_height=plot_height, toolbar_location=None, title=Title(text="Scatter Plot & Regression Line", align="center"), tools=[], x_axis_label=xcol, y_axis_label=ycol, ) # Scatter scatter = fig.scatter(x=df.columns[0], y=df.columns[1], source=df) if maybe_label: assert len(maybe_label) == 1 mapper = CategoricalColorMapper(factors=["=", "+", "-"], palette=palette) scatter.glyph.fill_color = {"field": maybe_label[0], "transform": mapper} scatter.glyph.line_color = {"field": maybe_label[0], "transform": mapper} # Regression line coeff_a, coeff_b = itmdt["coeffs"] line_x = np.asarray([df.iloc[:, 0].min(), df.iloc[:, 0].max()]) line_y = coeff_a * line_x + coeff_b fig.line(x=line_x, y=line_y, line_width=3) # Not adding the tooltips before because we only want to apply tooltip to the scatter hover = HoverTool(tooltips=tooltips, renderers=[scatter]) fig.add_tools(hover) # Add legends if maybe_label: nidx = df.index[df[maybe_label[0]] == "-"][0] pidx = df.index[df[maybe_label[0]] == "+"][0] legend = Legend( items=[ LegendItem(label="Most Influential (-)", renderers=[scatter], index=nidx), LegendItem(label="Most Influential (+)", renderers=[scatter], index=pidx), ], margin=0, padding=0, ) fig.add_layout(legend, place="right") return fig
def create_fig(self, sources): """ Implementation of :meth:`LivePlot.create_fig` to set up the bokeh figure """ fig = Figure(background_fill_color= None, toolbar_location = None, x_range=[-100, 100], y_range=[-100, 100], tools="", **self._fig_args) # Remove existing axes and grid fig.xgrid.grid_line_color = None fig.ygrid.grid_line_color = None fig.axis.visible = False # Draw circular grid th = np.linspace(0, 360, 100) # Draw visibility field self.vis_horizon = 10 #fig.patch(*pol2rect([90 - self.vis_horizon]*len(th), th), color='lightgray') fig.patch(*azel2rect(th, [self.vis_horizon]*len(th)), color='lightgray') for r in [0, 20, 40, 60, 80]: fig.line(*azel2rect(th, [r]*len(th)), line_dash='dashed') for th in np.arange(0,360,45): fig.line(*azel2rect([th,th], [0,90]), line_dash='dashed') # Add grid labels lx,ly = azel2rect([0, 90, 180, 270], [0]*4) lx[1] -= 30 lx[2] -= 20 ly[0] -= 10 lx[0] -= 10 src_labels = ColumnDataSource(dict( labels= ['N (0)', 'E (90)', 'S (180)', 'W (270)'], label_x= lx, label_y =ly)) fig.add_layout(LabelSet(x='label_x', y='label_y', text='labels', source=src_labels)) fig.line(source=sources['dpass'], x='x', y = 'y', line_width=2) fig.circle(source=sources['ant_cmd'], x='x', y='y', size=20, fill_color=None) fig.circle(source=sources['ant_cur'], x='x', y='y', size=10, color='green') fig.circle(source=sources['sat'], x= 'x', y ='y', size=10, color= 'yellow') return fig
class ScatterDiagram(Component): def __init__(self, environment: Environment): super().__init__() self.environment = environment self.data_source = ColumnDataSource( data=dict(x_axis=[], y_axis=[], color=[])) self.diagram = Figure(plot_width=400, plot_height=400) self.x_axis_menu = Select(title="x axis", value="radius", options=list(BlobStatistics)) self.y_axis_menu = Select(title="y axis", value="speed", options=list(BlobStatistics)) self.color_menu = Select(title="colours", value="time of birth", options=list(BlobStatistics)) self.color_mapper = LinearColorMapper(palette='Cividis11') self.color_bar = ColorBar(color_mapper=self.color_mapper, location=(0, 0)) self.diagram.circle('x_axis', 'y_axis', color={ 'field': 'color', 'transform': self.color_mapper }, source=self.data_source) self.diagram.add_layout(self.color_bar, 'right') self.component = column( self.diagram, row(self.x_axis_menu, self.y_axis_menu, self.color_menu)) def refresh(self): self.data_source.data = { 'x_axis': [ BlobStatistics[self.x_axis_menu.value](organism, self.environment) for organism in self.environment.organisms.organism_list ], 'y_axis': [ BlobStatistics[self.y_axis_menu.value](organism, self.environment) for organism in self.environment.organisms.organism_list ], 'color': [ BlobStatistics[self.color_menu.value](organism, self.environment) for organism in self.environment.organisms.organism_list ] }
def render_heatmaps_tab(itmdt: Intermediate, plot_width: int, plot_height: int, palette: Sequence[str]) -> Figure: """ Render missing heatmaps in to tabs """ tooltips = [("x", "@x"), ("y", "@y"), ("correlation", "@correlation{1.11}")] axis_range = itmdt["axis_range"] df = itmdt["data_heatmap"] df = df.where( np.triu(np.ones(df.shape)).astype(np.bool) # pylint: disable=no-member ).T df = df.unstack().reset_index(name="correlation") df = df.rename(columns={"level_0": "x", "level_1": "y"}) df = df[df["x"] != df["y"]] df = df.dropna() # in case of numerical column names df["x"] = df["x"].apply(str) df["y"] = df["y"].apply(str) mapper, color_bar = create_color_mapper_heatmap(palette) x_range = FactorRange(*axis_range) y_range = FactorRange(*reversed(axis_range)) fig = Figure( x_range=x_range, y_range=y_range, plot_width=plot_width, plot_height=plot_height, x_axis_location="below", tools="hover", toolbar_location=None, tooltips=tooltips, background_fill_color="#fafafa", ) tweak_figure(fig) fig.grid.grid_line_color = None fig.axis.axis_line_color = None fig.rect( x="x", y="y", width=1, height=1, source=df, fill_color={ "field": "correlation", "transform": mapper }, line_color=None, ) fig.add_layout(color_bar, "right") return fig
def update_success(): if (status_param.success==True): print ('Inside success') cite = Label(text='Success', render_mode='css', text_color='white', border_line_color='green', background_fill_color='green') else: print ('Inside fail') cite = Label(text='False', render_mode='css', text_color='white', border_line_color='red', background_fill_color='red') error_plt = Figure(plot_width=100, plot_height=50, toolbar_location = None,) error_plt.add_layout(cite) layout.children[2].children[1] = error_plt
def highlight( fig: Figure, x_start: Any, x_end: Any, color: str = "#FF3936", redirect_to: str = None, ): """Add a box highlight to an area above the x axis. If a redirection URL is given, it can open the URL on double-click (this assumes datetimes are used on x axis!). It will pass the year, month, day, hour and minute as parameters to the URL.""" ba = BoxAnnotation( left=x_start, right=x_end, fill_alpha=0.1, line_color=color, fill_color=color ) fig.add_layout(ba) if redirect_to is not None: if isinstance(x_start, datetime): def open_order_book( o_url: str, box_start: datetime, box_end: datetime ) -> CustomJS: return CustomJS( code=""" var boxStartDate = new Date("%s"); var boxEndDate = new Date("%s"); var clickedDate = new Date(cb_obj["x"]); // This quick-fixes some localisation behaviour in bokeh JS (a bug?). Bring back to UTC. clickedDate = new Date(clickedDate.getTime() + clickedDate.getTimezoneOffset() * 60000); console.log("tapped!!"); if (boxStartDate <= clickedDate && clickedDate <= boxEndDate) { // TODO: change this to a URL which fits the order book once we actually make it work var urlPlusParams = "%s" + "?year=" + clickedDate.getUTCFullYear() + "&month=" + (clickedDate.getUTCMonth()+1) + "&day=" + clickedDate.getUTCDate() + "&hour=" + clickedDate.getUTCHours() + "&minute=" + clickedDate.getMinutes(); $(location).attr("href", urlPlusParams); } """ % ( box_start.replace(tzinfo=None), box_end.replace(tzinfo=None), o_url, ) ) else: raise NotImplementedError( "Highlighting only works for datetime ranges" ) # TODO: implement for other x-range types fig.js_on_event(events.DoubleTap, open_order_book(redirect_to, x_start, x_end))
def main (): logger.debug('version %s starting' % VERSION) opt, args = getParms() # Find all the exons in all the transcripts for the gene, put them # in a list. tranList = list() # list of Transcript objects exonList = list() # list of Exon objects if opt.gtf is not None: getGeneFromAnnotation (opt, tranList, exonList) # lists will be changed if opt.matches is not None: getGeneFromMatches (opt, tranList, exonList) # lists will be changed if len(exonList) == 0: raise RuntimeError ('no exons found for gene %s in annotation or match files' % opt.gene) forwardStrand = '-' if opt.flip else '+' if exonList[0].strand == forwardStrand: exonList.sort(key=lambda x: x.start) # sort the list by start position blocks = assignBlocks (opt, exonList) # assign each exon to a block else: exonList.sort(key=lambda x: x.end, reverse=True) # sort the list by decreasing end position blocks = assignBlocksReverse (opt, exonList) # assign each exon to a block -- backwards findRegions (tranList) # determine regions occupied by each transcript tranNames = orderTranscripts (tranList) output_file("transcript.html") p = Figure(plot_width=1000, plot_height=750) df = groupTran(tranList, exonList, opt.group) length = len(tranNames) for myExon in exonList: exonSize = myExon.end - myExon.start + 1 adjStart = myExon.adjStart for index, row in df.iterrows(): name = row['name'] groupColor = 'purple' if name in myExon.name: groupColor = row['color'] break p.line([adjStart, adjStart+exonSize], [length-(myExon.tran.tranIx+1), length-(myExon.tran.tranIx+1)], line_width=20, line_color=groupColor) f_range = FactorRange(factors=tranNames[::-1]) p.extra_y_ranges = {"Tran": f_range} new_axis = CategoricalAxis(y_range_name="Tran") p.add_layout(new_axis, 'left') show(p)
def relocate_legend(fig: Figure, loc: str) -> Figure: """Relocate legend(s) from center to `loc`.""" remains = [] targets = [] for layout in fig.center: if isinstance(layout, Legend): targets.append(layout) else: remains.append(layout) fig.center = remains for layout in targets: fig.add_layout(layout, loc) return fig
def render_correlation_heatmaps(itmdt: Intermediate, plot_width: int, plot_height: int) -> Tabs: """ Render correlation heatmaps in to tabs """ tabs: List[Panel] = [] tooltips = [("x", "@x"), ("y", "@y"), ("correlation", "@correlation{1.11}")] axis_range = itmdt["axis_range"] for method, df in itmdt["data"].items(): # in case of numerical column names df = df.copy() df["x"] = df["x"].apply(str) df["y"] = df["y"].apply(str) mapper, color_bar = create_color_mapper(RDBU) x_range = FactorRange(*axis_range) y_range = FactorRange(*reversed(axis_range)) fig = Figure( x_range=x_range, y_range=y_range, plot_width=plot_width, plot_height=plot_height, x_axis_location="below", tools="hover", toolbar_location=None, tooltips=tooltips, background_fill_color="#fafafa", ) tweak_figure(fig) fig.rect( x="x", y="y", width=1, height=1, source=df, fill_color={"field": "correlation", "transform": mapper}, line_color=None, ) fig.add_layout(color_bar, "right") tab = Panel(child=fig, title=method) tabs.append(tab) tabs = Tabs(tabs=tabs) return tabs
def multi_plot(figure_info, source): fig = Figure(plot_width=figure_info["plot_width"], plot_height=figure_info["plot_height"], title=figure_info["title"], x_axis_type="datetime") fig.extra_y_ranges = { "foo": Range1d(start=0, end=figure_info["max_unemployment"]) } fig.add_layout(LinearAxis(y_range_name="foo"), 'right') for idx in range(1, len(figure_info["names"])): legend_name = str(figure_info["legends"][idx - 1]) + " " if "Unem" not in figure_info["names"][idx]: fig.vbar(source=source, x=figure_info["names"][0], top=figure_info["names"][idx], bottom=0, width=1000000000, color=figure_info["colors"][idx - 1], fill_alpha=0.2, line_alpha=0.1, legend=legend_name) else: fig.line(source=source, x=figure_info["names"][0], y=figure_info["names"][idx], line_width=figure_info["line_widths"][idx - 1], alpha=figure_info["alphas"][idx - 1], color=figure_info["colors"][idx - 1], legend=legend_name, y_range_name="foo") fig.legend.location = figure_info["legend_location"] fig.xaxis.axis_label = figure_info["xaxis_label"] fig.yaxis.axis_label = figure_info["yaxis_label"] fig.title.align = figure_info["title_align"] return fig
def _create_title_fig(self): fig = Figure(sizing_mode='scale_width', x_range=[0, 1], y_range=[0, 1], plot_height=50, tools="") # Remove existing axes and grid fig.xgrid.grid_line_color = None fig.ygrid.grid_line_color = None fig.axis.visible = False fig.background_fill_color = None fig.toolbar_location = None text = Label(x=0.5, y=0.5, text=self._title_text, render_mode='css', background_fill_color='white', background_fill_alpha=1.0, text_font_size='28pt', text_align='center', text_baseline='middle' ) fig.add_layout(text) return (fig)
x = spectrumwave[i], y = [y_offsets[i] + j for j in spectrumscaled[i]], src = [catalog[entry]['spectra'][i]['source']]*sl ) if 'redshift' in catalog[entry]: data['xrest'] = [x/(1.0 + z) for x in spectrumwave[i]] if 'timeunit' in spectrum and 'time' in spectrum: data['epoch'] = [catalog[entry]['spectra'][i]['time'] for j in spectrumscaled[i]] sources.append(ColumnDataSource(data)) p2.line('x', 'y', source=sources[i], color=mycolors[i % len(mycolors)], line_width=2) if 'redshift' in catalog[entry]: minredw = minsw/(1.0 + z) maxredw = maxsw/(1.0 + z) p2.extra_x_ranges = {"other wavelength": Range1d(start=minredw, end=maxredw)} p2.add_layout(LinearAxis(axis_label ="Restframe Wavelength (Å)", x_range_name="other wavelength"), 'above') sdicts = dict(zip(['s'+str(x) for x in range(len(sources))], sources)) callback = CustomJS(args=sdicts, code=""" var yoffs = [""" + ','.join([str(x) for x in y_offsets]) + """]; for (s = 0; s < """ + str(len(sources)) + """; s++) { var data = eval('s'+s).get('data'); var redshift = """ + str(z if 'redshift' in catalog[entry] else 0.) + """; if (!('binsize' in data)) { data['binsize'] = 1.0 } if (!('spacing' in data)) { data['spacing'] = 1.0 } if (cb_obj.get('title') == 'Spacing') { data['spacing'] = cb_obj.get('value');
def plot(): # FIGURES AND X-AXIS fig1 = Figure(title = 'Dive Profile', plot_width = WIDTH, plot_height = HEIGHT, tools = TOOLS) fig2 = Figure(title = 'Dive Controls', plot_width = WIDTH, plot_height = HEIGHT, tools = TOOLS, x_range=fig1.x_range) fig3 = Figure(title = 'Attitude', plot_width = WIDTH, plot_height = HEIGHT, tools = TOOLS, x_range=fig1.x_range) figs = gridplot([[fig1],[fig2],[fig3]]) # Formatting x-axis timeticks = DatetimeTickFormatter(formats=dict(seconds =["%b%d %H:%M:%S"], minutes =["%b%d %H:%M"], hourmin =["%b%d %H:%M"], hours =["%b%d %H:%M"], days =["%b%d %H:%M"], months=["%b%d %H:%M"], years =["%b%d %H:%M %Y"])) fig1.xaxis.formatter = timeticks fig2.xaxis.formatter = timeticks fig3.xaxis.formatter = timeticks # removing gridlines fig1.xgrid.grid_line_color = None fig1.ygrid.grid_line_color = None fig2.xgrid.grid_line_color = None fig2.ygrid.grid_line_color = None fig3.xgrid.grid_line_color = None fig3.ygrid.grid_line_color = None # INPUT WIDGETS collection_list = CONN[DB].collection_names(include_system_collections=False) gliders = sorted([platformID for platformID in collection_list if len(platformID)>2]) gliders = Select(title = 'PlatformID', value = gliders[0], options = gliders) prev_glider = Button(label = '<') next_glider = Button(label = '>') glider_controlbox = HBox(children = [gliders, prev_glider, next_glider], height=80) chunkations = Select(title = 'Chunkation', value = 'segment', options = ['segment', '24hr', '30days', '-ALL-']) chunk_indicator = TextInput(title = 'index', value = '0') prev_chunk = Button(label = '<') next_chunk = Button(label = '>') chunk_ID = PreText(height=80) chunk_controlbox = HBox(chunkations, HBox(chunk_indicator, width=25), prev_chunk, next_chunk, chunk_ID, height = 80) control_box = HBox(glider_controlbox, chunk_controlbox) # DATA VARS deadby_date = '' depth = ColumnDataSource(dict(x=[],y=[])) vert_vel = ColumnDataSource(dict(x=[],y=[])) mbpump = ColumnDataSource(dict(x=[],y=[])) battpos = ColumnDataSource(dict(x=[],y=[])) pitch = ColumnDataSource(dict(x=[],y=[])) mfin = ColumnDataSource(dict(x=[],y=[])) cfin = ColumnDataSource(dict(x=[],y=[])) mroll = ColumnDataSource(dict(x=[],y=[])) mheading = ColumnDataSource(dict(x=[],y=[])) cheading = ColumnDataSource(dict(x=[],y=[])) # AXIS setup colors = COLORS[:] fig1.y_range.flipped = True fig1.yaxis.axis_label = 'm_depth (m)' fig1.extra_y_ranges = {'vert_vel': Range1d(start=-50, end=50), 'dummy': Range1d(start=0, end=100)} fig1.add_layout(place = 'right', obj = LinearAxis(y_range_name = 'vert_vel', axis_label = 'vertical velocity (cm/s)')) fig1.add_layout(place = 'left', obj = LinearAxis(y_range_name = 'dummy', axis_label = ' ')) fig1.yaxis[1].visible = False fig1.yaxis[1].axis_line_alpha = 0 fig1.yaxis[1].major_label_text_alpha = 0 fig1.yaxis[1].major_tick_line_alpha = 0 fig1.yaxis[1].minor_tick_line_alpha = 0 fig2.yaxis.axis_label = 'pitch (deg)' fig2.y_range.start, fig2.y_range.end = -40,40 fig2.extra_y_ranges = {'battpos': Range1d(start=-1, end = 1), 'bpump': Range1d(start=-275, end=275)} fig2.add_layout(place = 'right', obj = LinearAxis(y_range_name = 'battpos', axis_label = 'battpos (in)')) fig2.add_layout(place = 'left', obj = LinearAxis(y_range_name = 'bpump', axis_label = 'bpump (cc)')) fig2.yaxis[1].visible = False # necessary for spacing. later gets set to true fig3.yaxis.axis_label = 'fin/roll (deg)' fig3.y_range.start, fig3.y_range.end = -30, 30 fig3.extra_y_ranges = {'heading': Range1d(start=0, end=360), #TODO dynamic avg centering 'dummy': Range1d(start=0, end=100)} fig3.add_layout(place = 'right', obj = LinearAxis(y_range_name = 'heading', axis_label = 'headings (deg)')) fig3.add_layout(place = 'left', obj = LinearAxis(y_range_name = 'dummy', axis_label = ' ')) fig3.yaxis[1].visible = False fig3.yaxis[1].axis_line_alpha = 0 fig3.yaxis[1].major_label_text_alpha = 0 fig3.yaxis[1].major_tick_line_alpha = 0 fig3.yaxis[1].minor_tick_line_alpha = 0 # PLOT OBJECTS fig1.line( 'x', 'y', source = depth, legend = 'm_depth', color = 'red') fig1.circle('x', 'y', source = depth, legend = 'm_depth', color = 'red') fig1.line( 'x', 'y', source = vert_vel, legend = 'vert_vel', color = 'green', y_range_name = 'vert_vel') fig1.circle('x', 'y', source = vert_vel, legend = 'vert_vel', color = 'green', y_range_name = 'vert_vel') fig1.renderers.append(Span(location = 0, dimension = 'width', y_range_name = 'vert_vel', line_color= 'green', line_dash='dashed', line_width=1)) fig2.line( 'x', 'y', source = pitch, legend = "m_pitch", color = 'indigo') fig2.circle('x', 'y', source = pitch, legend = "m_pitch", color = 'indigo') fig2.line( 'x', 'y', source = battpos, legend = 'm_battpos', color = 'magenta', y_range_name = 'battpos') fig2.circle('x', 'y', source = battpos, legend = 'm_battpos', color = 'magenta', y_range_name = 'battpos') fig2.line( 'x', 'y', source = mbpump, legend = "m_'bpump'", color = 'blue', y_range_name = 'bpump') fig2.circle('x', 'y', source = mbpump, legend = "m_'bpump'", color = 'blue', y_range_name = 'bpump') fig2.renderers.append(Span(location = 0, dimension = 'width', line_color= 'black', line_dash='dashed', line_width=1)) fig3.line( 'x', 'y', source = mfin, legend = 'm_fin', color = 'cyan') fig3.circle('x', 'y', source = mfin, legend = 'm_fin', color = 'cyan') fig3.line( 'x', 'y', source = cfin, legend = 'c_fin', color = 'orange') fig3.circle('x', 'y', source = cfin, legend = 'c_fin', color = 'orange') fig3.line( 'x', 'y', source = mroll, legend = 'm_roll', color = 'magenta') fig3.circle('x', 'y', source = mroll, legend = 'm_roll', color = 'magenta') fig3.line( 'x', 'y', source = mheading, legend = 'm_heading', color = 'blue', y_range_name = 'heading') fig3.circle('x', 'y', source = mheading, legend = 'm_heading', color = 'blue', y_range_name = 'heading') fig3.line( 'x', 'y', source = cheading, legend = 'c_heading', color = 'indigo', y_range_name = 'heading') fig3.circle('x', 'y', source = cheading, legend = 'c_heading', color = 'indigo', y_range_name = 'heading') fig3.renderers.append(Span(location = 0, dimension = 'width', y_range_name = 'default', line_color= 'black', line_dash='dashed', line_width=1)) # CALLBACK FUNCS def update_data(attrib,old,new): g = gliders.value chnk = chunkations.value chindex = abs(int(chunk_indicator.value)) depth.data = dict(x=[],y=[]) vert_vel.data = dict(x=[],y=[]) mbpump.data = dict(x=[],y=[]) battpos.data = dict(x=[],y=[]) pitch.data = dict(x=[],y=[]) mfin.data = dict(x=[],y=[]) cfin.data = dict(x=[],y=[]) mroll.data = dict(x=[],y=[]) mheading.data = dict(x=[],y=[]) cheading.data = dict(x=[],y=[]) depth.data,startend = load_sensor(g, 'm_depth', chnk, chindex) if chnk == 'segment': xbd = startend[2] chunk_ID.text = '{} {} \n{} ({}) \nSTART: {} \nEND: {}'.format(g, xbd['mission'], xbd['onboard_filename'], xbd['the8x3_filename'], e2ts(xbd['start']), e2ts(xbd['end'])) if len(set(depth.data['x']))<=1 and attrib == 'chunk': if old > new: next_chunk.clicks += 1 else: prev_chunk.clicks += 1 return elif len(set(depth.data['x']))<=1 and chunk_indicator.value == 0: chunk_indicator.value = 1 elif chnk in ['24hr', '30days']: chunk_ID.text = '{} \nSTART: {} \nEND: {}'.format(g, e2ts(startend[0]), e2ts(startend[1])) elif chnk == '-ALL-': chunk_ID.text = '{} \nSTART: {} \nEND: {}'.format(g,e2ts(depth.data['x'][0] /1000), e2ts(depth.data['x'][-1]/1000)) vert_vel.data = calc_vert_vel(depth.data) mbpump.data,_ = load_sensor(g, 'm_de_oil_vol', chnk, chindex) if len(mbpump.data['x']) > 1: #for yax in fig2.select('mbpump'): # yax.legend = 'm_de_oil_vol' pass else: mbpump.data,_ = load_sensor(g, 'm_ballast_pumped', chnk, chindex) #for yax in fig2.select('mbpump'): # yax.legend = 'm_ballast_pumped' battpos.data,_ = load_sensor(g, 'm_battpos', chnk, chindex) pitch.data,_ = load_sensor(g, 'm_pitch', chnk, chindex) pitch.data['y'] = [math.degrees(y) for y in pitch.data['y']] mfin.data,_ = load_sensor(g, 'm_fin', chnk, chindex) cfin.data,_ = load_sensor(g, 'c_fin', chnk, chindex) mroll.data,_ = load_sensor(g, 'm_roll', chnk, chindex) mheading.data,_ = load_sensor(g, 'm_heading', chnk, chindex) cheading.data,_ = load_sensor(g, 'c_heading', chnk, chindex) mfin.data['y'] = [math.degrees(y) for y in mfin.data['y']] cfin.data['y'] = [math.degrees(y) for y in cfin.data['y']] mheading.data['y'] = [math.degrees(y) for y in mheading.data['y']] cheading.data['y'] = [math.degrees(y) for y in cheading.data['y']] mroll.data['y'] = [math.degrees(y) for y in mroll.data['y']] fig1.yaxis[1].visible = True fig2.yaxis[1].visible = True fig3.yaxis[1].visible = True #GLIDER SELECTS def glider_buttons(increment): ops = gliders.options new_index = ops.index(gliders.value) + increment if new_index >= len(ops): new_index = 0 elif new_index < 0: new_index = len(ops)-1 gliders.value = ops[new_index] chunkation_update(None, None, None) #reset chunk indicator and clicks def next_glider_func(): glider_buttons(1) def prev_glider_func(): glider_buttons(-1) def update_glider(attrib,old,new): chunk_indicator.value = '0' #update_data(None,None,None) gliders.on_change('value', update_glider) next_glider.on_click(next_glider_func) prev_glider.on_click(prev_glider_func) #CHUNK SELECTS def chunkation_update(attrib,old,new): chunk_indicator.value = '0' prev_chunk.clicks = 0 next_chunk.clicks = 0 update_data(None,None,None) if new == '-ALL-': chunk_indicator.value = '-' def chunk_func(): chunkdiff = prev_chunk.clicks - next_chunk.clicks if chunkdiff < 0: prev_chunk.clicks = 0 next_chunk.clicks = 0 chunkdiff = 0 print (chunkdiff) chunk_indicator.value = str(chunkdiff) def chunk_indicator_update(attrib,old,new): try: if abs(int(old)-int(new))>1: #manual update, triggers new non-manual indicator update, ie else clause below prev_chunk.clicks = int(new) next_chunk.clicks = 0 else: update_data('chunk',int(old),int(new)) print("UPDATE", old, new) except Exception as e: print(type(e),e, old, new) chunkations.on_change('value', chunkation_update) chunk_indicator.on_change('value', chunk_indicator_update) next_chunk.on_click(chunk_func) prev_chunk.on_click(chunk_func) update_data(None,None,None) return vplot(control_box, figs)
class DynamicPlotHandler(Handler): def __init__(self, network): self._network = weakref.ref(network) self.sources = {} self._last_time_list = None self._update_complete = False self._recurring_update = RecurringTask(self.plan_update_data, delay=5) self._pcb = None # Periodic callback self._ntcb = None # Next Tick callback super().__init__() @property def network(self): return self._network() def organize_data(self): self._log.debug("Organize Data") self.s = {} for point in self.network.trends: self.s[point.history.name] = (point.history, point.history.units) self.lst_of_trends = [his[0] for name, his in self.s.items()] def build_data_sources(self): sources = {} self.organize_data() for each in self.lst_of_trends: df = pd.DataFrame(each) df = df.reset_index() df["name"] = each.name df["units"] = str(each.units) df["time_s"] = df["index"].apply(str) df.states = each.states try: df = ( df.fillna(method="ffill") .fillna(method="bfill") .replace(["inactive", "active"], [0, 1]) ) except TypeError: df = df.fillna(method="ffill").fillna(method="bfill") sources[each.name] = ColumnDataSource( data=dict( x=df["index"], y=df[each.name], time=df["time_s"], name=df["name"], units=df["units"], ) ) return sources def build_plot(self): self._log.debug("Build Plot") self.stop_update_data() self.sources = self.build_data_sources() 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="BAC0 Trends", tools=TOOLS, plot_width=800, plot_height=600, toolbar_location="above", ) self.p.background_fill_color = "#f4f3ef" self.p.border_fill_color = "#f4f3ef" 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" ) hover = HoverTool( tooltips=[ ("name", "@name"), ("value", "@y"), ("units", "@units"), ("time", "@time"), ] ) self.p.add_tools(hover) length = len(self.s.keys()) if length <= 10: if length < 3: length = 3 color_mapper = dict(zip(self.s.keys(), d3["Category10"][length])) else: # This would be a very loaded trend... color_mapper = dict(zip(self.s.keys(), Spectral6[:length])) for each in self.lst_of_trends: if each.states == "binary": self.p.circle( "x", "y", source=self.sources[each.name], name=each.name, color=color_mapper[each.name], legend=("%s | %s (OFF-ON)" % (each.name, each.description)), y_range_name="bool", size=10, ) elif each.states == "multistates": self.p.diamond( "x", "y", source=self.sources[each.name], name=each.name, color=color_mapper[each.name], legend=("%s | %s (%s)" % (each.name, each.description, each.units)), y_range_name="enum", size=20, ) else: self.p.line( "x", "y", source=self.sources[each.name], name=each.name, color=color_mapper[each.name], legend=("%s | %s (%s)" % (each.name, each.description, each.units)), line_width=2, ) self.p.legend.location = "bottom_right" self.p.legend.click_policy = "hide" self.plots = [self.p] def update_data(self): self._log.debug("Update Data") doc = curdoc() # self.organize_data() if self._last_time_list: if self._last_time_list != self.s.keys(): self._list_have_changed = True self.stop_update_data() # doc.add_next_tick_callback(self.modify_document) self.modify_document(doc) else: self._list_have_changed = False l = [] for each in self.p.renderers: l.append(each.name) # for each in self.lst_of_trends: # df = pd.DataFrame(each) # df = df.reset_index() # df['name'] = each.name # df['units'] = str(each.units) # df['time_s'] = df['index'].apply(str) # try: # df = df.fillna(method='ffill').fillna( # method='bfill').replace(['inactive', 'active'], [0, 1]) # except TypeError: # df = df.fillna(method='ffill').fillna(method='bfill') index = l.index(each.name) # renderer = self.p.renderers[index] # new_data = {} # new_data['name'] = df['name'] # new_data['x'] = df['index'] # new_data['y'] = df[each.name] # if each.states == 'binary': # new_data['units'] = [each.units[int(x)] for x in df[each.name]] # elif each.states == 'multistates': # new_data['units'] = [ # each.units[int(math.fabs(x-1))] for x in df[each.name]] # else: # new_data['units'] = df['units'] # new_data['time'] = df['time_s'] # renderer.data_source.data = new_data try: new_data = self.build_data_sources() for each in self.lst_of_trends: self.sources[each.name].data = new_data[each.name].data except KeyError: self._log.warning( "Problem updating {} on chart, will try again next time.".format( each.name ) ) else: self._last_time_list = self.s.keys() # self.start_update_data() self._update_complete = True def modify_document(self, doc): curdoc().clear() # doc = curdoc() try: curdoc().remove_periodic_callback(self._pcb) except: pass doc.clear() self.build_plot() layout = gridplot(self.plots, ncols=2) doc.add_root(layout) self._pcb = doc.add_periodic_callback(self.update_data, 10000) return doc def plan_update_data(self): doc = curdoc() if self._update_complete == True: self._update_complete = False self._ntcb = doc.add_next_tick_callback(self.update_data) def stop_update_data(self): doc = curdoc() if self._recurring_update.is_running: self._recurring_update.stop() while self._recurring_update.is_running: pass try: doc.remove_next_tick_callback(self._ntcb) except (ValueError, RuntimeError): pass # Already gone def start_update_data(self): if not self._recurring_update.is_running: try: self._recurring_update.start() while not self._recurring_update.is_running: pass except RuntimeError: pass
# overlay volume level chart to salinity tc = "MediumBlue" # tide color tide_range = Range1d(start=0, end=15) tide_axis = LinearAxis(y_range_name="Z") tide_axis.axis_label = "Tidal Height (m)" tide_axis.axis_label_text_color = tc tide_axis.axis_label_text_font_size = label_fontsize tide_axis.major_tick_line_color = tc tide_axis.major_label_text_color = tc tide_axis.minor_tick_line_alpha = 0. top.extra_y_ranges = {"Z": tide_range} # top.line('day', 'Z', source=source, # line_color=tc, line_width=2, line_cap='round') top.add_layout(tide_axis, "right") top.line('day', 'Z', source=source, line_color=tc, line_width=2, line_cap='round', y_range_name="Z") mid = Figure(title=None, x_range=top.x_range, toolbar_location=None, **figure_style_kws) mid.line('day', 'N', source=source, line_color=colors[1], line_width=3, line_cap='round') mid.y_range = Range1d(0., 200.) mid.yaxis.axis_label = "Nitrate (µmol/L)" mid.xaxis.axis_label_text_font_size = label_fontsize mid.yaxis.axis_label_text_font_size = label_fontsize bot = Figure(title=None, x_range=top.x_range,
# %% # COLOR BAR cb = bokeh.models.ColorBar( color_mapper=cm['transform'], width=30, location=(0, 0), # title="DEN (N/km^2)", title="MAS-CC%", # margin=0,padding=0, title_standoff=10, # ticker=bokeh.models.LogTicker() ) cart_fig.add_layout(cb, 'left') # layout = row(column(slider, cart_f),map_f) layout = bokeh.layouts.gridplot([[slider, None], [cart_fig, map_fig]], merge_tools=False) # layout = bokeh.layouts.column([slider, cart_fig]) cart_fig.x_range.start = -75 cart_fig.x_range.end = -50 cart_fig.y_range.start = -25 cart_fig.y_range.end = -5 _ll = ebu.lola_to_cart(lo=[-75, -50], la=[-25, -5]) map_fig.x_range.start = _ll[0][0] map_fig.x_range.end = _ll[0][1] map_fig.y_range.start = _ll[1][0]
hover_line_color='red') taptool = p.select(type=TapTool) taptool.callback = OpenURL(url=url) ## px.circle('x1','y1', source = source_comp, radius = 0.015, ## fill_color = 'lightgray', line_color='black', line_width=0.3) # bokeh.pydata.org/en/latest/docs/reference/models/annotations.html xcolor_bar = ColorBar(color_mapper=mapper, label_standoff=-13, major_label_text_font_style="bold", padding=26, major_label_text_align='right', major_label_text_font_size="10pt", location=(0, 0)) p.add_layout(xcolor_bar, 'left') #infos info, nlines = write_info('skypeak', tests['skypeak']) txt = PreText(text=info, height=nlines * 20, width=p.plot_width) info_col = Div(text=write_description('skypeak'), width=p.plot_width) p2txt = column(widgetbox(info_col), p) layout = gridplot([[p2txt]]) # End of Bokeh Block curdoc().add_root(layout) curdoc().title = "SKYPEAK"
def plot_carto_single(self, data, frente, palette, path=FILE_OUT, name_file="", low=0, high=100, show_plot=True): """ :param data: df loaded by data_load :param frente: string, name of "partido" lowercase: diff, mas, cc, creemos, fpv, pan_bol :param palette: ej: P_GRAD_CC :param name_file: default:test :param low: cmap low limit: default: -80 :param high: cmap high limit: defauilt: +80. :param path: file out :return: df """ da_col = ['HAB','PAIS','MUN','REC','X','Y','LAT','LON','x','y', 'r','r2','GX','GY' ] cart_init_val = self.CART_SLIDER_INIT # add slider self.process_data(cart_init_val, data) if frente == "diff": low = self.C_BAR_LOW high = self.C_BAR_HIGH frente = "d_mas_cc" f1 = 'mas_o_cc' f2 = 'ad_mas_cc' _p = 'mas' _p1 = 'cc' da_col.append(frente) da_col.append(f1) da_col.append(f2) da_col.append(_p) da_col.append(_p1) if frente == "d_mas_creemos": low = self.C_BAR_LOW high = self.C_BAR_HIGH f1 = 'mas_o_creemos' f2 = 'ad_mas_creemos' da_col.append(frente) da_col.append(f1) da_col.append(f2) da_col.append('mas') da_col.append('creemos') da_col.append(frente) cm = linear_cmap(frente, palette=palette, low=low, high=high) data = data[da_col] source_master = ColumnDataSource(data) source_red_map = ColumnDataSource({'gx': [], 'gy': []}) # la, lo = ebu.get_la_lo_bolivia() # source_bol = ColumnDataSource({'la': la, 'lo': lo}) # source_red_car = ColumnDataSource({'lo': [], 'la': []}) # JS CODE code_draw_red_map = """ const data = {'gx': [], 'gy': []} const indices = cb_data.index.indices for (var i = 0; i < indices.length; i++ ) { data['gx'].push(source_master.data.GX[indices[i]]) data['gy'].push(source_master.data.GY[indices[i]]) } source_red_map.data = data """ code_slider = """ var data = source.data; var f = cb_obj.value var x = data['x'] var y = data['y'] var Y = data['Y'] var X = data['X'] var lat = data['LAT'] var lon = data['LON'] for (var i = 0; i < x.length; i++) { y[i] = (1-f)*lat[i] + f*Y[i] x[i] = (1-f)*lon[i] + f*X[i] } source.change.emit(); """ # FIGURES curr_time = ebu.get_bolivian_time(-3) pw = self.FIG_WIDTH callback_red_map = CustomJS( args={'source_master': source_master, 'source_red_map': source_red_map, }, code=code_draw_red_map) hover_cart = bokeh.models.HoverTool( tooltips=self.TOOL_TIP_DIC[frente], callback=callback_red_map, # renderers = [red_scat_car] ) cart_fig = Figure(plot_width=pw, plot_height=pw, output_backend="webgl", ) cart_fig.background_fill_color = "grey" cart_fig.background_fill_alpha = .5 cart_fig.scatter('x', 'y', source=source_master, radius='r', color=cm) cart_fig.add_tools(hover_cart, ) title = "Última actualización: " + curr_time["datetime_val"].strftime( "%Y-%m-%d %H:%M") + "BOT" map_fig = Figure(plot_width=pw, plot_height=pw, x_axis_type='mercator', y_axis_type='mercator', output_backend="webgl", title=title, ) # cb_fig = bokeh.plotting.Figure(plot_height=pw,plot_width=) # cb_fig.toolbar.logo = None # cb_fig.toolbar_location = None # SCATTER # noinspection PyUnresolvedReferences # add tiles tile_provider = bokeh.tile_providers.get_provider( bokeh.tile_providers.Vendors.CARTODBPOSITRON) map_fig.add_tile(tile_provider) # scatter in map map_fig.scatter( 'GX', 'GY', source=source_master, size='r2', color=cm ) # todo if we wont use map then we nee to delete the source # cart_fig.line('lo', 'la', source=source_bol, color='black') # noinspection PyUnusedLocal red_scat_map = map_fig.circle_cross('gx', 'gy', source=source_red_map, fill_color=None, size=20, line_color="white", line_width=4 ) # noinspection PyUnusedLocal red_scat_map = map_fig.circle_cross('gx', 'gy', source=source_red_map, fill_color=None, size=20, line_color="red", line_width=1 ) # red_scat_car = cart_fig.scatter('lo', 'la', # source=source_red_car, color='green') # add a hover tool that sets the link data for a hovered circle # callbacks # code = code_merged) # callback_red_car = CustomJS( # args={'source_master': source_master, 'source_red_car': source_red_car}, # code=code_draw_red_car) # tools hover_map = bokeh.models.HoverTool( tooltips=self.TOOL_TIP_DIC[frente], # callback=callback_red_car, # renderers = [red_scat_map] ) map_fig.add_tools(hover_map, ) # slider callback_slider = CustomJS(args=dict(source=source_master), code=code_slider) slider = Slider(start=0, end=1, value=cart_init_val, step=.02, title="carto") slider.js_on_change('value', callback_slider) # COLOR BAR ml = {int(i): str(np.abs(i)) for i in np.arange(-80, 81, 20)} cb = bokeh.models.ColorBar( color_mapper=cm['transform'], # width=int(.9 * 450), width='auto', location=(0, 0), # title="DEN (N/km^2)", # title=(BAR_TITLE), # margin=0,padding=0, title_standoff=10, # ticker=bokeh.models.LogTicker(), orientation='horizontal', major_label_overrides=ml ) cart_fig.add_layout(cb, 'above') # cb.title_text_align = 'left' cart_fig.title.text = self.BAR_TITLE_DIC[frente] cart_fig.title.align = 'center' # layout = row(column(slider, cart_f),map_f) layout = bokeh.layouts.gridplot( [[slider, None], [cart_fig, map_fig]], sizing_mode='scale_width', merge_tools=False) layout.max_width = 1400 # layout = bokeh.layouts.column([slider, cart_fig]) cart_fig.x_range.start = self.CXS cart_fig.x_range.end = self.CXE cart_fig.y_range.start = self.CYS cart_fig.y_range.end = self.CYE _ll = ebu.lola_to_cart(lo=[self.MXS, self.MXE], la=[self.MYS, self.MYE]) map_fig.x_range.start = _ll[0][0] map_fig.x_range.end = _ll[0][1] map_fig.y_range.start = _ll[1][0] map_fig.y_range.end = _ll[1][1] cart_fig.xaxis.major_tick_line_color = None # turn off x-axis major ticks cart_fig.xaxis.minor_tick_line_color = None # turn off x-axis minor ticks cart_fig.yaxis.major_tick_line_color = None # turn off y-axis major ticks cart_fig.yaxis.minor_tick_line_color = None cart_fig.xaxis.major_label_text_font_size = '0pt' # turn off x-axis tick labels cart_fig.yaxis.major_label_text_font_size = '0pt' # turn off y-axis tick labels nam = 'z037_' + frente + '_' + name_file + '.html' nam_lat = 'z037_' + frente + '_' + 'latest' + '.html' nam1 = os.path.join(path, nam) nam2 = os.path.join(os.path.dirname(ebu.DIR), 'docs', 'graficas_htmls', nam_lat) # bokeh.plotting.output_file(nam2) if show_plot: bokeh.plotting.show(layout) bokeh.plotting.save(layout, nam1) bokeh.plotting.save(layout, nam2) return data
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']