def draw_constant_salary_bump(s: figure, constant_list: list, pay_norm: int): """ Draw lines for constant salary increase """ constant_list0 = [c / pay_norm for c in constant_list] if CURRENCY_NORM and pay_norm == 1: constant_list0 = [a / 1e3 for a in constant_list] x_max = 2500. if pay_norm > 1: x_max = 1200. for c, constant in enumerate(constant_list0): x = np.arange(max([s.x_range.start, constant + 1]), x_max, 5) y = 100 * constant / (x - constant) if pay_norm == 1: text = f'${constant}k' else: text = f'${constant_list[c]/1e3}k (${constant:.2f}/hr)' source = ColumnDataSource(data=dict(x=x, y=y, name=[text] * len(x))) s.line('x', 'y', line_dash='dashed', line_color='black', source=source) y_label = constant_list[c] / 1e3 x_label = constant + 100 * constant / y_label label = Label(x=x_label, y=y_label, text=text) s.add_layout(label) return s
def _add_layer(cls, plot: figure, layer_document: ChartLayerDocument) -> None: """ Create circle on a plot figure. Method creates circle and adjusts it based on configuration. The circle is appended to the provided plot. :param layer_document: (LayerDocument) layer document object containing ingredients and configuration. :param plot: (bokeh.plotting.figure) bokeh figure to create circle on. :return: None """ layer_model = layer_document.model layer_figure = layer_model.figure axis = layer_model.axis axis.name = axis.name or axis.data_field plot.yaxis.axis_label = axis.name plot.yaxis.axis_label = axis.name or axis.data_field plot.circle(layer_document.x_axis.data_field, axis.data_field, color=layer_figure.colour, alpha=layer_figure.opacity, legend=axis.name, size=layer_figure.size * cls._scale, source=layer_document.data_source)
def add_figure_attributes(self, fig: figure, selected_keys: List): """ add some annotations to the figure :param fig: :param selected_keys: :return: """ # only show legend if at least one plot is active if self.active_plot_raw or self.active_plot_average or self.active_plot_trend: fig.legend.location = "top_left" fig.legend.click_policy = "hide" fig.xaxis.formatter = DATETIME_TICK_FORMATTER fig.add_tools(self.generate_tool_tips(selected_keys))
def bokeh_pr_curve_raw(precision: Iterable[float], recall: Iterable[float], threshold: List[float], fig: figure = None, color: str = 'blue', legend=None) -> LayoutDOM: """ plot precision recall curve. can add to an existing figure, or create a new one Args: precision: iterable of precision points recall: iterable of recall points threshold: iterable of threshold points which resulted in the previous $precision and $recall fig: if None: create a new bokeh figure, otherwise, add plot to figure one color: color of the plot Returns: precision recall bokeh plot """ if fig is None: hover = HoverTool(tooltips=[( 'recall', "$x{%0.2f}"), ('precision', "$y{%0.2f}"), ('threshold', "@threshold{%0.2f}")]) tools = "pan, wheel_zoom, box_zoom, reset" fig = figure(x_range=(0, 1), y_range=(0, 1), tools=[hover, tools], title='Precision Recall Curve', plot_height=350, plot_width=400) cds = ColumnDataSource(data={ 'precision': precision, 'recall': recall, 'threshold': threshold }) fig.line(x='recall', y='precision', line_width=2, source=cds, color=color, muted_alpha=0.2, muted_color=color) # legend=legend # fig.circle(x='precision', y='recall', line_width=1, source=cds) fig.xaxis.axis_label = 'Recall' fig.yaxis.axis_label = 'Precision' fig.legend.click_policy = "mute" fig.legend.label_text_font_size = '6pt' return fig
def tap_tool_callback(plot: figure): ''' This callback is always active. Clicking on the plot updates contours see Region.modify_pmap plot is passed to add the tool to the Bokeh div ''' callback = CustomJS(args=dict(), code=""" var target = "api/v0.1/sendClick/" + cb_obj.x.toString() + "/" + cb_obj.y.toString(); console.log(target); fetch(target) .catch(err=>console.log(err)) """) plot.js_on_event('tap', callback)
def create_line(self, fig: figure, color): """ Creates the line in the specified figure based on the ColumnDataSource of this parameter. :param fig: bokeh figure object where this line is going to live. :param color: used to cycle through the colors. """ return fig.line(x=f'{self.name}_time', y=self.name, source=self.source, legend_label=self.name, color=color)
def add_tools(plot: figure, img_directory: path): ''' configure which additional tools are shown on the Bokeh page ''' api = "http://localhost:5000/api/v0.1/" next_path = path.join(img_directory, "Right.png") prev_path = path.join(img_directory, "Left.png") approve_path = path.join(img_directory, "Check.png") reject_path = path.join(img_directory, "Cross.png") update_path = path.join(img_directory, "eye.jpeg") plot.add_tools( create_navigate_to_updated_button(update_path), create_nav_tool(plot, "Previous Annotation", api + "prev", prev_path), create_nav_tool(plot, "Next Annotation", api + "next", next_path), create_approval_tool(plot, "Approval Tool", api + 'approve/true', api + "next", approve_path), create_approval_tool(plot, "Reject Tool", api + 'approve/false', api + "next", reject_path), create_poly_edit_tool(plot), create_poly_draw_tool(plot) ) tap_tool_callback(plot)
def create_graph(graph: figure, data: ColumnDataSource, graph_params: Dict) -> figure: ''' Creates a scatter plot by given parameters ''' coloring = '' use_bucket_colorization = graph_params['use_bucket_colorization'] if use_bucket_colorization: number_of_colors = graph_params['number_of_colors'] factors_list = graph_params['factors_list'] y_value = graph_params['y_value'] graph_point_size = graph_params['graph_point_size'] palette = graph_params['palette'] if use_bucket_colorization and number_of_colors <= 11: factors_list = get_factors(number_of_colors) color_mapper = CategoricalColorMapper( factors=factors_list, palette=palette[number_of_colors]) logger.info(f'{number_of_colors} color buckets created') graph.scatter(source=data, x='number', y=y_value, color={ 'field': 'color_bucket', 'transform': color_mapper }, size=graph_point_size) coloring = palette_name.lower() else: base_color = '#3030ff' logger.info('Base coloring') graph.scatter(source=data, x='number', y=y_value, color=base_color, size=graph_point_size) coloring = 'monocolor' return graph, coloring
def plot_circles( mol_plot: figure, source: ColumnDataSource, categorical_colour: bool = False, factors: Optional[List[Any]] = None, colormap=palettes.Category10_10, ) -> figure: """Add the points to a bokeh figure to render the trimer molecule. This enables the trimer molecules to be drawn on the figure using only the position and the orientations of the central molecule. """ glyph_args = dict( x="x", y="y", fill_alpha=1, line_alpha=0, radius="radius", fill_color="colour" ) if categorical_colour: if factors is None: factors = np.unique(source.data["colour"]).astype(str) colour_categorical = factor_cmap( field_name="colour", factors=factors, palette=colormap ) glyph_args["fill_color"] = colour_categorical glyph = Circle(**glyph_args) mol_plot.add_glyph(source, glyph=glyph) mol_plot.add_tools( HoverTool( tooltips=[ ("index", "$index"), ("x:", "@x"), ("y:", "@y"), ("orientation:", "@orientation"), ] ) ) mol_plot.toolbar.active_inspect = None return mol_plot
def setup_timeline_tools(plot: figure) -> None: """ :param plot: :return: """ timeline_hover = HoverTool(tooltips=[('PEP', '@PEP'), ('Title', '@Title'), ('Type', '@Type'), ('Status', '@Status'), ('Created', '@Created'), ('Python-Version', '@PythonVersion')], names=["circle"]) release_hover = HoverTool(tooltips=[('Version', '@release_number'), ('Release Date', '@release_date_str')], names=["release_label"]) plot.add_tools(timeline_hover, release_hover, BoxZoomTool(), ResetTool(), SaveTool()) url = 'https://www.python.org/dev/peps/pep-@index/' taptool = plot.select(type=TapTool) taptool.callback = OpenURL(url=url) taptool.names = ['circle']
def candle_plot(stocks: List, plot:figure=plot, color='blue'): stock, stock_day = stocks name = stock.data['name'].values[0] label = 'Mean price of ' + name plot.segment('shortened_date', 'high', 'shortened_date', 'low', color="black", source=stock) plot.vbar('inc', w, 'open_inc', 'close_inc', fill_color="#D5E1DD", line_color="black",source=stock_day) plot.vbar('dec', w, 'open_dec', 'close_dec', fill_color="#F2583E", line_color="black",source=stock_day) # stock_mean_val=whole_data[['high', 'low']].mean(axis=1) plot.line('shortened_date', 'mean', legend_label=label, muted_alpha=0.2, line_color=color, alpha=0.5, source=stock)
def create_poly_draw_tool(plot: figure): p1 = plot.patches([], [], fill_alpha=0.4) return PolyDrawTool(renderers = [p1])
def create_poly_edit_tool(plot: figure): p1 = plot.patches([], [], fill_alpha=0.4) c1 = plot.circle([], [], size=10, color='red') return PolyEditTool(renderers = [p1], vertex_renderer = c1)
def bokeh_scatter(x, y, name: pd.Series = None, x_err=None, pay_norm: int = 1, x_label: str = '', y_label: str = '', x_range: list = tuple([0, 500]), title: str = '', size: Union[int, float] = 4, bc: str = "#f0f0f0", bfc: str = "#fafafa", fc="#f8b739", ec="#f8b739", alpha=0.5, label: Optional[str] = None, s: figure = None): if s is None: s = bokeh_scatter_init(pay_norm, x_label, y_label, title=title, x_range=x_range, bc=bc, bfc=bfc, plot_constants=True) if x_err is not None: bin_range = ColumnDataSource( data=dict(base=y, lower=x_err[0], upper=x_err[1])) w = Whisker(source=bin_range, base='base', lower='lower', upper='upper', dimension='width', line_color=fc) w.upper_head.line_color = fc w.lower_head.line_color = fc s.add_layout(w) if name is not None: source = ColumnDataSource(data=dict(x=x, y=y, name=name)) s.scatter('x', 'y', marker='circle', fill_color=fc, source=source, line_color=ec, alpha=alpha, size=size, legend_label=label) else: s.scatter('x', 'y', marker='circle', fill_color=fc, line_color=ec, alpha=alpha, size=size, legend_label=label) return s
def setup_timeline_backend_parts(plot: figure, desc_label_source: ColumnDataSource) -> None: """ :param plot: :param desc_label_source: :return: """ start_date, end_date = plot.x_range.start, plot.x_range.end arrow_x = start_date + datetime.timedelta(days=180) # 補助線を引く plot.line([start_date, end_date], [1, 1], line_width=3, line_color='pink') plot.line([start_date, end_date], [0.5, 0.5], line_width=3, line_dash='dotted', line_color='pink') plot.line([start_date, end_date], [1.5, 1.5], line_width=3, line_dash='dotted', line_color='pink') # 矢印を表示する plot.add_layout( Arrow(end=VeeHead(size=15), line_color='black', x_start=arrow_x, y_start=1.4, x_end=arrow_x, y_end=1.1)) plot.add_layout( Arrow(end=VeeHead(size=15), line_color='black', x_start=arrow_x, y_start=0.9, x_end=arrow_x, y_end=0.6)) plot.text(source=desc_label_source, x='x', y='y', text='text', text_font_size='size', text_alpha=0.8)
def figure_constructor(tool, loader, node): #print('Figureeeee: /n') fig = loader.construct_mapping(node, deep=True) fmt = tool.formats.get('Figure', {}) elements = fig.pop('elements', []) #print('Figureeeee2: /n', elements) cmds = [] ref = fig.pop("ref", "") callback = fig.pop("on_change", []) axis = tool.formats.get("Axis", {}) for key in fig: val = fig[key] #print('Figureeeee3: /n', val,key) if key in ['text', 'add_tools']: cmds.append((key, val)) else: fmt[key] = val figure = Figure(**fmt) for key, cmd in cmds: if key == 'add_tools': figure.add_tools(*cmd) elif key == 'text': figure.text(*cmd.pop('loc'), **cmd) for element in elements: key = element.pop('kind') if key == 'line': line_fmt = tool.formats.get('Line', {}) line_fmt.update(element) figure.line('x', 'y', **line_fmt) #print('PLOT LINE: ', line_fmt, line_fmt.update(element)) elif key == 'circle': circle_fmt = tool.formats.get('Circle', {}) circle_fmt.update(element) figure.circle('x', 'y', **circle_fmt) elif key == 'image': print('HElooooo!!') image_fmt = tool.formats.get('Image', {}) image_fmt.update(element) figure.image('value', 'x', 'y', 'dw', 'dh', **image_fmt) #print('PLOT image: ', image_fmt, image_fmt.update(element)) for attr, val in axis.items(): #change axis attributes, hopefully setattr(figure.axis, attr, val) if ref: tool.refs[ref] = figure if callback: figure.on_change(*callback) yield figure