def add_legend(fig, labels, colors): """ Add a legend to a figure given legend labels & colors. Parameters ---------- fig : Bokeh Figure instance Figure instance labels should be generated for. labels : list of str Labels to use as legend entries. colors : Bokeh Palette instance Palette instance containing colours of choice. """ from bokeh.models import Legend # add labels to figure (workaround, # legend with geojsondatasource doesn't work, # see https://github.com/bokeh/bokeh/issues/5904) items = [] for label, color in zip(labels, colors): patch = fig.patches(xs=[], ys=[], fill_color=color) items.append((label, [patch])) legend = Legend(items=items, location='top_left', margin=0, orientation='horizontal') # possibility to define glyph_width=10, glyph_height=10) legend.label_text_font_size = '8pt' fig.add_layout(legend, 'below') return legend
def plot_legend(self, legend_items=None): """Add a legend to the plot. """ if self._use_legend: from bokeh.models import Legend loc = {'best': 'top_left'}.get(self.legend_loc, self.legend_loc) where = {None: 'right'}.get(self.legend_where, self.legend_where) # might be manually specified, e.g. from multiplot if legend_items is None: legend_items = self._lgnd_items lg = Legend(items=legend_items) lg.location = loc lg.click_policy = 'hide' self._plot.add_layout(lg, where) # Don't repeatedly redraw legend self._use_legend = False
## plot-boundaries displacement_range = Range1d(-40,40) force_range = Range1d(-1.2,1.2) time_range = Range1d(0,20) ##displacement-time diagram displacementTime_plot = figure(title="",tools=["ywheel_zoom,xwheel_pan,pan,reset"],width = 400,height= 300,x_range = time_range, y_range = displacement_range) displacementTime_plot.axis.axis_label_text_font_size="12pt" displacementTime_plot.axis.axis_label_text_font_style="normal" displacementTime_plot.yaxis.axis_label="Normalized Displacement u/(F/k₁)" line_1 = displacementTime_plot.line(x='x',y='y', source = mainMass_displacementTime_source, color='#e37222') line_2 = displacementTime_plot.line(x='x',y='y', source = topMass_displacementTime_source, color='#3070b3') displacementTime_plot.toolbar.logo = None legend = Legend(items=[(legend_text[0],[line_1]),(legend_text[1],[line_2])], location='top_right') displacementTime_plot.add_layout(legend) ##force-time diagram forceTime_plot = figure(title="",tools=["ywheel_zoom,xwheel_pan,pan,reset"],width = 400,height= 300,x_range = time_range, y_range = force_range) forceTime_plot.axis.axis_label_text_font_size="12pt" forceTime_plot.axis.axis_label_text_font_style="normal" forceTime_plot.xaxis.axis_label="Time [s]" forceTime_plot.yaxis.axis_label="Force [N]" forceTime_plot.line(x='x',y='y', source = forceTime_source, color='black') forceTime_plot.toolbar.logo = None ################################################################################ #Add application describtion
def _display_timeline_dict(data: dict, **kwargs) -> figure: # noqa: C901, MC0001 """ Display a timeline of events. Parameters ---------- data : dict Data points to plot on the timeline. Need to contain: Key - Name of data type to be displayed in legend Value - dict of data containing: data : pd.DataFrame Data to plot time_column : str Name of the timestamp column source_columns : list List of source columns to use in tooltips color: str Color of datapoints for this data Other Parameters ---------------- ref_time : datetime, optional Input reference line to display (the default is None) title : str, optional Title to display (the default is None) time_column : str, optional Name of the timestamp column (the default is 'TimeGenerated') legend: str, optional Where to position the legend None, left, right or inline (default is None) yaxis : bool, optional Whether to show the yaxis and labels range_tool : bool, optional Show the the range slider tool (default is True) source_columns : list, optional List of default source columns to use in tooltips (the default is None) height : int, optional The height of the plot figure (the default is auto-calculated height) width : int, optional The width of the plot figure (the default is 900) Returns ------- figure The bokeh plot figure. """ reset_output() output_notebook() height: int = kwargs.pop("height", None) width: int = kwargs.pop("width", 900) ref_time: Any = kwargs.pop("ref_time", None) ref_label: str = kwargs.pop("ref_label", None) title: str = kwargs.pop("title", None) legend_pos: str = kwargs.pop("legend", None) show_yaxis: bool = kwargs.pop("yaxis", False) show_range: bool = kwargs.pop("range_tool", True) xgrid: bool = kwargs.pop("xgrid", True) ygrid: bool = kwargs.pop("ygrid", False) tool_tip_columns, min_time, max_time = _unpack_data_series_dict( data, **kwargs) series_count = len(data) # build the tool tips from all specified columns tool_tip_items = [(f"{col}", f"@{col}") for col in tool_tip_columns] hover = HoverTool(tooltips=tool_tip_items, formatters={"Tooltip": "printf"}) title = f"Timeline: {title}" if title else "Event Timeline" start_range = min_time - ((max_time - min_time) * 0.1) end_range = max_time + ((max_time - min_time) * 0.1) height = height if height else _calc_auto_plot_height(len(data)) y_range = ((-1 / series_count), series_count - 1 + (1 / series_count)) plot = figure( x_range=(start_range, end_range), y_range=y_range, min_border_left=50, plot_height=height, plot_width=width, x_axis_label="Event Time", x_axis_type="datetime", x_minor_ticks=10, tools=[hover, "xwheel_zoom", "box_zoom", "reset", "save", "xpan"], title=title, ) plot.yaxis.visible = show_yaxis if show_yaxis: if data: y_labels = { ser_def["y_index"]: str(lbl) for lbl, ser_def in data.items() } plot.yaxis.major_label_overrides = y_labels if ygrid: plot.ygrid.minor_grid_line_color = "navy" plot.ygrid.minor_grid_line_alpha = 0.1 plot.ygrid.grid_line_color = "navy" plot.ygrid.grid_line_alpha = 0.3 else: plot.ygrid.grid_line_color = None if xgrid: plot.xgrid.minor_grid_line_color = "navy" plot.xgrid.minor_grid_line_alpha = 0.3 else: plot.xgrid.grid_line_color = None # Create plot bar to act as as range selector rng_select = _create_range_tool( data=data, min_time=min_time, max_time=max_time, plot_range=plot.x_range, width=width, height=height, ) # set the tick datetime formatter plot.xaxis[0].formatter = _get_tick_formatter() if series_count > 1 and not legend_pos: legend_pos = "left" # plot groups individually so that we can create an interactive legend # if legend_pos is "inline", we add add the normal legend inside the plot # if legend_pos is "left" or "right", we add the legend to the side legend_items = [] for ser_name, series_def in data.items(): inline_legend = ser_name if legend_pos == "inline" else None p_series = plot.diamond( x=series_def["time_column"], y="y_index", color=series_def["color"], alpha=0.5, size=10, source=series_def["source"], legend=inline_legend, ) if legend_pos in ["left", "right"]: legend_items.append((str(ser_name), [p_series])) if legend_pos == "inline": # Position the inline legend plot.legend.location = "center_left" plot.legend.click_policy = "hide" elif legend_pos in ["left", "right"]: # Create the legend box outside of the plot area ext_legend = Legend( items=legend_items, location="center", click_policy="hide", label_text_font_size="8pt", ) plot.add_layout(ext_legend, legend_pos) if ref_time is not None: _add_ref_line(plot, ref_time, ref_label, len(data)) if show_range: show(column(plot, rng_select)) else: show(plot) return plot
def plotspectra(spectra, zcatalog=None, model=None, notebook=False, title=None): ''' TODO: document ''' if notebook: bk.output_notebook() #- If inputs are frames, convert to a spectra object if isinstance(spectra, list) and isinstance(spectra[0], desispec.frame.Frame): spectra = frames2spectra(spectra) frame_input = True else: frame_input = False if frame_input and title is None: meta = spectra.meta title = 'Night {} ExpID {} Spectrograph {}'.format( meta['NIGHT'], meta['EXPID'], meta['CAMERA'][1], ) #- Gather spectra into ColumnDataSource objects for Bokeh nspec = spectra.num_spectra() cds_spectra = list() for band in spectra.bands: #- Set masked bins to NaN so that Bokeh won't plot them bad = (spectra.ivar[band] == 0.0) | (spectra.mask[band] != 0) spectra.flux[band][bad] = np.nan cdsdata = dict( origwave=spectra.wave[band].copy(), plotwave=spectra.wave[band].copy(), ) for i in range(nspec): key = 'origflux' + str(i) cdsdata[key] = spectra.flux[band][i] cdsdata['plotflux'] = cdsdata['origflux0'] cds_spectra.append(bk.ColumnDataSource(cdsdata, name=band)) #- Reorder zcatalog to match input targets #- TODO: allow more than one zcatalog entry with different ZNUM per targetid targetids = spectra.target_ids() if zcatalog is not None: ii = np.argsort(np.argsort(targetids)) jj = np.argsort(zcatalog['TARGETID']) kk = jj[ii] zcatalog = zcatalog[kk] #- That sequence of argsorts may feel like magic, #- so make sure we got it right assert np.all(zcatalog['TARGETID'] == targetids) assert np.all(zcatalog['TARGETID'] == spectra.fibermap['TARGETID']) #- Also need to re-order input model fluxes if model is not None: mwave, mflux = model model = mwave, mflux[kk] #- Gather models into ColumnDataSource objects, row matched to spectra if model is not None: mwave, mflux = model model_obswave = mwave.copy() model_restwave = mwave.copy() cds_model_data = dict( origwave=mwave.copy(), plotwave=mwave.copy(), plotflux=np.zeros(len(mwave)), ) for i in range(nspec): key = 'origflux' + str(i) cds_model_data[key] = mflux[i] cds_model_data['plotflux'] = cds_model_data['origflux0'] cds_model = bk.ColumnDataSource(cds_model_data) else: cds_model = None #- Subset of zcatalog and fibermap columns into ColumnDataSource target_info = list() for i, row in enumerate(spectra.fibermap): target_bit_names = ' '.join(desi_mask.names(row['DESI_TARGET'])) txt = 'Target {}: {}'.format(row['TARGETID'], target_bit_names) if zcatalog is not None: txt += '<BR/>{} z={:.4f} ± {:.4f} ZWARN={}'.format( zcatalog['SPECTYPE'][i], zcatalog['Z'][i], zcatalog['ZERR'][i], zcatalog['ZWARN'][i], ) target_info.append(txt) cds_targetinfo = bk.ColumnDataSource(dict(target_info=target_info), name='targetinfo') if zcatalog is not None: cds_targetinfo.add(zcatalog['Z'], name='z') plot_width = 800 plot_height = 400 # tools = 'pan,box_zoom,wheel_zoom,undo,redo,reset,save' tools = 'pan,box_zoom,wheel_zoom,reset,save' fig = bk.figure(height=plot_height, width=plot_width, title=title, tools=tools, toolbar_location='above', y_range=(-10, 20)) fig.toolbar.active_drag = fig.tools[1] #- box zoom fig.toolbar.active_scroll = fig.tools[2] #- wheel zoom fig.xaxis.axis_label = 'Wavelength [Å]' fig.yaxis.axis_label = 'Flux' fig.xaxis.axis_label_text_font_style = 'normal' fig.yaxis.axis_label_text_font_style = 'normal' colors = dict(b='#1f77b4', r='#d62728', z='maroon') data_lines = list() for spec in cds_spectra: lx = fig.line('plotwave', 'plotflux', source=spec, line_color=colors[spec.name]) data_lines.append(lx) if cds_model is not None: model_lines = list() lx = fig.line('plotwave', 'plotflux', source=cds_model, line_color='black') model_lines.append(lx) legend = Legend(items=[ ("data", data_lines[-1::-1]), #- reversed to get blue as lengend entry ("model", model_lines), ]) else: legend = Legend(items=[ ("data", data_lines[-1::-1]), #- reversed to get blue as lengend entry ]) fig.add_layout(legend, 'center') fig.legend.click_policy = 'hide' #- or 'mute' #- Zoom figure around mouse hover of main plot zoomfig = bk.figure( height=plot_height // 2, width=plot_height // 2, y_range=fig.y_range, x_range=(5000, 5100), # output_backend="webgl", toolbar_location=None, tools=[]) for spec in cds_spectra: zoomfig.line('plotwave', 'plotflux', source=spec, line_color=colors[spec.name], line_width=1, line_alpha=1.0) if cds_model is not None: zoomfig.line('plotwave', 'plotflux', source=cds_model, line_color='black') #- Callback to update zoom window x-range zoom_callback = CustomJS(args=dict(zoomfig=zoomfig), code=""" zoomfig.x_range.start = cb_obj.x - 100; zoomfig.x_range.end = cb_obj.x + 100; """) fig.js_on_event(bokeh.events.MouseMove, zoom_callback) #----- #- Emission and absorption lines z = zcatalog['Z'][0] if (zcatalog is not None) else 0.0 line_data, lines, line_labels = add_lines(fig, z=z) #----- #- Add widgets for controling plots z1 = np.floor(z * 100) / 100 dz = z - z1 zslider = Slider(start=0.0, end=4.0, value=z1, step=0.01, title='Redshift') dzslider = Slider(start=0.0, end=0.01, value=dz, step=0.0001, title='+ Delta redshift') dzslider.format = "0[.]0000" #- Observer vs. Rest frame wavelengths waveframe_buttons = RadioButtonGroup(labels=["Obs", "Rest"], active=0) ifiberslider = Slider(start=0, end=nspec - 1, value=0, step=1) if frame_input: ifiberslider.title = 'Fiber' else: ifiberslider.title = 'Target' zslider_callback = CustomJS( args=dict( spectra=cds_spectra, model=cds_model, targetinfo=cds_targetinfo, ifiberslider=ifiberslider, zslider=zslider, dzslider=dzslider, waveframe_buttons=waveframe_buttons, line_data=line_data, lines=lines, line_labels=line_labels, fig=fig, ), #- TODO: reorder to reduce duplicated code code=""" var z = zslider.value + dzslider.value var line_restwave = line_data.data['restwave'] var ifiber = ifiberslider.value var zfit = 0.0 if(targetinfo.data['z'] != undefined) { zfit = targetinfo.data['z'][ifiber] } // Observer Frame if(waveframe_buttons.active == 0) { var x = 0.0 for(var i=0; i<line_restwave.length; i++) { x = line_restwave[i] * (1+z) lines[i].location = x line_labels[i].x = x } for(var i=0; i<spectra.length; i++) { var data = spectra[i].data var origwave = data['origwave'] var plotwave = data['plotwave'] for (var j=0; j<plotwave.length; j++) { plotwave[j] = origwave[j] } spectra[i].change.emit() } // Update model wavelength array if(model) { var origwave = model.data['origwave'] var plotwave = model.data['plotwave'] for(var i=0; i<plotwave.length; i++) { plotwave[i] = origwave[i] * (1+z) / (1+zfit) } model.change.emit() } // Rest Frame } else { for(i=0; i<line_restwave.length; i++) { lines[i].location = line_restwave[i] line_labels[i].x = line_restwave[i] } for (var i=0; i<spectra.length; i++) { var data = spectra[i].data var origwave = data['origwave'] var plotwave = data['plotwave'] for (var j=0; j<plotwave.length; j++) { plotwave[j] = origwave[j] / (1+z) } spectra[i].change.emit() } // Update model wavelength array if(model) { var origwave = model.data['origwave'] var plotwave = model.data['plotwave'] for(var i=0; i<plotwave.length; i++) { plotwave[i] = origwave[i] / (1+zfit) } model.change.emit() } } """) zslider.js_on_change('value', zslider_callback) dzslider.js_on_change('value', zslider_callback) waveframe_buttons.js_on_click(zslider_callback) plotrange_callback = CustomJS(args=dict( zslider=zslider, dzslider=dzslider, waveframe_buttons=waveframe_buttons, fig=fig, ), code=""" var z = zslider.value + dzslider.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) } """) waveframe_buttons.js_on_click(plotrange_callback) smootherslider = Slider(start=0, end=31, value=0, step=1.0, title='Gaussian Sigma Smooth') target_info_div = Div(text=target_info[0]) #----- #- Toggle lines lines_button_group = CheckboxButtonGroup(labels=["Emission", "Absorption"], active=[]) lines_callback = CustomJS(args=dict(line_data=line_data, lines=lines, line_labels=line_labels), code=""" var show_emission = false var show_absorption = false if (cb_obj.active.indexOf(0) >= 0) { // index 0=Emission in active list show_emission = true } if (cb_obj.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['emission'][i]) { lines[i].visible = show_emission line_labels[i].visible = show_emission } else { lines[i].visible = show_absorption line_labels[i].visible = show_absorption } } """) lines_button_group.js_on_click(lines_callback) # lines_button_group.js_on_change('value', lines_callback) #----- update_plot = CustomJS(args=dict( spectra=cds_spectra, model=cds_model, targetinfo=cds_targetinfo, target_info_div=target_info_div, ifiberslider=ifiberslider, smootherslider=smootherslider, zslider=zslider, dzslider=dzslider, lines_button_group=lines_button_group, fig=fig, ), code=""" var ifiber = ifiberslider.value var nsmooth = smootherslider.value target_info_div.text = targetinfo.data['target_info'][ifiber] if(targetinfo.data['z'] != undefined) { var z = targetinfo.data['z'][ifiber] var z1 = Math.floor(z*100) / 100 zslider.value = z1 dzslider.value = (z - z1) } function get_y_minmax(pmin, pmax, data) { // copy before sorting to not impact original, and filter out NaN var dx = data.slice().filter(Boolean) dx.sort() var imin = Math.floor(pmin * dx.length) var imax = Math.floor(pmax * dx.length) return [dx[imin], dx[imax]] } // Smoothing kernel var kernel = []; for(var i=-2*nsmooth; i<=2*nsmooth; i++) { kernel.push(Math.exp(-(i**2)/(2*nsmooth))) } var kernel_offset = Math.floor(kernel.length/2) // Smooth plot and recalculate ymin/ymax // TODO: add smoother function to reduce duplicated code var ymin = 0.0 var ymax = 0.0 for (var i=0; i<spectra.length; i++) { var data = spectra[i].data var plotflux = data['plotflux'] var origflux = data['origflux'+ifiber] for (var j=0; j<plotflux.length; j++) { if(nsmooth == 0) { plotflux[j] = origflux[j] } else { plotflux[j] = 0.0 var weight = 0.0 // TODO: speed could be improved by moving `if` out of loop for (var k=0; k<kernel.length; k++) { var m = j+k-kernel_offset if((m >= 0) && (m < plotflux.length)) { var fx = origflux[m] if(fx == fx) { plotflux[j] = plotflux[j] + fx * kernel[k] weight += kernel[k] } } } plotflux[j] = plotflux[j] / weight } } spectra[i].change.emit() tmp = get_y_minmax(0.01, 0.99, plotflux) ymin = Math.min(ymin, tmp[0]) ymax = Math.max(ymax, tmp[1]) } // update model if(model) { var plotflux = model.data['plotflux'] var origflux = model.data['origflux'+ifiber] for (var j=0; j<plotflux.length; j++) { if(nsmooth == 0) { plotflux[j] = origflux[j] } else { plotflux[j] = 0.0 var weight = 0.0 // TODO: speed could be improved by moving `if` out of loop for (var k=0; k<kernel.length; k++) { var m = j+k-kernel_offset if((m >= 0) && (m < plotflux.length)) { var fx = origflux[m] if(fx == fx) { plotflux[j] = plotflux[j] + fx * kernel[k] weight += kernel[k] } } } plotflux[j] = plotflux[j] / weight } } model.change.emit() } // update y_range if(ymin<0) { fig.y_range.start = ymin * 1.4 } else { fig.y_range.start = ymin * 0.6 } fig.y_range.end = ymax * 1.4 """) smootherslider.js_on_change('value', update_plot) ifiberslider.js_on_change('value', update_plot) #----- #- Add navigation buttons navigation_button_width = 30 prev_button = Button(label="<", width=navigation_button_width) next_button = Button(label=">", width=navigation_button_width) prev_callback = CustomJS(args=dict(ifiberslider=ifiberslider), code=""" if(ifiberslider.value>0) { ifiberslider.value-- } """) next_callback = CustomJS(args=dict(ifiberslider=ifiberslider, nspec=nspec), code=""" if(ifiberslider.value<nspec+1) { ifiberslider.value++ } """) prev_button.js_on_event('button_click', prev_callback) next_button.js_on_event('button_click', next_callback) #----- slider_width = plot_width - 2 * navigation_button_width navigator = bk.Row( widgetbox(prev_button, width=navigation_button_width), widgetbox(next_button, width=navigation_button_width + 20), widgetbox(ifiberslider, width=slider_width - 20)) bk.show( bk.Column( bk.Row(fig, zoomfig), widgetbox(target_info_div, width=plot_width), navigator, widgetbox(smootherslider, width=plot_width // 2), bk.Row( widgetbox(waveframe_buttons, width=120), widgetbox(zslider, width=plot_width // 2 - 60), widgetbox(dzslider, width=plot_width // 2 - 60), ), widgetbox(lines_button_group), ))
renderers=[glyphs[missions.index(ii)]]) for ii in bottomleg ] items3 = [ LegendItem(label=ii + f' ({counts[missions.index(ii)]})', renderers=[glyphs[missions.index(ii)]]) for ii in vbottomleg ] # create the two legends for ii in np.arange(3): if ii == 0: items = items3 elif ii == 1: items = items2 else: items = items1 legend = Legend(items=items, location="center") if ii == 2: legend.title = 'Discovered by and Status' legend.spacing = 10 else: legend.spacing = 11 legend.location = (-70, 5) legend.label_text_align = 'left' legend.margin = 0 fig.add_layout(legend, 'above') # overall figure title fig.title.text = 'Transiting Planets and Planet Candidates'
def plot_data(df, dsn): '''Plot the data in the given dataframe Parameters: df (dataframe) - data from the given dsn dsn (str) - device identifier ''' names = [ "heart_rate_avg", "oxygen_avg", "skin_temperature", "base_state", "movement_raw" ] colors = ["blue", "orange", "red", "purple", "green"] alphas = [.8, 8, .8, .7, .6] # Where data is stored so it can be displayed and changed dynamically source_data, source_data1, source_data2, source_data3, source_data4, source_data5, min_val, max_hr = get_source( df, names) # Multiple sources because there are different lengths of data source = ColumnDataSource(data=source_data) source1 = ColumnDataSource(data=source_data1) source2 = ColumnDataSource(data=source_data2) source3 = ColumnDataSource(data=source_data3) source4 = ColumnDataSource(data=source_data4) source5 = ColumnDataSource(data=source_data5) # Build plot tools hover_tool = HoverTool( tooltips=[ ('time', '@date{%T}'), ] + [(name, '@{}'.format(name)) for name in names] + [('notification', '@notification_mask')], #data: good; corrupt formatters={ 'date': 'datetime', }, # use default 'numeral' formatter for other fields mode='vline', renderers=[]) crosshair = CrosshairTool(dimensions='height', line_alpha=.6) box_zoom = BoxZoomTool(dimensions='width') zoom_out = ZoomOutTool(dimensions='width', factor=.5) save = CustomSaveTool(save_name=dsn) x_range_start = df.timestamp.min() - timedelta(minutes=30) x_range_end = df.timestamp.max() + timedelta(minutes=30) # Create figure; use webgl for better rendering tools = [save, box_zoom, 'xpan', zoom_out, 'reset', hover_tool, crosshair] p = figure(width=950, height=500, title="{} Data".format(dsn), x_axis_type="datetime", tools=tools, toolbar_location="above", x_range=(x_range_start, x_range_end), y_range=(0, max_hr + (24 * (len(names) + 1))), output_backend='webgl') # To have the Legend outside the plot, each line needs to be added to it legend_it = [] for i in range(len(names)): legend_line = p.line(x=df.timestamp.iloc[-1:], y=0, color=colors[i], alpha=1, line_width=2) if names[i] in ["movement_raw", "base_state"]: legend_it.append((names[i], [ legend_line, p.multi_line(xs='plot_xs', ys='plot_' + names[i], color=colors[i], alpha=alphas[i], source=source1) ])) else: bad_data_line = p.multi_line(xs='bad_x', ys='bad_' + names[i], color=colors[i], alpha=.1, source=source3) legend_it.append((names[i], [ legend_line, p.multi_line(xs='good_x', ys='good_' + names[i], color=colors[i], alpha=alphas[i], source=source2), bad_data_line ])) legend_it.append(("Yellow notifications", [ p.multi_line(xs='yellow', ys='ys', color='#F5BE41', line_dash='dashed', line_width=1.5, source=source4) ])) legend_it.append(("Red notifications", [ p.multi_line(xs='red', ys='red_ys', color='red', line_dash='dashed', source=source5) ])) # legend_it.append(("Red notifications", [p.circle(x='red', y='red_ys', color='red', size=6, source=source5)])) # Creating a location for the tooltip box to appear (so it doesn't cover the data) horizontal_line = p.line(x='date', y='horizontal', color='white', alpha=0, source=source) hover_tool.renderers.append(horizontal_line) p.xaxis.axis_label = 'Time' p.xaxis.formatter = DatetimeTickFormatter(days=["%m/%d %T"], months=["%m/%d %T"], hours=["%m/%d %T"], minutes=["%m/%d %T"], seconds=["%m/%d %T"], minsec=["%m/%d %T"], hourmin=["%m/%d %T"]) legend = Legend(items=legend_it) legend.click_policy = "hide" # Hide lines when they are clicked on p.add_layout(legend, 'right') return p, source, source1, source2, source3, source4, source5
def test_adding_legend_doesnt_work_when_legends_already_added( self, p, source) -> None: p.add_layout(Legend()) p.add_layout(Legend()) with pytest.raises(RuntimeError): p.circle(x='x', y='y', legend='label', source=source)
def generate_spmfp_plot(circuit_years, circuit_races, circuit_results): """ Plot mean of starting position - finish position and num DNFs vs time, with horizontal line showing average :param circuit_years: Circuit years :param circuit_races: Circuit races :param circuit_results: Circuit results :return: SPmFP plot layout """ logging.info("Generating SPMFP plot") source = pd.DataFrame(columns=["year", "msp", "mfp", "mspmfp", "dnf"]) for year in circuit_years: race = circuit_races[circuit_races["year"] == year] rid = race.index.values[0] results = circuit_results[circuit_results["raceId"] == rid] finishing_pos = pd.to_numeric(results["positionText"], errors="coerce") mspmfp = (results["grid"] - finishing_pos).mean() dnf = results.shape[0] - results["positionText"].str.isnumeric().sum() source = source.append({ "year": year, "msp": round(results["grid"].mean(), 1), "mfp": finishing_pos.mean(), "mspmfp": mspmfp, "dnf": dnf }, ignore_index=True) min_year = source["year"].min() max_year = source["year"].max() min_y = min(source["dnf"].min(), source["mspmfp"].min(), 1.5) max_y = max(source["dnf"].max(), source["mspmfp"].max()) if min_year == max_year: min_year -= 1 max_year += 1 spfp_plot = figure( title=u"Average Start Position minus Finish Position \u2014 How many places do drivers make up on average?", x_axis_label="Year", y_axis_label="Average start position minus finish position", x_range=Range1d(min_year, max_year, bounds=(min_year, max_year + 3)), y_range=Range1d(min(min_y - 2, -1), max_y + 2, bounds=(min(min_y - 2, -1), max_y)), tools="pan,xbox_zoom,xwheel_zoom,reset,box_zoom,wheel_zoom,save" ) kwargs = { "x": "year", "source": source, "muted_alpha": 0.05 } mspmfp_line = spfp_plot.line(y="mspmfp", line_width=2, color="white", **kwargs) dnf_line = spfp_plot.line(y="dnf", line_width=1.9, color="orange", line_alpha=0.8, **kwargs) # Mean lines kwargs = { "x": [1950, 2100], "line_alpha": 0.5, "line_width": 2, "line_dash": "dashed", "muted_alpha": 0.08 } mspmfp_mean_line = spfp_plot.line(y=[source["mspmfp"].mean()] * 2, line_color="white", **kwargs) dnf_mean_line = spfp_plot.line(y=[source["dnf"].mean()] * 2, line_color="orange", **kwargs) # Zero line spfp_plot.add_layout(Span(line_color="white", location=0, dimension="width", line_alpha=0.3, line_width=1.5)) # Legend legend_items = [ LegendItem(label="Average Start - Finish Pos.", renderers=[mspmfp_line, mspmfp_mean_line]), LegendItem(label="Number of DNFs", renderers=[dnf_line, dnf_mean_line]), ] legend = Legend(items=legend_items, location="top_right", glyph_height=15, spacing=2, inactive_fill_color="gray") spfp_plot.add_layout(legend, "right") spfp_plot.legend.click_policy = "mute" spfp_plot.legend.label_text_font_size = "12pt" # The default font size # Labels text_label_kwargs = dict(x=min_year + 0.5, render_mode="canvas", text_color="white", text_font_size="12pt", border_line_color="white", border_line_alpha=0.7) label1 = Label(y=-0.9, text=" Finish lower than started ", **text_label_kwargs) label2 = Label(y=0.4, text=" Finish higher than start ", **text_label_kwargs) spfp_plot.add_layout(label1) spfp_plot.add_layout(label2) # Hover tooltip spfp_plot.add_tools(HoverTool(show_arrow=False, tooltips=[ ("Year", "@year"), ("Mean Starting Position", "@msp"), ("Mean Finishing Position", "@mfp"), ("Mean Start minus Finish Position", "@mspmfp"), ("Number of DNFs", "@dnf"), ])) # Crosshair spfp_plot.add_tools(CrosshairTool(line_color="white", line_alpha=0.6)) return spfp_plot
x_axis_type="datetime", title="Geothermal Stocks") l0 = p.line(listings[0].index, listings[0]["Close"], color="greenyellow", alpha=0.5) # HTM l1 = p.line(listings[1].index, listings[1]["Close"], color="red", alpha=0.5) #ORA # l2 = p.line(listings[2].index, listings[2]["Close"] ,color="deepskyblue", alpha=0.5) #CVX most expensive l3 = p.line(listings[3].index, listings[3]["Close"], color="aqua", alpha=0.5) #BRK-A l4 = p.line(listings[4].index, listings[4]["Close"], color="deeppink", alpha=0.5) #ENEL.MI l5 = p.line(listings[5].index, listings[5]["Close"], color="gold", alpha=0.5) #PIF.TO l6 = p.line(listings[6].index, listings[6]["Close"], color="ivory", alpha=0.5) #INE.TO # l7 = p.line(listings[7].index, listings[7]["Close"] ,color="yellow", alpha=0.5) #LXV # p.line(listings[8].index, listings[8]["Close"] ,color="aqua", alpha=0.5) #CLIME-B.ST legend1 = Legend(items=[("HTM", [l0]), ("ORA", [l1]), ("BRK-A", [l3]), ("ENEL.MI", [l4]), ("PIF.TO", [l5]), ("INE.TO", [l6])], location=(70, 20), orientation="horizontal") p.add_layout(legend1, "below") output_file("geostock.html") show(p)
def line( df_in: pd.DataFrame, *args, plot_height: int = 500, plot_width: int = 1400, toolbar_location: str = 'below', legend_location: str = 'right', **kwargs, ) -> figure: """Lineplot in bokeh.""" #df = df.reset_index() df = df_in.copy() if isinstance(df, pd.Series): df = pd.DataFrame(df) df.columns = ['data'] if 'datetime' in df.columns: df = df.drop('datetime', axis=1) df.index.name = None for column in df.columns: if df[column].dtypes == 'object': for index, category in enumerate( df[column].astype('category').cat.categories): print(index, category) df[column] = df[column].astype('category').cat.codes df_cds = ColumnDataSource(df) p = figure( x_axis_type='datetime', plot_height=plot_height, plot_width=plot_width, title='', x_axis_label='timestamp', y_axis_label='value', toolbar_location=toolbar_location, tools="reset,box_zoom", # buggy: # x_range=DataRange1d( # # df.index[0], # # df.index[-1], # bounds=(df.index[0] - dt.timedelta(weeks=52), # df.index[-1] + dt.timedelta(weeks=52)), ), x_range=DataRange1d(bounds='auto'), ) col_num = 0 colors = color(len(df.columns)) legends = [] tooltips = [] for column in df.columns: r = p.line( x='index', y=column, name='value', color=colors[col_num], source=df_cds, ) col_num += 1 legends.append((column, [r])) tooltips.append((column, '@{%s}' % column)) tooltips.append(('index', '@index{%F}')) p.add_tools( HoverTool( tooltips=tooltips, renderers=[r], mode='vline', point_policy='follow_mouse', line_policy='none', formatters={'index': 'datetime'}, )) legend = Legend(items=legends, location=(0, 0)) p.add_tools(CrosshairTool()) wheel_zoom_tool = WheelZoomTool() wheel_zoom_tool.dimensions = 'width' p.add_tools(wheel_zoom_tool) p.toolbar.active_scroll = wheel_zoom_tool pan_tool = PanTool() pan_tool.dimensions = 'width' p.add_tools(pan_tool) p.add_layout(legend, legend_location) p.legend.click_policy = 'hide' show(p) return p
def plot(self, source1, source2, source3, source4, source5, source6, source7, source8, source9): hover = HoverTool(tooltips=[ ("x", "($x)"), ("y", "($y)"), ("NAME", "(@N)"), ]) p = figure(title="TSNE/MACCS Keys FP", x_range=(-7, 7), y_range=(-7, 7), tools=[hover], plot_width=1000, plot_height=800) FDA_plot = p.circle(x="x", y="y", source=source1, color="darkslateblue", size=5) PPI_plot = p.circle(x="x", y="y", source=source2, color="yellowgreen", size=5) MACRO_plot = p.circle(x="x", y="y", source=source3, color="lightsteelblue", size=5) NP_plot = p.circle(x="x", y="y", source=source4, color="olive", size=5) PEP_FDA_plot = p.circle(x="x", y="y", source=source5, color="darkslategray", size=5) LIN_plot = p.circle(x="x", y="y", source=source6, color="aquamarine", size=5) LIN_NM_plot = p.circle(x="x", y="y", source=source7, color="teal", size=5) CYC_plot = p.circle(x="x", y="y", source=source8, color="lightpink", size=5) CYC_NM_plot = p.circle(x="x", y="y", source=source9, color="mediumvioletred", size=5) p.add_tools(LassoSelectTool(), ZoomInTool(), ZoomOutTool(), SaveTool(), PanTool()) legend = Legend(items=[ ("FDA", [FDA_plot]), ("PPI", [PPI_plot]), ("MACRO", [MACRO_plot]), ("NP", [NP_plot]), ("PEP FDA", [PEP_FDA_plot]), ("LIN", [LIN_plot]), ("LIN NM", [LIN_NM_plot]), ("CYC", [CYC_plot]), ("CYC NM", [CYC_NM_plot]), ], location="center", orientation="vertical", click_policy="hide") p.add_layout(legend, place='right') p.xaxis.axis_label_text_font_size = "20pt" p.yaxis.axis_label_text_font_size = "20pt" p.xaxis.axis_label_text_color = "black" p.yaxis.axis_label_text_color = "black" p.xaxis.major_label_text_font_size = "18pt" p.yaxis.major_label_text_font_size = "18pt" p.title.text_font_size = "22pt" return p
from bokeh.plotting import figure, output_file, show from bokeh.sampledata.stocks import AAPL, MSFT def datetime(x): return np.array(x, dtype=np.datetime64) p = figure(background_fill_color="#fafafa", x_axis_type="datetime", plot_width=800, plot_height=350) r = p.multi_line( [datetime(AAPL['date']), datetime(MSFT['date'])], [AAPL['adj_close'], MSFT['adj_close']], color=["navy", "crimson"], line_width=2, alpha=0.6) legend = Legend(items=[ LegendItem(label="AAPL", renderers=[r], index=0), LegendItem(label="MSFT", renderers=[r], index=1), ], location="top_left") p.add_layout(legend) output_file("multi_legend.html") show(p)
def scatterPlots(categories): TITLE = "Several blood chemicals versus Age quantile" figures = [] # list to contain all subplots posneg_list = [] # list to contain all dots in a plot colorPositive = "blue" # color of positively tested colorNegative = "red" # color of negatively tested count = 0 for index in categories: # create subplots for every bloodtype # for the first one don't use x_range, the remaining all will use the same x_range if count != 0: # a seperate plot is made for the first entry scatter = figure(title=index, plot_width=400, plot_height=300, x_range=figures[0].x_range, y_range=figures[0].y_range, tools="save, pan, reset, wheel_zoom, box_select", x_axis_label='age quantile', y_axis_label='standardized test result') else: scatter = figure( # plots for all the other blood values title= index, # ... these are the same but they copy their axis from the first one plot_width=400, plot_height=300, y_range=(-4, 4), tools="save, pan, reset, wheel_zoom, box_select", x_axis_label='age quantile', y_axis_label='standardized test result') # create dot objects for the points in the plots p = scatter.square(x=jitter("Patient age quantile", 0.5), y=index, size=4, color=colorPositive, alpha=0.5, source=sourcePos, muted_alpha=0.1) n = scatter.circle(x=jitter("Patient age quantile", 0.5), y=index, size=4, color=colorNegative, alpha=0.5, source=sourceNeg, muted_alpha=0.1) posneg_list += [p] # add dots to list posneg_list += [n] figures.append(scatter) # add figure to the list of subfigures count += 1 # Lines with the same color will share a same legend item legend_items = [ LegendItem(label="Covid-19 positive", renderers=[ thing for thing in posneg_list if thing.glyph.line_color == colorPositive ]), LegendItem(label="Covid-19 negative", renderers=[ thing for thing in posneg_list if thing.glyph.line_color == colorNegative ]) ] # use a dummy figure for the legend dum_fig = figure(plot_width=300, plot_height=600, outline_line_alpha=0, toolbar_location=None) # set the components of the figure invisible for fig_component in [ dum_fig.grid[0], dum_fig.ygrid[0], dum_fig.xaxis[0], dum_fig.yaxis[0] ]: fig_component.visible = False # The points referred by the legend need to be present in the figure ,so add them to figure renderers dum_fig.renderers += posneg_list # set the figure range outside of the range of all glyphs dum_fig.x_range.end = 1005 dum_fig.x_range.start = 1000 # add the legend dum_fig.add_layout( Legend(click_policy='mute', location='top_left', border_line_alpha=0, items=legend_items)) # copy list to make it later possible to delete/ add items for the list without using original list (NOT YET USED) show_figures = figures splom = gridplot(show_figures, ncols=3, toolbar_location='right') plot = gridplot([[splom, dum_fig]], toolbar_location=None) return plot
plot.add_layout(line_f_glyph) line_t = Line(x="x", y="ty", line_color="red", line_width=2) line_t_glyph = plot.add_glyph(source, line_t) plot.add_layout(line_t_glyph) xaxis = LinearAxis() plot.add_layout(xaxis, 'below') yaxis = LinearAxis() plot.add_layout(yaxis, 'left') xgrid = Grid(dimension=0, ticker=xaxis.ticker) ygrid = Grid(dimension=1, ticker=yaxis.ticker) legend = Legend(orientation="bottom_left") plot.add_layout(legend) def on_slider_value_change(attr, old, new): global order order = int(new) update_data() def on_text_value_change(attr, old, new): try: global expr expr = sy.sympify(new, dict(x=xs)) except (sy.SympifyError, TypeError, ValueError) as exception: dialog.content = str(exception)
plot.add_layout(line_f_glyph) line_t = Line(x="x", y="ty", line_color="red", line_width=2) line_t_glyph = plot.add_glyph(source, line_t) plot.add_layout(line_t_glyph) xaxis = LinearAxis() plot.add_layout(xaxis, 'below') yaxis = LinearAxis() plot.add_layout(yaxis, 'left') xgrid = Grid(dimension=0, ticker=xaxis.ticker) ygrid = Grid(dimension=1, ticker=yaxis.ticker) legend = Legend(location="top_right") legend.items = [ LegendItem(label=value("%s" % expr), renderers=[line_f_glyph]), LegendItem(label=value("taylor(%s)" % expr), renderers=[line_t_glyph]), ] plot.add_layout(legend) def on_slider_value_change(attr, old, new): global order order = int(new) update_data() def on_text_value_change(attr, old, new): global expr try:
plot.add_layout(line_f_glyph) line_t = Line(x="x", y="ty", line_color="red", line_width=2) line_t_glyph = plot.add_glyph(source, line_t) plot.add_layout(line_t_glyph) xaxis = LinearAxis() plot.add_layout(xaxis, 'below') yaxis = LinearAxis() plot.add_layout(yaxis, 'left') xgrid = Grid(dimension=0, ticker=xaxis.ticker) ygrid = Grid(dimension=1, ticker=yaxis.ticker) legend = Legend(location="top_right") plot.add_layout(legend) def on_slider_value_change(attr, old, new): global order order = int(new) update_data() def on_text_value_change(attr, old, new): try: global expr expr = sy.sympify(new, dict(x=xs)) except (sy.SympifyError, TypeError, ValueError) as exception: dialog.content = str(exception)
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", 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
fig.yaxis.formatter = FuncTickFormatter(code=log_axis_labels(max_tick=5)) # add the x-axis's label and use our custom log formatting fig.xaxis.axis_label = 'Period (days)' fig.xaxis.formatter = FuncTickFormatter(code=log_axis_labels(max_tick=5)) # add the second y-axis's label fig.right[0].axis_label = 'Radius (Jupiter Radii)' # set up all the legend objects items = [ LegendItem(label=ii + f' ({counts[missions.index(ii)]})', renderers=[jj]) for ii, jj in zip(missions, glyphs) ] # create the legend legend = Legend(items=items, location="center") legend.title = 'Discovered by' legend.spacing = 10 fig.add_layout(legend, 'above') # overall figure title fig.title.text = 'Confirmed Transiting Planets' # create the three lines of credit text in the two bottom corners label_opts1 = dict(x=-68, y=42, x_units='screen', y_units='screen') label_opts2 = dict(x=-68, y=47, x_units='screen', y_units='screen') label_opts3 = dict(x=627, y=64, x_units='screen',
def create_graph( # noqa: C901 data: pd.DataFrame, unit: str = "Some unit", title: str = "A plot", x_label: str = "X", y_label: str = "Y", legend_location: Union[str, Tuple[float, float]] = "top_right", legend_labels: Tuple[str, Optional[str], Optional[str]] = ( "Actual", "Forecast", "Schedules", ), x_range: Range1d = None, forecasts: pd.DataFrame = None, schedules: pd.DataFrame = None, show_y_floats: bool = False, non_negative_only: bool = False, tools: List[str] = None, sizing_mode="scale_width", ) -> Figure: """ Create a Bokeh graph. As of now, assumes x data is datetimes and y data is numeric. The former is not set in stone. :param data: the actual data. Expects column name "event_value" and optional "belief_horizon" and "source" columns. :param unit: the (physical) unit of the data :param title: Title of the graph :param x_label: x axis label :param y_label: y axis label :param legend_location: location of the legend :param legend_labels: labels for the legend items :param x_range: values for x axis. If None, taken from series index. :param forecasts: forecasts of the data. Expects column names "event_value", "yhat_upper" and "yhat_lower". :param schedules: scheduled data. Expects column name "event_value". :param hover_tool: Bokeh hover tool, if required :param show_y_floats: if True, y axis will show floating numbers (defaults False, will be True if y values are < 2) :param non_negative_only: whether or not the data can only be non-negative :param tools: some tools for the plot, which defaults to ["box_zoom", "reset", "save"]. :return: a Bokeh Figure """ # Replace "source" column with "label" column (containing strings) data = replace_source_with_label(data) forecasts = replace_source_with_label(forecasts) schedules = replace_source_with_label(schedules) resolution = decide_plot_resolution(data) # Set x range if x_range is None: x_range = make_range(data.index) data = tz_index_naively(data) # Set default y range in case there is no data from which to derive a range y_range = None if ( data["event_value"].isnull().all() and (forecasts is None or forecasts["event_value"].isnull().all()) and (schedules is None or schedules["event_value"].isnull().all()) ): y_range = Range1d(start=0, end=1) # Set default tools if none were given if tools is None: tools = ["box_zoom", "reset", "save"] if "belief_horizon" in data.columns and "label" in data.columns: hover_tool = create_hover_tool(unit, resolution, as_beliefs=True) else: hover_tool = create_hover_tool(unit, resolution, as_beliefs=False) tools = [hover_tool] + tools fig = figure( title=title, x_range=x_range, y_range=y_range, min_border=0, toolbar_location="right", tools=tools, h_symmetry=False, v_symmetry=False, sizing_mode=sizing_mode, outline_line_color="#666666", ) if non_negative_only: fig.y_range.bounds = (0, None) fig.y_range.start = 0 if data.empty: current_app.logger.warning("No data to show for %s" % title) # Format y floats if ( not data.empty and show_y_floats is False and data["event_value"].size > 0 ): # apply a simple heuristic if forecasts is None or forecasts.empty: show_y_floats = max(data["event_value"].values) < 2 else: show_y_floats = ( max(max(data["event_value"].values), max(forecasts["event_value"])) < 2 ) palette, forecast_color, schedule_color = build_palette() legend_items: List[Tuple] = [] # Plot power data. Support special case of multiple source labels. if not data.empty: data_groups = {legend_labels[0]: data} is_multiple = "label" in data.columns and len(data["label"].unique()) > 1 if is_multiple: data_groups = { label: data.loc[data.label == label] for label in data["label"].unique() } legend_items = [] for plot_label, plot_data in data_groups.items(): ds = make_datasource_from(plot_data, resolution) if not is_multiple: ac = fig.circle( x="x", y="y", source=ds, color=palette.pop(0), alpha=0.5, size=10 ) else: ac = fig.line(x="x", y="y", source=ds, color=palette.pop(0)) legend_items.append((plot_label, [ac])) # Plot forecast data if forecasts is not None and not forecasts.empty: forecasts = tz_index_naively(forecasts) if "label" not in forecasts: forecasts["label"] = "Forecast from unknown source" labels = forecasts["label"].unique() for label in labels: # forecasts from different data sources label_forecasts = forecasts[forecasts["label"] == label] fds = make_datasource_from(label_forecasts, resolution) fc = fig.circle(x="x", y="y", source=fds, color=forecast_color, size=10) fl = fig.line(x="x", y="y", source=fds, color=forecast_color) # draw uncertainty range as a two-dimensional patch if "yhat_lower" and "yhat_upper" in label_forecasts: x_points = np.append(label_forecasts.index, label_forecasts.index[::-1]) y_points = np.append( label_forecasts.yhat_lower, label_forecasts.yhat_upper[::-1] ) fig.patch( x_points, y_points, color=forecast_color, fill_alpha=0.2, line_width=0.01, ) if legend_labels[1] is None: raise TypeError("Legend label must be of type string, not None.") if label == labels[0]: # only add 1 legend item for forecasts legend_items.append((legend_labels[1], [fc, fl])) # Plot schedule data. Support special case of multiple source labels. if ( schedules is not None and not schedules.empty and not schedules["event_value"].isnull().all() ): schedules = tz_index_naively(schedules) legend_label = "" if legend_labels[2] is None else legend_labels[2] schedule_groups = {legend_label: schedules} if "label" in schedules.columns and len(schedules["label"].unique()) > 1: schedule_groups = { label: schedules.loc[schedules.label == label] for label in schedules["label"].unique() } for plot_label, plot_data in schedule_groups.items(): sds = make_datasource_from(plot_data, resolution) sl = fig.line(x="x", y="y", source=sds, color=palette.pop(0)) if plot_label is None: raise TypeError("Legend label must be of type string, not None.") legend_items.append((plot_label, [sl])) fig.toolbar.logo = None fig.yaxis.axis_label = y_label fig.yaxis.formatter = NumeralTickFormatter(format="0,0") if show_y_floats: fig.yaxis.formatter = NumeralTickFormatter(format="0,0.00") fig.ygrid.grid_line_alpha = 0.5 fig.xaxis.axis_label = x_label fig.xgrid.grid_line_alpha = 0.5 if legend_location is not None: legend = Legend(items=legend_items, location=legend_location) fig.add_layout(legend, "center") return fig
def CreateMetricOneWord(w_i, y_rep, y_dem, sizedot=9, sizefont='28pt', lgnd=False, plotax=False, plotsize=(350, 350), Colors=('goldenrod', '#820872', 'black')): from sklearn.linear_model import LinearRegression from math import ceil import numpy as np from bokeh.models import ColumnDataSource, HoverTool, Label, Legend from bokeh.plotting import figure c1 = Colors[0] c2 = Colors[1] c3 = Colors[2] max_count = max(y_rep + y_dem) y_rep = [j / max_count for j in y_rep] y_dem = [j / max_count for j in y_dem] maxxy = 1.03 #+ 1 minxy = -0.03 x_vector = range(-10, 10) X_rep = np.array(y_rep).reshape(-1, 1) reg = LinearRegression(fit_intercept=False).fit(X=X_rep, y=y_dem) R2 = reg.score(X=X_rep, y=y_dem) slope = reg.coef_[0] neutrality_index = R2, np.exp(R2) * np.tanh(-(slope - 1)) p_1 = figure(plot_width=plotsize[0], plot_height=plotsize[1], title='', x_range=(minxy, maxxy), y_range=(minxy, maxxy), tools='') center_xy = (maxxy + minxy) / 2 label_i = Label(x=center_xy, y=center_xy, text=w_i, text_font_size=sizefont, border_line_color=None, border_line_alpha=1.0, text_font_style='bold', background_fill_color=None, background_fill_alpha=1.0, text_color='black', text_baseline='middle', text_align='center', text_alpha=1, level='underlay') p_1.add_layout(label_i) ref_line = p_1.line(y=x_vector, x=x_vector, color=c2, alpha=1, line_width=1.6, line_dash='dashed') slope_line = p_1.line(x=x_vector, y=[slope * x for x in x_vector], color=c2, alpha=1, line_width=1.8, line_dash='solid') r = p_1.scatter(x=y_rep, y=y_dem, color=c1, alpha=1, size=sizedot, line_color=c3) if (lgnd): legend = Legend(items=[('Monthly mentions of "china" in (*)', [r]), ('Reference line', [ref_line]), ('Slope line', [slope_line])]) legend.click_policy = "mute" legend.border_line_width = 0 legend.label_text_font_size = '16pt' p_1.add_layout(legend, 'right') # Adjusting plot parameters #p.x_range.range_padding = 0.05 p_1.xaxis.axis_label = "(*) r/republican" p_1.yaxis.axis_label = "(*) r/democrats" p_1.xaxis.visible = plotax p_1.yaxis.visible = plotax p_1.yaxis.axis_line_width = 1 p_1.yaxis.ticker = [] p_1.xaxis.axis_line_width = 1 p_1.xaxis.ticker = [] p_1.axis.axis_label_text_font_size = '16pt' p_1.axis.axis_label_text_font_style = 'normal' p_1.axis.axis_label_text_color = 'black' p_1.axis.axis_line_width = 1.5 p_1.grid.visible = False p_1.background_fill_color = 'white' p_1.background_fill_alpha = 1 p_1.outline_line_color = 'black' p_1.border_fill_color = None p_1.background_fill_color = "seashell" p_1.sizing_mode = 'scale_width' return (p_1, neutrality_index)
height=350, title="US Population Age for each year", toolbar_location="right", tools="hover,tap, save", tooltips="$name: @$name") v = p.vbar_stack(age, x='Year', width=0.9, color=colors, source=read_data) p.y_range.start = 0 p.yaxis[0].axis_label = 'Population (%)' p.x_range.range_padding = 0.1 p.xaxis.major_label_orientation = 1 p.xgrid.grid_line_color = None p.axis.minor_tick_line_color = None p.outline_line_color = None # p.legend.location = "top_right" # p.legend.orientation = "vertical" legend = Legend(items=[ ("Under 5", [v[0]]), ("5 to 19", [v[1]]), ("20 to 44", [v[2]]), ("45 to 64", [v[3]]), ("65+", [v[4]]), ], location=(0, 100)) p.add_layout(legend, 'right') show(p)
'y': [ df_sleep['x'].min() * (slope) + intercept, df_sleep['x'].max() * (slope) + intercept ] }) plot_sleep_scatter.line( x='x', y='y', color='#154ba6', line_width=3, #line_dash="8 4", alpha=0.90, source=regline_cds, legend_label='reg') legend = Legend() plot_sleep_scatter.add_layout(legend, 'center') plot_sleep_scatter.legend.orientation = 'vertical' plot_sleep_scatter.legend.location = 'bottom_left' plot_sleep_scatter.legend.click_policy = 'hide' plot_sleep_scatter.legend.background_fill_alpha = 0.5 plot_sleep_scatter.legend.border_line_alpha = 0 movements = ['deadlift', 'barbell_bench_press', 'back_squat', 'shoulder_press'] three_lift_total = int( df_pr.query("reps==1")[['barbell_bench_press', 'back_squat', 'deadlift']].sum().sum()) plot_rep_prs, plot_rep_prs_cds = plot_ts( df_pr,
aDf = pd.DataFrame(data={'x': df.Day, 'y': df.Measurement}) a_source = ColumnDataSource(aDf) bDf = pd.DataFrame(data={'x': df.Day, 'y': df.Projection}) b_source = ColumnDataSource(bDf) model = Model(default_model) result = model.fit(df.Measurement, x=df.Day, a=1, b=1) fit = result.best_fit cDf = pd.DataFrame(data={'x': df.Day, 'y': fit}) c_source = ColumnDataSource(cDf) a = p.circle('x', 'y', size=8, source=a_source, color='grey', alpha=0.6) b = p.line('x', 'y', source=b_source, line_width=3, color='blue', alpha=0.4) c = p.line('x', 'y', source=c_source, line_width=3, color='red', alpha=0.4) legend = Legend(items=[("Measurement", [a]), ("Projection", [b]), ("y = a + b*ln(x)", [c])]) source_data = {'a': [result.best_values['a']], 'b': [result.best_values['b']]} source_data_table = ColumnDataSource(source_data) columns = [ TableColumn(field='a', title='a'), TableColumn(field='b', title='b') ] data_table = DataTable(source=source_data_table, columns=columns, width=300, height=50) proj_resid = np.sum((df.Projection - df.Measurement)**2) fit_resid = np.sum((df.Projection - fit)**2)
def definePlot(self, source): # format the text of the plot p1 = figure(**self.plot_options, title='Covid Simulation', toolbar_location='above') p1.yaxis.axis_label = 'Number of people' p1.xaxis.axis_label = 'Simulation time (days)' p1.xaxis[0].formatter = PrintfTickFormatter(format="%9.0f") p1.yaxis[0].formatter = PrintfTickFormatter(format="%9.0f") p1.xaxis.major_label_text_font_size = "10pt" p1.yaxis.major_label_text_font_size = "10pt" p2 = figure(**self.plot_options, title='Number of Susceptible people', toolbar_location='above') p2.yaxis.axis_label = 'Number of people' p2.xaxis.axis_label = 'Simulation time (days)' p2.xaxis[0].formatter = PrintfTickFormatter(format="%9.0f") p2.yaxis[0].formatter = PrintfTickFormatter(format="%9.0f") p2.xaxis.major_label_text_font_size = "10pt" p2.yaxis.major_label_text_font_size = "10pt" # format the plot line r0 = p2.line(source =source, x='x', y='sus', color='cyan', line_width=1,line_dash='dashed', legend='Susceptible') r1 = p2.circle(source=source, x='x', y='sus', color='cyan', size=10, legend='Susceptible') r2 = p1.line(source=source, x='x', y='exp',color='gold',line_width=1,line_dash='dotted', legend='Exposed') r3 = p1.circle(source=source, x='x', y='exp',color='gold',size=10, legend='Exposed') r4 = p1.line(source=source, x='x', y='inf',color='white',line_width=1,line_dash='dotted', legend='Infected') r5 = p1.circle(source=source, x='x', y='inf',color='white',size=10, legend='Infected') r6 = p1.line(source=source, x='x', y='sin',color='purple',line_width=1,line_dash='dotted', legend='Severe Infected') r7 = p1.circle(source=source, x='x', y='sin',color='purple',size=10, legend='Severe Infected') r8 = p1.line(source=source, x='x', y='qua',color='lime',line_width=1,line_dash='dotted', legend='Quarantined') r9 = p1.circle(source=source, x='x', y='qua',color='lime',size=10, legend='Quarantined') r10 = p1.line(source=source, x='x', y='imm',color='deepskyblue',line_width=1,line_dash='dotted', legend='Immunized') r11 = p1.circle(source=source, x='x', y='imm',color='deepskyblue',size=10, legend='Immunized') r12 = p1.line(source=source, x='x', y='dea',color='red',line_width=1,line_dash='dotted', legend='Dead') r13 = p1.circle(source=source, x='x', y='dea',color='red',size=10, legend='Dead') legend = Legend(items=[ ('Exposed', [r2, r3]), ('Infected', [r4, r5]), ('Severe Infected', [r6, r7]), ('Quarantined', [r8, r9]), ('Immunized', [r10, r11]), ('Dead', [r12, r13])]) # legends p1.legend.click_policy = 'hide' p1.background_fill_color = "black" p1.background_fill_alpha = 0.8 p1.legend.location = "top_left" p1.legend.background_fill_color = "cyan" p1.legend.background_fill_alpha = 0.5 p1.outline_line_width = 7 p1.outline_line_alpha = 0.9 p1.outline_line_color = "black" p2.legend.click_policy = 'hide' p2.background_fill_color = "black" p2.background_fill_alpha = 0.8 p2.legend.location = "top_left" p2.legend.background_fill_color = "cyan" p2.legend.background_fill_alpha = 0.5 p2.outline_line_width = 7 p2.outline_line_alpha = 0.9 p2.outline_line_color = "black" kz_map_tag = Div(text="""<div id="svg_holder" style="float:left;"> <svg width="780" height="530" id="statesvg"></svg> <div id="tooltip"></div> </div>""", width=960, height=600) kz_map_row = row(kz_map_tag) pAll = row(p1, kz_map_row) return pAll
recs.append( p.hbar(y='y', left='left', right='right', height='height', fill_alpha='fill_alpha', fill_color='fill_color', line_alpha=0.1, line_color='line_color', line_dash='solid', line_width=0.1, source=hbar_source)) # Create a legend legend = Legend(items=[(stock, [l]) for stock, l in zip(unique_names, lines)], location=(0, 0), orientation='horizontal') # Adjust the x view based upon the range of the data time_range = xs[0].max() - xs[0].min() p.x_range.start = np.min(xs[0]) - time_range * 0.1 p.x_range.end = np.max(xs[0]) # Add the stock logos to the plot N = len(unique_names) source = ColumnDataSource( dict( url=[image_urls.loc[name, 'image_url'] for name in unique_names], x1=[i.min() for i in xs], y1=max_ys, w1=[32] * N,
def display_timeline_values( data: pd.DataFrame, y: str, time_column: str = "TimeGenerated", source_columns: list = None, **kwargs, ) -> figure: """ Display a timeline of events. Parameters ---------- data : pd.DataFrame DataFrame as a single data set or grouped into individual plot series using the `group_by` parameter time_column : str, optional Name of the timestamp column (the default is 'TimeGenerated') y : str The column name holding the value to plot vertically source_columns : list, optional List of default source columns to use in tooltips (the default is None) Other Parameters ---------------- x : str, optional alias of `time_column` title : str, optional Title to display (the default is None) ref_event : Any, optional Add a reference line/label using the alert time (the default is None) ref_time : datetime, optional Add a reference line/label using `ref_time` (the default is None) group_by : str (where `data` is a DataFrame) The column to group timelines on legend_column : str, optional (where `data` is a DataFrame) Name of the column used to generate the legend labels if a legend is to be displayed. Default is `group_by` parameter. yaxis : bool, optional Whether to show the yaxis and labels range_tool : bool, optional Show the the range slider tool (default is True) height : int, optional The height of the plot figure (the default is auto-calculated height) width : int, optional The width of the plot figure (the default is 900) color : str Default series color (default is "navy"). This is overridden by automatic color assignments if plotting a grouped chart kind : Union[str, List[str]] one or more glyph types to plot., optional Supported types are "circle", "line" and "vbar" (default is "vbar") Returns ------- figure The bokeh plot figure. """ reset_output() output_notebook() height: int = kwargs.pop("height", None) width: int = kwargs.pop("width", 900) title: str = kwargs.pop("title", None) time_column = kwargs.get("x", time_column) group_by: str = kwargs.get("group_by", None) show_yaxis: bool = kwargs.pop("yaxis", True) show_range: bool = kwargs.pop("range_tool", True) color: str = kwargs.get("color", "navy") legend_pos: str = kwargs.pop("legend", None) kind: Any = kwargs.pop("kind", ["vbar"]) plot_kinds = kind if isinstance(kind, list) else [kind] ref_time, ref_label = _get_ref_event_time(**kwargs) graph_df, group_count_df, tool_tip_columns, series_count = _create_data_grouping( data, source_columns, time_column, group_by, color) # build the tool tips from columns (excluding these) tool_tip_items = [(f"{col}", f"@{col}") for col in tool_tip_columns] hover = HoverTool(tooltips=tool_tip_items, formatters={"Tooltip": "printf"}) # Create the Plot figure title = title if title else "Timeline" min_time = graph_df[time_column].min() max_time = graph_df[time_column].max() start_range = min_time - ((max_time - min_time) * 0.1) end_range = max_time + ((max_time - min_time) * 0.1) height = height if height else _calc_auto_plot_height(series_count) plot = figure( x_range=(start_range, end_range), min_border_left=50, plot_height=height, plot_width=width, x_axis_label="Event Time", x_axis_type="datetime", x_minor_ticks=10, y_axis_label=y, tools=[hover, "xwheel_zoom", "box_zoom", "reset", "save", "xpan"], toolbar_location="above", title=title, ) plot.yaxis.visible = show_yaxis plot.ygrid.minor_grid_line_color = "navy" plot.ygrid.minor_grid_line_alpha = 0.1 plot.ygrid.grid_line_color = "navy" plot.ygrid.grid_line_alpha = 0.3 plot.xgrid.minor_grid_line_color = "navy" plot.xgrid.minor_grid_line_alpha = 0.1 plot.xgrid.grid_line_color = "navy" plot.xgrid.grid_line_alpha = 0.3 # set the tick datetime formatter plot.xaxis[0].formatter = _get_tick_formatter() # plot groups individually so that we can create an interactive legend if group_by: legend_items = [] for _, group_id in group_count_df[group_by].items(): first_group_item = graph_df[graph_df[group_by] == group_id].iloc[0] legend_label = str(first_group_item[group_by]) inline_legend = str(group_id) if legend_pos == "inline" else None group_color = first_group_item["color"] row_source = ColumnDataSource( graph_df[graph_df[group_by] == group_id]) p_series = [] # create default plot args plot_args: Dict[str, Any] = dict(x=time_column, alpha=0.7, source=row_source, legend=inline_legend) if "vbar" in plot_kinds: p_series.append( plot.vbar(top=y, width=4, color="color", **plot_args)) if "circle" in plot_kinds: p_series.append( plot.circle(y=y, size=4, color="color", **plot_args)) if "line" in plot_kinds: p_series.append( plot.line(y=y, line_width=1, line_color=group_color, **plot_args)) if not inline_legend: legend_items.append((legend_label, p_series)) if legend_pos == "inline": # Position the inline legend plot.legend.location = "top_left" plot.legend.click_policy = "hide" elif legend_pos in ["left", "right"]: # Create the legend box outside of the plot area ext_legend = Legend( items=legend_items, location="center", click_policy="hide", label_text_font_size="8pt", ) plot.add_layout(ext_legend, legend_pos) else: plot_args = dict(x=time_column, color="color", alpha=0.7, source=ColumnDataSource(graph_df)) if "vbar" in plot_kinds: plot.vbar(top=y, width=4, **plot_args) if "circle" in plot_kinds: plot.circle(y=y, size=4, **plot_args) if "line" in plot_kinds: plot.line(y=y, line_width=4, **plot_args) # if we have a reference, plot the time as a line if ref_time is not None: _add_ref_line(plot, ref_time, ref_label, series_count) if show_range: rng_select = _create_range_tool( data=graph_df, min_time=min_time, max_time=max_time, plot_range=plot.x_range, width=width, height=height, time_column=time_column, ) show(column(plot, rng_select)) else: show(plot) return plot
return x, fy, ty source = ColumnDataSource(data=dict(x=[], fy=[], ty=[])) p = figure(x_range=(-7, 7), y_range=(-100, 200), width=800, height=400) line_f = p.line(x="x", y="fy", line_color="navy", line_width=2, source=source) line_t = p.line(x="x", y="ty", line_color="firebrick", line_width=2, source=source) p.background_fill_color = "lightgrey" legend = Legend(location="top_right") legend.items = [ LegendItem(label=value(f"{expr}"), renderers=[line_f]), LegendItem(label=value(f"taylor({expr})"), renderers=[line_t]), ] p.add_layout(legend) def update(): try: expr = sy.sympify(text.value, dict(x=xs)) except Exception as exception: errbox.text = str(exception) else: errbox.text = "" x, fy, ty = taylor(expr, xs, slider.value, (-2 * sy.pi, 2 * sy.pi), 200)
def mousover_plot(datadict, attr_x, attr_y, attr_color=None, attr_size=None, save_file=None, plot_title="", point_transparency = 0.5, point_size=20, default_color="#2222aa", hidden_keys = []): """ Produces dynamic scatter plot that can be interacted with by mousing over each point to see its label Args: datadict (dict): keys contain attributes, values of lists of data from each attribute to plot (each list index corresponds to datapoint). The values of all extra keys in this dict are considered (string) labels to assign to datapoints when they are moused over. Apply _formatDict() to any entries in datadict which are themselves dicts. attr_x (str): name of column in dataframe whose values are shown on x-axis (eg. 'latency'). Can be categorical or numeric values attr_y (str): name of column in dataframe whose values are shown on y-axis (eg. 'validation performance'). Must be numeric values. attr_size (str): name of column in dataframe whose values determine size of dots (eg. 'memory consumption'). Must be numeric values. attr_color (str): name of column in dataframe whose values determine color of dots (eg. one of the hyperparameters). Can be categorical or numeric values point_labels (list): list of strings describing the label for each dot (must be in same order as rows of dataframe) save_file (str): where to save plot to (html) file (if None, plot is not saved) plot_title (str): Title of plot and html file point_transparency (float): alpha value of points, lower = more transparent point_size (int): size of points, higher = larger hidden keys (list[str]): which keys of datadict NOT to show labels for. """ try: with warning_filter(): import bokeh from bokeh.plotting import output_file, ColumnDataSource, show, figure from bokeh.models import HoverTool, CategoricalColorMapper, LinearColorMapper, Legend, LegendItem, ColorBar from bokeh.palettes import Category20 bokeh_imported = True except ImportError: bokeh_imported = False if not bokeh_imported: warnings.warn('AutoGluon summary plots cannot be created because bokeh is not installed. To see plots, please do: "pip install bokeh"') return None n = len(datadict[attr_x]) for key in datadict.keys(): # Check lengths are all the same if len(datadict[key]) != n: raise ValueError("Key %s in datadict has different length than %s" % (key, attr_x)) attr_x_is_string = any([type(val)==str for val in datadict[attr_x]]) if attr_x_is_string: attr_x_levels = list(set(datadict[attr_x])) # use this to translate between int-indices and x-values og_x_vals = datadict[attr_x][:] attr_x2 = attr_x + "___" # this key must not already be in datadict. hidden_keys.append(attr_x2) datadict[attr_x2] = [attr_x_levels.index(category) for category in og_x_vals] # convert to ints legend = None if attr_color is not None: attr_color_is_string = any([type(val)==str for val in datadict[attr_color]]) color_datavals = datadict[attr_color] if attr_color_is_string: attr_color_levels = list(set(color_datavals)) colorpalette = Category20[20] color_mapper = CategoricalColorMapper(factors=attr_color_levels, palette=[colorpalette[2*i % len(colorpalette)] for i in range(len(attr_color_levels))]) legend = attr_color else: color_mapper = LinearColorMapper(palette='Magma256', low=min(datadict[attr_color]), high=max(datadict[attr_color])*1.25) default_color = {'field': attr_color, 'transform': color_mapper} if attr_size is not None: # different size for each point, ensure mean-size == point_size attr_size2 = attr_size + "____" hidden_keys.append(attr_size2) og_sizevals = np.array(datadict[attr_size]) sizevals = point_size + (og_sizevals - np.mean(og_sizevals))/np.std(og_sizevals) * (point_size/2) if np.min(sizevals) < 0: sizevals = -np.min(sizevals) + sizevals + 1.0 datadict[attr_size2] = list(sizevals) point_size = attr_size2 if save_file is not None: output_file(save_file, title=plot_title) print("Plot summary of models saved to file: %s" % save_file) source = ColumnDataSource(datadict) TOOLS="crosshair,pan,wheel_zoom,box_zoom,reset,hover,previewsave" p = figure(title=plot_title, tools=TOOLS) if attr_x_is_string: circ = p.circle(attr_x2, attr_y, line_color=default_color, line_alpha = point_transparency, fill_color = default_color, fill_alpha=point_transparency, size=point_size, source=source) else: circ = p.circle(attr_x, attr_y, line_color=default_color, line_alpha = point_transparency, fill_color = default_color, fill_alpha=point_transparency, size=point_size, source=source) hover = p.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([(key,'@'+key+'{safe}') for key in datadict.keys() if key not in hidden_keys]) # Format axes: p.xaxis.axis_label = attr_x p.yaxis.axis_label = attr_y if attr_x_is_string: # add x-ticks: p.xaxis.ticker = list(range(len(attr_x_levels))) p.xaxis.major_label_overrides = {i: attr_x_levels[i] for i in range(len(attr_x_levels))} # Legend additions: if attr_color is not None and attr_color_is_string: legend_it = [] for i in range(len(attr_color_levels)): legend_it.append(LegendItem(label=attr_color_levels[i], renderers = [circ], index=datadict[attr_color].index(attr_color_levels[i]))) legend = Legend(items=legend_it, location=(0, 0)) p.add_layout(legend, 'right') if attr_color is not None and not attr_color_is_string: color_bar = ColorBar(color_mapper=color_mapper, title = attr_color, label_standoff=12, border_line_color=None, location=(0,0)) p.add_layout(color_bar, 'right') if attr_size is not None: p.add_layout(Legend(items=[LegendItem(label='Size of points based on "'+attr_size + '"')]), 'below') show(p)
def ShowGraph(graphDict): if not graphDict['ShowGraph']: logger.warning('%s is not shown.', graphDict['GraphTitle']) return if (len(graphDict['Yaxes']) <= 0) or (len(graphDict['items']) <= 0): debug('No axes or no lines defined for graph "%s"', graphDict['GraphTitle']) return if graphDict['DBHost'] not in DBHostDict.keys(): logger.warning('Unknown database host "%s" for plot "%s"' % (graphDict['DBHost'], graphDict['GraphTitle'])) return hostItem = DBHostDict[graphDict['DBHost']] # Signal that we want to reference local files for html output. res = Resources(mode='absolute') # output_file(graphDict["outputFile"], title=graphDict['GraphTitle']) plot = figure(title=graphDict['GraphTitle'], tools="pan,wheel_zoom,box_zoom,reset,save,box_select", x_axis_type='datetime', plot_width=1600, plot_height=800, active_drag="box_zoom", active_scroll="wheel_zoom") plot.title.align = "center" plot.title.text_font_size = "25px" plot.xaxis.axis_label = graphDict['XaxisTitle'] # plot.xaxis.ticker = DatetimeTicker(num_minor_ticks = 4) plot.xaxis.formatter = DatetimeTickFormatter(seconds=["%M:%S"], minutes=["%R"], minsec=["%M:%S"], hours=["%R"], hourmin=["%m/%d %R"], days=['%m/%d']) plot.toolbar.logo = None legend = Legend() # legend.items = [LegendItem(label="--- Left Axis ---" , renderers=[])] legend.items = [] ######### Setup Y axes ## Colors plot.yaxis.visible = False extra_y_ranges = {} for i in range(len(graphDict['Yaxes'])): ya = graphDict['Yaxes'][i] eyrName = 'Y%s_axis' % i clr = ya['color_map'] if clr is None: clr = graphDict["graph_color_map"] ya["cmap"] = myPalette.Palette(clr, graphDict['max_palette_len'], loggingLevel=helperFunctionLoggingLevel) clr = ya['color'] if clr is None: clr = "black" side = ya['location'] extra_y_ranges[eyrName] = DataRange1d(range_padding=0.01) plot.extra_y_ranges = extra_y_ranges plot.add_layout( LinearAxis(y_range_name=eyrName, axis_label=ya['title'], axis_line_color=clr, major_label_text_color=clr, axis_label_text_color=clr, major_tick_line_color=clr, minor_tick_line_color=clr), side) for i in range(len(graphDict['items'])): item = graphDict['items'][i] info('-------------- %s ------------' % item['dataname']) ya = graphDict['Yaxes'][item['axisNum']] colorGroup = ya['title'] query = item['query'].format( my_schema=hostItem['myschema'], ha_schema=hostItem['haschema'], BeginDate= '{BeginDate}' # Leave {BeginDate} unmolested; it is for later replacement. ) if item['dataTimeZone'] == 'UTC': dataTimeOffsetUTC = 0 else: dataTimeOffsetUTC = hostItem['ServerTimeFromUTC'] data = GetData(item['datafile'], query, dataTimeOffsetUTC, hostItem) if data is None: logger.warning( 'item "%s" of graph "%s" has no data and is skipped.' % (item['dataname'], graphDict['GraphTitle'])) continue else: debug('Got %s rows of data.' % data.size) data = ColumnDataSource(data) debug('data column names are: %s; num rows is: %s' % (data.column_names, data.to_df().size)) yRangeName = 'Y%s_axis' % item['axisNum'] for thisCol in data.column_names[1:]: debug('Column "%s" is plotted against y axis: "%s"' % (thisCol, yRangeName)) itemColor = item["color"] if item["color"] is None: itemColor = ya['cmap'].nextColor(colorGroup) else: debug('item color "%s" is defined in the item definition.' % itemColor) r = eval('''plot.%s(x=data.column_names[0] , y = thisCol , source=data , color = itemColor, alpha=0.5 , muted_color = itemColor, muted_alpha=1 , name = thisCol , y_range_name=yRangeName)''' % item['lineType']) for (k, v) in item['lineMods'].items(): s = 'r.%s = %s' % (k, v) debug('Executing line mod "%s"' % s) exec(s) extra_y_ranges[yRangeName].renderers.append(r) if item['includeInLegend']: legend.items.append(LegendItem(label=thisCol, renderers=[r])) plot.add_layout(legend) plot.legend.location = "top_left" plot.legend.click_policy = "mute" plot.add_tools( HoverTool( tooltips=[ ('', '$name') # use @{ } for field names with spaces , ('', '$y{0.0}') # use @{ } for field names with spaces , ('', '@Time{%F %T}') ], formatters={ '@Time': 'datetime' # use 'datetime' formatter for 'x' field # use default 'numeral' formatter for other fields })) # show(plot) html = file_html(plot, res, graphDict['GraphTitle']) f = open(graphDict["outputFile"], mode='w') f.write(html) f.close() view(graphDict["outputFile"], new='tab')
import numpy as np from bokeh.models import Legend from bokeh.plotting import figure, show, output_file x = np.linspace(0, 4 * np.pi, 100) y = np.sin(x) output_file("legend_labels.html") p = figure(toolbar_location="above") r0 = p.circle(x, y) r1 = p.line(x, y) r2 = p.line(x, 2 * y, line_dash=[4, 4], line_color="orange", line_width=2) r3 = p.square(x, 3 * y, fill_color=None, line_color="green") r4 = p.line(x, 3 * y, line_color="green") legend = Legend(items=[ ("sin(x)", [r0, r1]), ("2*sin(x)", [r2]), ("3*sin(x)", [r3, r4]), ], location="center") p.add_layout(legend, 'right') show(p)
def generate_dnf_plot(circuit_years, circuit_results, circuit_races, circuit_id): """ Plots number of races, number of DNFs, and DNF percent for that year on the same plot. (2 different axes). :param circuit_years: Circuit years :param circuit_results: Circuit results :param circuit_races: Circuit races :param circuit_id: Circuit ID :return: Plot layout """ # TODO refactor to use existing method logging.info("Generating dnf plot") if len(circuit_years) == 0: return Div() source = pd.DataFrame(columns=["n_races", "year", "n_drivers", "dnf_pct", "dnfs", "dnf_pct_str", "total_dnf_pct", "total_dnfs", "total_dnf_pct_str"]) n_races = 0 total_dnfs = 0 total_drivers = 0 for year in circuit_years: year_race = circuit_races[circuit_races["year"] == year] if year_race.shape[0] == 0: continue rid = year_race.index.values[0] year_results = circuit_results[circuit_results["raceId"] == rid] num_dnfs = year_results["position"].isna().sum() num_drivers = year_results.shape[0] total_dnfs += num_dnfs total_drivers += num_drivers if num_drivers > 0: dnf_pct = num_dnfs / num_drivers total_dnf_pct = total_dnfs / total_drivers n_races += 1 source = source.append({ "n_races": n_races, "n_drivers": num_drivers, "year": year, "dnf_pct": dnf_pct, "dnfs": num_dnfs, "dnf_pct_str": str(round(100 * dnf_pct, 1)) + "%", "total_dnf_pct": total_dnf_pct, "total_dnfs": total_dnfs, "total_dnf_pct_str": str(round(100 * total_dnf_pct, 1)) + "%", }, ignore_index=True) circuit_name = get_circuit_name(circuit_id) min_year = min(circuit_years) max_year = max(circuit_years) max_drivers = source["n_drivers"].max() if max_drivers == 0: return Div() dnf_plot = figure( title=u"Number of DNFs \u2014 " + circuit_name, y_axis_label="", x_axis_label="Year", x_range=Range1d(min_year, max_year, bounds=(min_year, max_year + 3)), tools="pan,xbox_zoom,xwheel_zoom,reset,box_zoom,wheel_zoom,save", y_range=Range1d(0, max_drivers, bounds=(-1000, 1000)) ) subtitle = 'Year DNFs refers to the number/percent of DNFs for that year, Total DNFs refers to all DNFs up to ' \ 'that point in time' dnf_plot.add_layout(Title(text=subtitle, text_font_style="italic"), "above") max_dnf_pct = max(source["dnf_pct"].max(), source["total_dnf_pct"].max()) if max_dnf_pct > 0: k = max_drivers / max_dnf_pct else: k = 1 source["dnf_pct_scaled"] = k * source["dnf_pct"] source["total_dnf_pct_scaled"] = k * source["total_dnf_pct"] # Other y axis y_range = Range1d(start=0, end=max_dnf_pct, bounds=(-0.02, 1000)) dnf_plot.extra_y_ranges = {"percent_range": y_range} axis = LinearAxis(y_range_name="percent_range") axis.formatter = NumeralTickFormatter(format="0.0%") dnf_plot.add_layout(axis, "right") kwargs = { "x": "year", "line_width": 2, "line_alpha": 0.7, "source": source, "muted_alpha": 0.05 } races_line = dnf_plot.line(y="n_races", color="white", **kwargs) drivers_line = dnf_plot.line(y="n_drivers", color="yellow", **kwargs) dnfs_line = dnf_plot.line(y="dnfs", color="aqua", **kwargs) dnf_pct_line = dnf_plot.line(y="dnf_pct_scaled", color="aqua", line_dash="dashed", **kwargs) total_dnfs_line = dnf_plot.line(y="total_dnfs", color="orange", **kwargs) total_dnf_pct_line = dnf_plot.line(y="total_dnf_pct_scaled", color="orange", line_dash="dashed", **kwargs) legend = [LegendItem(label="Number of Races", renderers=[races_line]), LegendItem(label="Number of Drivers", renderers=[drivers_line]), LegendItem(label="Year DNFs", renderers=[dnfs_line]), LegendItem(label="Year DNF Pct.", renderers=[dnf_pct_line]), LegendItem(label="Total DNFs", renderers=[total_dnfs_line]), LegendItem(label="Total DNF Pct.", renderers=[total_dnf_pct_line])] legend = Legend(items=legend, location="top_right", glyph_height=15, spacing=2, inactive_fill_color="gray") dnf_plot.add_layout(legend, "right") dnf_plot.legend.click_policy = "mute" dnf_plot.legend.label_text_font_size = "12pt" # Hover tooltip dnf_plot.add_tools(HoverTool(show_arrow=False, tooltips=[ ("Number of Races", "@n_races"), ("Number of Drivers", "@n_drivers"), ("Year Num. DNFs", "@dnfs (@dnf_pct_str)"), ("Total Num. DNFs", "@total_dnfs (@total_dnf_pct_str)"), ("Year", "@year"), ])) # Crosshair tooltip dnf_plot.add_tools(CrosshairTool(line_color="white", line_alpha=0.6)) return dnf_plot
def generate_times_plot(circuit_years, circuit_quali, circuit_fastest_lap_data, circuit_races, circuit_results, circuit_id): """ Plot quali, fastest lap, and average lap times vs year along with rating vs year :param circuit_years: Circuit years :param circuit_quali: Circuit quali :param circuit_fastest_lap_data: Circuit fastest lap data :param circuit_races: Circuit races :param circuit_results: Circuit results :param circuit_id: Circuit ID :return: Times plot layout """ logging.info("Generating times plot") if circuit_quali.shape[0] == 0 and (circuit_fastest_lap_data.shape[0] == 0 or circuit_fastest_lap_data["avg_lap_time_millis"].isna().sum() == circuit_fastest_lap_data["avg_lap_time_millis"].shape[0]): return Div(text="") source = pd.DataFrame(columns=["year", "quali_time", "quali_time_str", "fastest_lap_time", "fastest_lap_str", "avg_lap_time", "avg_lap_str", "rating"]) for year in circuit_years: race = circuit_races[circuit_races["year"] == year] rid = race.index.values[0] # Qualifying year_quali = circuit_quali[circuit_quali["raceId"] == rid] quali_times = year_quali["q1"].append(year_quali["q2"].append(year_quali["q3"])) if quali_times.shape[0] == 0 or np.isnan(quali_times.idxmin()): quali_millis = np.nan quali_str = "" else: idxmin = int(quali_times.idxmin()) quali_name = get_driver_name(year_quali.loc[idxmin, "driverId"]) quali_millis = int(quali_times.loc[idxmin].min()) quali_str = millis_to_str(quali_millis) + " by " + quali_name # Fastest and average lap year_fastest_lap_data = circuit_fastest_lap_data[circuit_fastest_lap_data["raceId"] == rid] if year_fastest_lap_data.shape[0] == 0: avg_lap_millis = np.nan avg_lap_str = "" else: avg_lap_millis = int(year_fastest_lap_data["avg_lap_time_millis"].mean()) avg_lap_str = millis_to_str(avg_lap_millis) if year_fastest_lap_data.shape[0] == 0 or \ year_fastest_lap_data["fastest_lap_time_millis"].isna().sum() == year_fastest_lap_data.shape[0]: fastest_lap_millis = np.nan fastest_lap_str = "" else: idxmin = int(year_fastest_lap_data["fastest_lap_time_millis"].idxmin()) fastest_lap_name = get_driver_name(year_fastest_lap_data.loc[idxmin, "driver_id"]) fastest_lap_millis = int(year_fastest_lap_data.loc[idxmin, "fastest_lap_time_millis"]) fastest_lap_str = millis_to_str(fastest_lap_millis) + " by " + fastest_lap_name source = source.append({ "year": year, "quali_time": quali_millis, "quali_time_str": quali_str, "fastest_lap_time": fastest_lap_millis, "fastest_lap_str": fastest_lap_str, "avg_lap_time": avg_lap_millis, "avg_lap_str": avg_lap_str, "rating": race["rating"].values[0], }, ignore_index=True) circuit_name = get_circuit_name(circuit_id) min_time = min(source["fastest_lap_time"].min(), source["avg_lap_time"].min(), source["quali_time"].min()) - 5000 max_time = max(source["fastest_lap_time"].max(), source["avg_lap_time"].max(), source["quali_time"].max()) + 5000 start = pd.to_datetime(min_time, unit="ms") end = pd.to_datetime(max_time, unit="ms") if pd.isna(start) or pd.isna(end): min_time = source["avg_lap_time"].min() - 5000 max_time = source["avg_lap_time"].max() + 5000 start = pd.to_datetime(min_time, unit="ms") end = pd.to_datetime(max_time, unit="ms") # Scale rating so that a 0=min_time, 10=max_time source["rating_scaled"] = (max_time - min_time) * (source["rating"] / 10) + min_time source["rating"] = source["rating"].fillna("") min_year = np.min(circuit_years) max_year = np.max(circuit_years) if min_year == max_year: min_year -= 0.01 times_plot = figure( title=u"Qualifying, Fastest, Average, and Winning Times for " + circuit_name + " \u2014 Some data may be missing, zoom for more detail", x_axis_label="Year", y_axis_label="Lap Time", y_range=DataRange1d(start=start, end=end, bounds=(start, end)), x_range=Range1d(min_year, max_year, bounds=(min_year, max_year + 3)), tools="pan,xbox_zoom,xwheel_zoom,reset,box_zoom,wheel_zoom,save" ) times_plot.yaxis.formatter = DatetimeTickFormatter(**DATETIME_TICK_KWARGS) column_source = ColumnDataSource(data=source) kwargs = { "x": "year", "source": column_source, "line_width": 2, "muted_alpha": 0.05 } avg_lap_time_line = times_plot.line(y="avg_lap_time", line_color="white", **kwargs) legend_items = [ LegendItem(label="Average Race Lap", renderers=[avg_lap_time_line]), ] tooltips = [ ("Year", "@year"), ("Average Lap Time", "@avg_lap_str"), ] if source["quali_time"].isna().sum() < source.shape[0]: quali_time_line = times_plot.line(y="quali_time", line_color="red", **kwargs) legend_items.append(LegendItem(label="Qualifying Fastest", renderers=[quali_time_line])) tooltips.append(("Qualifying Lap Time", "@quali_time_str")) if source["fastest_lap_time"].isna().sum() < source.shape[0]: fastest_lap_time_line = times_plot.line(y="fastest_lap_time", line_color="yellow", **kwargs) legend_items.append(LegendItem(label="Fastest Race Lap", renderers=[fastest_lap_time_line])) tooltips.append(("Fastest Lap Time", "@fastest_lap_str")) # Add rating and other axis if source["rating"].replace("", np.nan).isna().sum() < source.shape[0]: rating_line = times_plot.line(y="rating_scaled", line_color="green", line_alpha=0.9, name="rating_line", **kwargs) legend_items.append(LegendItem(label="Average Rating", renderers=[rating_line])) tooltips.append(("Rating", "@rating")) y_range = Range1d(start=0, end=10, bounds=(0, 10)) times_plot.extra_y_ranges = {"rating_range": y_range} axis = LinearAxis(y_range_name="rating_range", axis_label="Rating") times_plot.add_layout(axis, "right") def update_rating_axis(): def dt_to_millis(t): if isinstance(t, float) or isinstance(t, int): return t return t.microsecond / 1000 + t.second * 1000 + t.minute * 1000 * 60 max_time = dt_to_millis(times_plot.y_range.end) min_time = dt_to_millis(times_plot.y_range.start) new_rating = (max_time - min_time) * (source["rating"].replace("", np.nan).astype(float) / 10) + min_time column_source.patch({ "rating_scaled": [(slice(new_rating.shape[0]), new_rating)] }) times_plot.extra_y_ranges.update({"rating_range": Range1d(start=0, end=10, bounds=(0, 10))}) times_plot.y_range.on_change("start", lambda attr, old, new: update_rating_axis()) times_plot.y_range.on_change("end", lambda attr, old, new: update_rating_axis()) # Legend legend = Legend(items=legend_items, location="top_right", glyph_height=15, spacing=2, inactive_fill_color="gray") times_plot.add_layout(legend, "right") times_plot.legend.click_policy = "mute" times_plot.legend.label_text_font_size = "12pt" # The default font size # Hover tooltip times_plot.add_tools(HoverTool(show_arrow=False, tooltips=tooltips)) # Crosshair times_plot.add_tools(CrosshairTool(line_color="white", line_alpha=0.6)) return times_plot
def plot_scatter_4D(data, x_key, y_key, size_key=None, color_key=None, x_label=None, y_label=None, size_label=None, color_fn=None, add_marker_text=False, ax=None, title=None, plotengine='matplotlib'): """y_key can be a list...""" colors = np.asarray(['b','r','g','y']) if x_label is None: x_label = compute_scatter_label(x_key) if y_label is None: y_label = compute_scatter_label(y_key) if size_label is None: size_label = compute_scatter_label(size_key) # Data is in format needed to scatter, so we call it # kwargs. kwargs = decimate_data(data, x_key=x_key, y_key=y_key, size_key=size_key, color_key=color_key, color_fn=color_fn) common_keys = kwargs.pop('keys') # Now plot it, and annotate it! if plotengine in ['matplotlib', 'mpld3']: if ax is None: ax = plt.figure(figsize=(11, 10.5)).gca() ax.scatter(**kwargs) ax.tick_params(labelsize=16) if x_label: ax.set_xlabel(x_label, fontsize=18) if y_label: ax.set_ylabel(y_label, fontsize=18) if size_label: if 'thickness' in size_label: # hack loc = 'upper left' else: loc = 'upper right' ax.legend([size_label], loc=loc) if add_marker_text: # Interesting if it's outside of some range of values is_interesting = lambda v, varr, dist: np.abs(varr.mean() - v) >= dist * varr.std() for xi, (label, x, y) in enumerate(zip(common_keys, kwargs['x'], kwargs['y'])): # , kwargs['s']): locs = locals() annotations = [key for key, sval in zip(['x', 'y'], [1.35, 1.5]) if is_interesting(locs[key], kwargs[key], sval)] if len(annotations) > 0: plt.annotate( '%s (%s)' % (data.get_anatomical_name(data.get_nonhemi_key(label)), ', '.join(annotations)), xy=(x, y), xytext=(25, 25), textcoords='offset points', ha='right', va='bottom', bbox=dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.5), arrowprops=dict(arrowstyle='->', connectionstyle='arc3, rad=0'), fontsize=16) plt.axis('equal') #ax.set_aspect('equal') if np.any(kwargs['x'] <= 0) and np.any(kwargs['x'] >= 0): ax.plot([0, 0], ax.get_ylim(), 'k--') # y-axis if np.any(kwargs['y'] <= 0) and np.any(kwargs['y'] >= 0): ax.plot(ax.get_xlim(), [0, 0], 'k--') # x-axis plt.axis('tight') ax.get_figure().suptitle(title, fontsize=24) elif plotengine in ['bokeh', 'bokeh-silent']: from bokeh.io import show from bokeh.models.glyphs import Circle from bokeh.models import (Plot, DataRange1d, LinearAxis, Legend, ColumnDataSource, PanTool, WheelZoomTool, HoverTool, CrosshairTool, PreviewSaveTool, ResizeTool, BoxZoomTool, ResetTool) source = ColumnDataSource(data=dict( label=[data.get_anatomical_name(data.get_nonhemi_key(label)) for label in common_keys], x=kwargs['x'], y=kwargs['y'], s=kwargs.get('s', np.ones(kwargs['x'].shape) * 1000) / 1.E5)) xdr = DataRange1d() ydr = DataRange1d() plot = Plot(x_range=xdr, y_range=ydr, name='scatter', title=title) circle = Circle(x="x", y="y", radius="s", fill_color=kwargs.get('c', 'blue'), line_color="black") circle_renderer = plot.add_glyph(source, circle) if size_label: legend = Legend(orientation="top_right") legend.legends = [(size_label, [circle_renderer])] plot.add_layout(legend) plot.add_layout(LinearAxis(axis_label=x_label), 'below') plot.add_layout(LinearAxis(axis_label=y_label), 'left') plot.add_tools(PanTool(), WheelZoomTool(), CrosshairTool(), PreviewSaveTool(), ResizeTool(), BoxZoomTool(), HoverTool(tooltips=[('label', '@label')]), ResetTool()) ax = plot return ax