def get_empty_triangle_canvas(title): p = figure(title=title) # draw the axes f0 = (0, 0, 1) f1 = (0, 1, 0) f2 = (1, 0, 0) p.add_layout( Arrow(end=NormalHead(fill_color="gray"), x_start=triangle_transform(*f0)[0], y_start=triangle_transform(*f0)[1], x_end=triangle_transform(*f1)[0], y_end=triangle_transform(*f1)[1])) # F0 p.add_layout( Arrow(end=NormalHead(fill_color="gray"), x_start=triangle_transform(*f1)[0], y_start=triangle_transform(*f1)[1], x_end=triangle_transform(*f2)[0], y_end=triangle_transform(*f2)[1])) # F1 p.add_layout( Arrow(end=NormalHead(fill_color="gray"), x_start=triangle_transform(*f2)[0], y_start=triangle_transform(*f2)[1], x_end=triangle_transform(*f0)[0], y_end=triangle_transform(*f0)[1])) # F2 return p
def annotate(self): FWHM, (x_left, x_right), HM = self.analysis.results[self.current_label] arrow = annotations.Arrow(x_start=x_left, y_start=HM, x_end=x_right, y_end=HM, start=NormalHead(), end=NormalHead()) label = annotations.Label(text=f"{self.current_label}: {FWHM:.1f}", x=(x_left + x_right) / 2, y=HM, text_align='center') self.analyser.gui.fig.renderers.extend([arrow, label])
def get_empirical_figure(x, y, data): fig = figure( height=600, sizing_mode='stretch_width', x_axis_label='X', y_axis_label='F(x)' ) x.append(x[len(x)-1]+1) y.append(y[len(y)-1]) fig.circle(x=x, y=y, fill_alpha=0) for i in range(0, len(data)): x = data[i+1].get('x') if i != len(data)-1 else data[i].get('x')+1 fig.add_layout(Arrow( end=NormalHead(size=10, fill_color="blue"), line_color="blue", line_width=2, x_start=x, y_start=data[i].get('w_nak'), x_end=data[i].get('x'), y_end=data[i].get('w_nak') )) fig.add_layout(Span( location=data[i].get('x'), dimension='height', line_color='black', line_dash='dashed', line_width=1 )) fig.yaxis.fixed_location = 0 return fig
def render_graph(self, vert_size): display_graph = GraphRenderer(kwargs) display_graph.node_renderer.data_src.add( list(self.graph.vertices.keys()), "index") display_graph.node_renderer.data_src.add(self.get_colors(), "color") display_graph.node_renderer.glyph = Circle(size=vert_size, fill_color="color") display_graph.node__renderer.data_src.data = self.get_edges() self.randomize() for i in range(len( display_graph.edge_renderer.data_src.data["start"])): self.plot.add_layout( Arrow( end=NormalHead(fill_color="blue"), x_start=self.pos[display_graph.edge_renderer.ddata.src. data["start"][i]][0], x_end=self.pos[display_graph.edge_renderer.ddata.src. data["end"][i]][0], y_start=self.pos[display_graph.edge_renderer.ddata.src. data["start"][i]][1], y_end=self.pos[display_graph.edge_renderer.ddata.src. data["end"][i]][1], ))
def add_path(self, path, shock=False, thin=False): path["X_1"] = path["X"] + path["dX"] path["Y_1"] = path["Y"] + path["dY"] if shock: path["X_1"] = path["X_1"] / 10 if thin: width = 1 / self.proportion else: width = 2 / self.proportion self.p.line( x=path.iloc[:-1, 0], y=path.iloc[:-1, 1], line_color="white", line_width=width, ) last = path.iloc[-2, :] self.p.add_layout( Arrow( end=NormalHead( line_color=None, fill_color="white", size=4 / self.proportion ), x_start=last["X"], y_start=last["Y"], x_end=last["X_1"], y_end=last["Y_1"], line_width=width, line_color="#FFFFFF", ) )
def test_arrow(output_file_url, selenium, screenshot): # Have to specify x/y range as labels aren't included in the plot area solver plot = figure(height=HEIGHT, width=WIDTH, x_range=(0,10), y_range=(0,10), tools='') arrow1 = Arrow(x_start=1, y_start=3, x_end=6, y_end=8, line_color='green', line_alpha=0.7, line_dash='8 4', line_width=5, end=OpenHead() ) arrow1.end.line_width=8 arrow2 = Arrow(x_start=2, y_start=2, x_end=7, y_end=7, start=NormalHead(), end=VeeHead() ) arrow2.start.fill_color = 'indigo' arrow2.end.fill_color = 'orange' arrow2.end.size = 50 plot.add_layout(arrow1) plot.add_layout(arrow2) # Save the plot and start the test save(plot) selenium.get(output_file_url) # Take screenshot assert screenshot.is_valid()
def strut_pressure_plot(layers, net, brace_elev): axis_size = max([max(net[0]), -1 * min(net[0])]) p = figure( x_range=[-axis_size-1000, axis_size*2.5], y_range=[net[1][-1]-3, net[1][0]+3], title="Strut Pressure Diagram", plot_width=800, plot_height=1200 ) p.xaxis.bounds = (0, 0) p.yaxis.bounds = (0, 0) p.line(net[0], net[1], line_width=2, color='black') p.line([0, 0], [layers[0][0], layers[-1][0]], color='black') p.add_layout(Label(x=1.5*axis_size, y=net[1][0] + 2, text="Pressure")) for i in range(len(layers)): p.line([-axis_size-1000, axis_size*2.5], [layers[i][0], layers[i][0]], color='dimgray', alpha=0.7) work_point_label = Label(x=-axis_size-1000, y=layers[i][0], text=str(layers[i][0]), text_font_size='12pt') p.add_layout(work_point_label) x, y = 0, 0 for k in range(len(net[0])): i = net[0][k] j = net[1][k] if j == y and i != x: pressure_label = Label(x=axis_size*1.5, y=j-0.5, text=str(i), text_font_size='12pt') else: pressure_label = Label(x=axis_size*1.5, y=j, text=str(i), text_font_size='12pt') x, y = i, j p.add_layout(pressure_label) p.add_layout(Arrow(end=NormalHead(size=10), x_start=-0.25*axis_size, y_start=brace_elev[0], x_end=00, y_end=brace_elev[0])) p.add_layout(Arrow(end=NormalHead(size=10), x_start=-0.25 * axis_size, y_start=brace_elev[1], x_end=00, y_end=brace_elev[1])) top_waler_label = Label(x=-0.4*axis_size, y=brace_elev[0]-0.5, text='T1') bot_waler_label = Label(x=-0.4*axis_size, y=brace_elev[1]-0.5, text='T2') p.add_layout(top_waler_label) p.add_layout(bot_waler_label) if len(brace_elev) == 3: t3_waler_label = Label(x=-0.4*axis_size, y=brace_elev[2]-0.5, text='T3') p.add_layout(t3_waler_label) p.add_layout(Arrow(end=NormalHead(size=10), x_start=-0.25 * axis_size, y_start=brace_elev[2], x_end=00, y_end=brace_elev[2])) return p
def biplot(score, coeff, expl_var, decomp='PCA', meta=None, fig_dir=None): coeff /= (np.abs(coeff).max() - np.abs(coeff).min()) * 1.5 score /= (score.max() - score.min()) coeff['norm'] = coeff.x**2 + coeff.y**2 coeff = coeff.sort_values(by='norm', ascending=False).iloc[:8] labels = meta.unique() if len(labels) < 11: colors = Category10[len(labels)] else: colors = inferno(len(labels)) color_map = {label: colors[i] for i, label in enumerate(labels)} score[meta.name] = meta.values score['color'] = [color_map[label] for label in meta.values] p = figure(plot_width=800, plot_height=800, x_range=(-1, 1), y_range=(-1, 1), title='Covariate contribution to the first 2 components') p.circle(x=score.columns[0], y=score.columns[1], color='color', alpha=0.25, size=5, legend_group=meta.name, source=score) for (x, y, _) in coeff.values: p.add_layout( Arrow(end=NormalHead(fill_color="orange", size=12, line_width=1), x_start=0, y_start=0, x_end=x, y_end=y)) labels = LabelSet(x='x', y='y', text='index', level='glyph', x_offset=5, y_offset=5, render_mode='canvas', source=ColumnDataSource(coeff.reset_index())) p.add_layout(labels) p.xaxis.axis_label = 'Component 1 ({:.1%})'.format(expl_var[0]) p.yaxis.axis_label = 'Component 2 ({:.1%})'.format(expl_var[1]) output_file(f"{fig_dir}/biplot_{decomp}.html") save(p)
def st_RHS_plotting(self): """ Plot the drag factors on a sharp cornered rectanglar exposed member """ plot = Plot(title=None, match_aspect=True) glyph = Rect(x=0, y=0, width=self.d, height=self.b, fill_color="#cab2d6") plot.add_glyph(glyph) plot.add_layout( Arrow(end=NormalHead(fill_color="orange"), x_start=0, y_start=self.b / 4, x_end=0, y_end=self.b / 2)) plot.add_layout( Arrow(end=NormalHead(fill_color="orange"), x_start=-self.d / 2, y_start=0, x_end=-self.d / 4, y_end=0)) plot.add_layout(LinearAxis(), 'below') plot.add_layout(LinearAxis(), 'left') plot.add_glyph( Text( x=0, y=self.b / 2, text=[ f"Cf_y = {self.Cf_y:.2f}\nsigma_wind = {self.sigma_wind_vert/1000:.2f} kPa" ], text_align="left")) plot.add_glyph( Text( x=-self.d / 4, y=0, text=[ f"Cf_x = {self.Cf_x:.2f}\nsigma_wind = {self.sigma_wind_horiz/1000:.2f} kPa" ], text_align="left")) return plot
def plot_ortho(plot, X_n, neg=1, color_choice='blue'): X_n_list = X_n.tolist() for i in X_n_list: new_point = [i[0] + neg * 1 / (5**0.5), i[1] + neg * 4 / (5**0.5)] plot.add_layout( Arrow(end=NormalHead(fill_color=color_choice, size=10), x_start=i[0], y_start=i[1], x_end=new_point[0], y_end=new_point[1], line_color=color_choice, line_alpha=0.8)) return plot
def _add_forward(fig, ftype, e, match): color = _get_team_color(e, match) fig.diamond(x=[e['start']['x'] / 100], y=[e['start']['y'] / 100], size=10, color=color, line_width=2) if ftype == 'goals_attempts': line_dash = 'dashed' else: line_dash = 'solid' arrow = Arrow(end=NormalHead(fill_color=color, line_color=color), line_color=color, line_width=2, line_dash=line_dash, x_start=e['start']['x'] / 100, y_start=e['start']['y'] / 100, x_end=e['end']['x'] / 100, y_end=e['end']['y'] / 100) fig.add_layout(arrow)
def plot_residuals(residuals): p = figure(plot_width=600, plot_height=600, title='Convergence Path', x_axis_label='x-est', y_axis_label='mean abs residual') pts = list(zip(*residuals)) p.circle(pts[0], pts[1], color='crimson', size=10) tail_pt = residuals[0] for a_pt in residuals[1:]: p.add_layout( Arrow(end=NormalHead(size=8, fill_color='lightcoral'), line_color='lightcoral', x_start=tail_pt[0], y_start=tail_pt[1], x_end=a_pt[0], y_end=a_pt[1])) tail_pt = a_pt return p
def vector(self, vector=None, add_color=None, alpha=1): ''' Visualize a vector in R2. Arguments: - vector: numpy array with two elements. - add_color: provide a string value for a specific colorself. Default is None. If None, a color from a specified (bu finite) assortment is drawn from. ''' if add_color is None: color = self.color.pop(0) # Draw a new color from the selection elif isinstance(add_color, str): color = add_color else: color = "black" # Apply the vector to our standard coordinate system new_vector = self.basis.dot(vector) self.vectors.append(new_vector) # store vector # Alter if origin is different if np.count_nonzero(self.origin) != 0: new_vector = new_vector + self.origin # Plot vector self.plot.add_layout( Arrow(end=NormalHead(fill_color=color, fill_alpha=alpha, size=10, line_color=color, line_alpha=alpha), x_start=self.origin[0], y_start=self.origin[1], line_color=color, line_alpha=alpha, x_end=new_vector[0], y_end=new_vector[1], line_width=3))
def show(self): N = len(self.graph.vertices) node_indices = list(range(N)) plot = figure(title='Graph Layout Demonstration', x_range=self.x_range, y_range=self.y_range, tools='', toolbar_location=None) graph = GraphRenderer() graph.node_renderer.data_source.add(node_indices, 'index') # Renders the colors graph.node_renderer.data_source.add( [vertex.color for vertex in self.graph.vertices], 'color') # Renders the shape of the nodes graph.node_renderer.glyph = Circle(radius=0.2, fill_color='color') # Draws the edges to neighboring nodes start_indices = [] end_indices = [] for vertex in self.graph.vertices: for edge_end in self.graph.vertices[vertex]: # Bi-directional if vertex in self.graph.vertices[edge_end]: start_indices.append(vertex.id) end_indices.append(edge_end.id) else: # Directional Edges plot.add_layout( Arrow(end=NormalHead(fill_color='black', line_color="firebrick", line_width=1), x_start=vertex.x, y_start=vertex.y, x_end=edge_end.x, y_end=edge_end.y)) # Renders the Bi-directional edges graph.edge_renderer.data_source.data = dict(start=start_indices, end=end_indices) # Plots the node locations x = [vertex.x for vertex in self.graph.vertices] y = [vertex.y for vertex in self.graph.vertices] graph_layout = dict(zip(node_indices, zip(x, y))) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) # Labels the nodes identities = [vertex.id for vertex in self.graph.vertices] labelSource = ColumnDataSource(data=dict(x=x, y=y, names=identities)) labels = LabelSet(x='x', y='y', text='names', level='glyph', text_align='center', text_baseline='middle', source=labelSource, render_mode='canvas', text_color='black') plot.renderers.append(graph) plot.add_layout(labels) output_file('graph.html') show(plot)
def plot_dag( functions, targets=None, columns_overriding_functions=None, check_minimal_specification="ignore", selectors=None, labels=True, tooltips=False, plot_kwargs=None, arrow_kwargs=None, edge_kwargs=None, label_kwargs=None, node_kwargs=None, ): """Plot the dag of the tax and transfer system. Parameters ---------- functions : str, pathlib.Path, callable, module, imports statements, dict Functions can be anything of the specified types and a list of the same objects. If the object is a dictionary, the keys of the dictionary are used as a name instead of the function name. For all other objects, the name is inferred from the function name. targets : str, list of str String or list of strings with names of functions whose output is actually needed by the user. columns_overriding_functions : str list of str Names of columns in the data which are preferred over function defined in the tax and transfer system. check_minimal_specification : {"ignore", "warn", "raise"}, default "ignore" Indicator for whether checks which ensure the most minimal configuration should be silenced, emitted as warnings or errors. selectors : str or list of str or dict or list of dict or list of str and dict Selectors allow to you to select and de-select nodes in the graph for visualization. For the full list of options, see the tutorial about `visualization <../docs/tutorials/visualize.ipynb>`_. By default, all nodes are shown. labels : bool, default True Annotate nodes with labels. tooltips : bool, default False Experimental feature which makes the source code of the functions accessible as a tooltip. Sometimes, the tooltip is not properly displayed. plot_kwargs : dict Additional keyword arguments passed to :class:`bokeh.models.Plot`. arrow_kwargs : dict Additional keyword arguments passed to :class:`bokeh.models.Arrow`. For example, change the size of the head with ``{"size": 10}``. edge_kwargs : dict Additional keyword arguments passed to :class:`bokeh.models.MultiLine`. For example, change the color with ``{"fill_color": "green"}``. label_kwargs : dict Additional keyword arguments passed to :class:`bokeh.models.LabelSet`. For example, change the fontsize with ``{"text_font_size": "12px"}``. node_kwargs : dict Additional keyword arguments passed to :class:`bokeh.models.Circle`. For example, change the color with ``{"fill_color": "orange"}``. """ targets = DEFAULT_TARGETS if targets is None else targets targets = parse_to_list_of_strings(targets, "targets") columns_overriding_functions = parse_to_list_of_strings( columns_overriding_functions, "columns_overriding_functions") # Load functions and perform checks. functions, internal_functions = load_user_and_internal_functions(functions) # Create one dictionary of functions and perform check. functions = {**internal_functions, **functions} functions = { k: v for k, v in functions.items() if k not in columns_overriding_functions } _fail_if_targets_not_in_functions(functions, targets) # Partial parameters to functions such that they disappear in the DAG. functions = _mock_parameters_arguments(functions) dag = create_dag(functions, targets, columns_overriding_functions, check_minimal_specification) selectors = [] if selectors is None else _to_list(selectors) plot_kwargs = {} if plot_kwargs is None else plot_kwargs arrow_kwargs = {} if arrow_kwargs is None else arrow_kwargs edge_kwargs = {} if edge_kwargs is None else edge_kwargs label_kwargs = {} if label_kwargs is None else label_kwargs node_kwargs = {} if node_kwargs is None else node_kwargs dag = _select_nodes_in_dag(dag, selectors) dag = _add_url_to_dag(dag) # Even if we do not use the source codes as tooltips, we need to remove the # functions. dag = _replace_functions_with_source_code(dag) plot_kwargs["title"] = _to_bokeh_title( plot_kwargs.get("title", "Tax and Transfer System")) plot = Plot(**{**PLOT_KWARGS_DEFAULTS, **plot_kwargs}) layout = _create_pydot_layout(dag) graph_renderer = from_networkx(dag, layout, scale=1, center=(0, 0)) graph_renderer.node_renderer.glyph = Circle(**{ **NODE_KWARGS_DEFAULTS, **node_kwargs }) graph_renderer.edge_renderer.visible = False for ( _, (start_node, end_node), ) in graph_renderer.edge_renderer.data_source.to_df().iterrows(): (x_start, y_start), (x_end, y_end) = _compute_arrow_coordinates( layout[start_node], layout[end_node]) plot.add_layout( Arrow( end=NormalHead(**{ **ARROW_KWARGS_DEFAULTS, **arrow_kwargs }), x_start=x_start, y_start=y_start, x_end=x_end, y_end=y_end, **{ **EDGE_KWARGS_DEFAULTS, **edge_kwargs }, )) plot.renderers.append(graph_renderer) tools = [BoxZoomTool(), ResetTool()] tools.append(TapTool(callback=OpenURL(url="@url"))) if tooltips: tools.append(HoverTool(tooltips=TOOLTIPS)) plot.add_tools(*tools) if labels: source = ColumnDataSource( pd.DataFrame(layout).T.rename(columns={ 0: "x", 1: "y" })) labels = LabelSet( x="x", y="y", text="index", source=source, **{ **LABEL_KWARGS_DEFAULT, **label_kwargs }, ) plot.add_layout(labels) output_notebook() show(plot) return plot
from bokeh.plotting import figure, output_file, show from bokeh.models import Arrow, OpenHead, NormalHead, VeeHead output_file("arrow.html", title="arrow.py example") p = figure(plot_width=600, plot_height=600, x_range=(-0.1, 1.1), y_range=(-0.1, 0.8)) p.circle(x=[0, 1, 0.5], y=[0, 0, 0.7], radius=0.1, color=["navy", "yellow", "red"], fill_alpha=0.1) p.add_layout(Arrow(end=OpenHead(), x_start=0, y_start=0, x_end=1, y_end=0)) p.add_layout( Arrow(end=NormalHead(), x_start=1, y_start=0, x_end=0.5, y_end=0.7)) p.add_layout(Arrow(end=VeeHead(), x_start=0.5, y_start=0.7, x_end=0, y_end=0)) show(p)
def _create_arrows(fig_handle, plot_width): x0 = plot_width * 0.55 all_arrows = [] for i in range(ATM_MAX_LAYERS + 1): layer_arrows = [] for j in range(ATM_MAX_LAYERS + 1): if i == j: head = NormalHead(fill_color=IR_COLOR_HOT) head2 = NormalHead(fill_color=IR_COLOR_HOT) l_alpha = 1.0 else: l_alpha = 0.8 head = OpenHead(line_color=IR_COLOR_HOT, line_alpha=l_alpha) head2 = OpenHead(line_color=IR_COLOR_HOT, line_alpha=l_alpha) data_src = ColumnDataSource(data=dict( x_start=[x0], x_end=[x0], y_start=[0], y_end=[1])) data_src2 = ColumnDataSource(data=dict( x_start=[x0], x_end=[x0], y_start=[0], y_end=[1])) up_arrow = Arrow(end=head, x_start='x_start', x_end='x_end', y_start='y_start', y_end='y_end', line_color=IR_COLOR_HOT, line_alpha=l_alpha, source=data_src) down_arrow = Arrow(end=head2, x_start='x_start', x_end='x_end', y_start='y_start', y_end='y_end', line_color=IR_COLOR_HOT, line_alpha=l_alpha, source=data_src2) up_arrow.visible = False down_arrow.visible = False if j < i: fig_handle.add_layout(up_arrow) layer_arrows.append((up_arrow, )) elif j == i: fig_handle.add_layout(up_arrow) if i == 0: layer_arrows.append((up_arrow, )) else: fig_handle.add_layout(down_arrow) layer_arrows.append((up_arrow, down_arrow)) else: if i != 0: fig_handle.add_layout(down_arrow) layer_arrows.append((down_arrow, )) all_arrows.append(layer_arrows) return all_arrows
fig.line(x='x', y='y', source=Bottom_Line, color="black", line_width=3) fig.line(x='x', y='y', source=Linking_Line, color="black", line_width=3) spring.plot(fig, width=2) damper.plot(fig, width=2) mass.plot(fig) fig.add_layout( Arrow(end=None, line_color="#E37222", line_width=2, x_start='x1', y_start='y1', x_end='x2', y_end='y2', source=arrow_line)) fig.add_layout( Arrow(end=NormalHead(fill_color="#E37222"), line_color="#A2AD00", line_width=2, x_start='x1', y_start='y1', x_end='x2', y_end='y2', source=arrow_offset)) fig.toolbar.logo = None #removes bokeh logo # time plot hover = HoverTool(tooltips=[("time", "@t s"), ("displacement", "@s m")]) p = figure(title="", y_range=(2,-2), x_range=Range1d(bounds=(0,1000), start=0, end=20), height=550, \ toolbar_location="right", tools=[hover,"ywheel_zoom,xwheel_pan,pan,reset"]) #ywheel_zoom,xwheel_pan,reset, line_1 = p.line(x='t', y='s',
def results(ad_hash): job_ad = JobAd.query.get_or_404(ad_hash) masculine_coded_words, feminine_coded_words = job_ad.list_words() cd = os.getcwd() with open(cd + "/app/wordsDF.pkl", 'rb') as f: words_df = pickle.load(f) HI_words_df = words_df[(abs(words_df.ratio.values) > 10) | (abs(words_df.coef.values) > 2) | ((words_df.coef.values) > 2)] if job_ad.gender == "pink": coded_words = feminine_coded_words elif job_ad.gender == "blue": coded_words = masculine_coded_words else: coded_words = masculine_coded_words + feminine_coded_words label_words_df = words_df[(words_df.word.isin(coded_words)) & (words_df.coef.values > 0)] min_x = HI_words_df.ratio.values.min() min_y = HI_words_df.coef.values.min() max_x = HI_words_df.ratio.values.max() #max_y = HI_words_df.coef.values.max() max_y = 6 p = figure(x_range=(min_x - 40, max_x + 10), y_range=(min_y - 1, max_y + 1), title="High Impact Words in Deodorant Descriptions", plot_width=600, plot_height=600, background_fill_color='#F0F0F0', border_fill_color='#F0F0F0') p.ray(x=[0], y=[0], length=0, angle=0, line_width=1, line_color='black') p.ray(x=[0], y=[0], length=0, angle=np.pi, line_width=1, line_color='black') p.ray(x=[0], y=[0], length=0, angle=np.pi * 3 / 2, line_width=1, line_color='black') p.ray(x=[0], y=[0], length=0, angle=np.pi * 1 / 2, line_width=1, line_color='black') p.scatter(x='ratio', y='coef', alpha=1, size=8, color='deeppink', source=ColumnDataSource( label_words_df[label_words_df.gender == 'f'])) p.scatter(x='ratio', y='coef', alpha=1, size=8, color='deepskyblue', source=ColumnDataSource( label_words_df[label_words_df.gender == 'm'])) p.scatter(x='ratio', y='coef', legend="Female", alpha=0.7, size=4, color='deeppink', source=ColumnDataSource(HI_words_df[HI_words_df.gender == 'f'])) p.scatter(x='ratio', y='coef', legend="Male", alpha=0.7, size=4, color='deepskyblue', source=ColumnDataSource(HI_words_df[HI_words_df.gender == 'm'])) if job_ad.gender == "pink" or job_ad.gender == "purple": labels_f = LabelSet(x='ratio', y='coef', text='word', level='glyph', x_offset=-2, text_align='right', text_font_size="10pt", source=ColumnDataSource( label_words_df[label_words_df.gender == 'f'])) p.add_layout(labels_f) elif job_ad.gender == "blue" or job_ad.gender == "purple": labels_m = LabelSet(x='ratio', y='coef', text='word', level='glyph', x_offset=2, text_font_size="10pt", source=ColumnDataSource( label_words_df[label_words_df.gender == 'm'])) p.add_layout(labels_m) p.yaxis.axis_line_color = None p.xaxis.axis_line_color = None p.yaxis.major_tick_line_color = None p.xaxis.major_tick_line_color = None p.yaxis.minor_tick_line_color = None p.xaxis.minor_tick_line_color = None p.outline_line_color = None p.xaxis.axis_label = "Gender Likelihood Ratio" p.yaxis.axis_label = "Relative Impact on Price" p.yaxis.axis_label_text_font_style = 'bold' p.xaxis.axis_label_text_font_style = 'bold' p.xaxis.axis_label_text_font_size = '1em' p.xaxis.major_label_text_font_size = '1em' p.yaxis.axis_label_text_font_size = '1em' p.yaxis.major_label_text_font_size = '1em' p.title.text_font_size = '1.3em' p.xaxis[0].formatter = PrintfTickFormatter(format="%uX") p.legend.location = "bottom_right" p.legend.label_text_font_size = '1em' p.legend.background_fill_color = '#F0F0F0' p.legend.border_line_color = None p.legend.background_fill_alpha = 0 #p.xgrid.grid_line_color = None #p.ygrid.grid_line_color = None hover = HoverTool(tooltips=[('word', '@word')]) p.add_tools(hover) p.add_layout( Arrow(end=NormalHead(size=10, fill_color='#A9A9A9', line_color='#A9A9A9'), x_start=min_x - 18, y_start=max_y, x_end=min_x - 20, y_end=max_y)) p.add_layout( Arrow(end=NormalHead(size=10, fill_color='#A9A9A9', line_color='#A9A9A9'), x_start=min_x - 22, y_start=max_y - 0.2, x_end=min_x - 22, y_end=max_y - 0.1)) p.add_layout( Arrow(end=NormalHead(size=10, fill_color='#A9A9A9', line_color='#A9A9A9'), x_start=max_x, y_start=max_y, x_end=max_x + 2, y_end=max_y)) p.add_layout( Arrow(end=NormalHead(size=10, fill_color='#A9A9A9', line_color='#A9A9A9'), x_start=min_x - 22, y_start=min_y - 0.2, x_end=min_x - 22, y_end=min_y - 0.3)) notes_f = Label(x=min_x - 16, y=max_y - 0.18, text='More Likely Female', text_color='#A9A9A9') notes_x = Label(x=min_x - 20.5, y=max_y - 0.39, text='Higher Cost', text_align='right', angle=np.pi / 2, text_color='#A9A9A9') notes_y = Label(x=min_x - 19.5, y=min_y, text='Lower Cost', angle=np.pi / 2, text_color='#A9A9A9') notes_m = Label(x=max_x - 2, y=max_y - 0.18, text='More Likely Male', text_align='right', text_color='#A9A9A9') p.add_layout(notes_x) p.add_layout(notes_f) p.add_layout(notes_y) p.add_layout(notes_m) script, div = components(p) resources = INLINE.render() html = render_template('results.html', job_ad=job_ad, masculine_coded_words=masculine_coded_words, feminine_coded_words=feminine_coded_words, explanation=explanations[job_ad.coding], gender=job_ad.gender, plot_script=script, plot_div=div, resources=resources) return encode_utf8(html)
def plot_features(features, start=0, end=None, fontsize="8pt", plot_width=800, plot_height=150, tools="xpan, xwheel_zoom, save", color='#abdda4', rows=3, key='gene'): """Bokeh sequence alignment view""" df = utils.features_to_dataframe(features) #, cds=True) df = df[(df.type != 'region') & (df['type'] != 'source')] df['length'] = df.end - df.start #df['level'] = 1 #df['color'] = random_colors(len(df)) #'green' df['x'] = df.start + df.length / 2 df = df.fillna('') def get_arrow(x): if x.strand == 1: return x.end else: return x.start df['arrow_start'] = df.apply(get_arrow, 1) df['arrow_end'] = df.apply( lambda x: x.arrow_start + 50 if x.strand == 1 else x.arrow_start - 50, 1) #def get_y(x): # df['col'].shift() np.random.seed(8) #df['y'] = np.random.randint(1,9, len(df)) y = list(range(0, rows)) * len(df) df['y'] = y[:len(df)] if end == None: end = df.end.max() + 100 if end > 10000: end = 10000 #print (df[:3]) text = df.gene S = df.start.min() N = df.end.max() + 10 x = list(df.start + df.length / 2) h = 20 source = ColumnDataSource(df) x_range = Range1d(start, end, min_interval=1) viewlen = end - start hover = HoverTool(tooltips=[ ("gene", "@gene"), ("locus_tag", "@locus_tag"), ("product", "@product"), ("strand", "@strand"), ("length", "@length"), ], ) tools = [hover, tools] #sequence text view with ability to scroll along x axis p = figure(title=None, plot_width=plot_width, plot_height=plot_height, x_range=x_range, y_range=(-1, rows), tools=tools, min_border=0, toolbar_location='right') #, lod_factor=1) #display text only at certain zoom level? #print (viewlen) if viewlen < 20000: tags = Text(x="x", y="y", y_offset=-8, text=key, text_align='center', text_color="black", text_font="monospace", text_font_size=fontsize, name="genetext") p.add_glyph(source, tags) #rects rects = Rect(x="x", y="y", width="length", height=.4, fill_color=color, fill_alpha=0.4, name='rects') #arrows arr = Arrow(source=source, x_start="arrow_start", x_end="arrow_end", y_start="y", y_end="y", line_color="black", name='arrows', end=NormalHead(size=8)) p.add_glyph(source, rects) p.add_layout(arr) p.grid.visible = False p.yaxis.visible = False p.xaxis.major_label_text_font_style = "bold" p.yaxis.minor_tick_line_width = 0 p.yaxis.major_tick_line_width = 0 p.toolbar.logo = None p.xaxis.formatter = NumeralTickFormatter(format="(0,0)") return p
y=1942, text="No Olympics in 1940 or 1944", text_align="center", text_baseline="middle", text_font_size="12px", text_font_style="italic", text_color="silver") plot.add_layout(no_olympics_label) x = sprint[sprint.Year == 1900].MetersBack.min() - 0.5 arrow = Arrow(x_start=x, x_end=5, y_start=1900, y_end=1900, line_width=1.5, start=NormalHead(fill_color="black", size=6), end=None) plot.add_layout(arrow) meters_back = Label(x=5, x_offset=10, y=1900, text="Meters behind\n2012 Usain Bolt", text_align="left", text_baseline="middle", text_font_size="13px", text_font_style="bold") plot.add_layout(meters_back) disclaimer = Label(x=0, y=0,
plot_main.outline_line_color = "Black" plot_main.title.text_font_size = "13pt" plot_main.toolbar.logo = None # plot error message if both supports are set to sliding error_label = LabelSet(x='x', y='y', text='name', source=error_msg) plot_main.add_layout(error_label) plot_main.add_glyph(error_msg_frame,Rect(x="x", y="y", width=8, height=1, angle=0, fill_color='red', fill_alpha=0.2)) # plot helper line plot_main.add_glyph(aux_line, aux_line_glyph) # measures beam_measure_doublearrow_glyph = Arrow(start=OpenHead(line_color=c_black, line_width=2, size=8), end=OpenHead(line_color='black',line_width= 2, size=8), x_start=xr_start, y_start=-1.2, x_end=xr_end, y_end=-1.2, line_width=5, line_color=c_black) beam_measure_singlearrow_glyph = Arrow(end=NormalHead(fill_color=c_gray, line_width=1, size=6), x_start=xr_start-0.1, y_start=-0.8, x_end=xr_start+0.8, y_end=-0.8, line_width=1, line_color=c_black) beam_measure_label_source.data = dict(x=[xr_start+0.25, 0.5*(xr_end-xr_start)], y=[-0.7,-1.6], text=["x","L"]) beam_measure_label = LatexLabelSet(x='x', y='y', text='text', source=beam_measure_label_source, level='glyph')#, x_offset=3, y_offset=-15) plot_main.line(x=[xr_start, xr_start], y=[-0.7,-0.9], line_color=c_black) # vertical line for single x-arrow plot_main.add_layout(beam_measure_singlearrow_glyph) plot_main.add_layout(beam_measure_doublearrow_glyph) plot_main.add_layout(beam_measure_label) # graphics for a cold beam snow_images = ["Normal_Force_Rod/static/images/snowflake01.svg", "Normal_Force_Rod/static/images/snowflake02.svg", "Normal_Force_Rod/static/images/snowflake03.svg"]
p.circle(x=[0, 1, 0.5], y=[0, 0, 0.7], radius=0.1, color=["navy", "yellow", "red"], fill_alpha=0.1) p.add_layout( Arrow(end=OpenHead(line_color="firebrick", line_width=4), x_start=0, y_start=0, x_end=1, y_end=0)) p.add_layout( Arrow(end=NormalHead(fill_color="orange"), x_start=1, y_start=0, x_end=0.5, y_end=0.7)) p.add_layout( Arrow(end=VeeHead(size=35), line_color="red", x_start=0.5, y_start=0.7, x_end=0, y_end=0)) show(p)
def plotWithCrosses(self, p=None, title=None, plot_width=800): '''bokeh implementation''' if not self.crosses_added: self.getCrosses() if p is None: TOOLS = "pan,wheel_zoom,box_zoom,zoom_in,zoom_out,hover,reset,save" p = figure(title=title, tools=TOOLS, plot_width=plot_width) p.grid.grid_line_alpha = 0.3 #p.xaxis.axis_label = 'Date' p.yaxis.axis_label = 'Price' p.xaxis.major_label_orientation = math.pi / 4 # This will be used to skip the gap by using numerical index x_replacement_dictionary = { i: date.strftime('%Y-%m-%d %-H:%M') for i, date in enumerate(self.data.index) } p.xaxis.major_label_overrides = x_replacement_dictionary # Plot the MAs data_to_plot = [self.series_name] + self.moving_average_labels colors = default_palette[len(data_to_plot)] for i, data_name in enumerate(data_to_plot): d = self.data[data_name] p.line(self.data['numerical_index'], d, legend=data_name, color=colors[i]) # Plot the arrows indicating crosses goldenX = (self.data['cross'] == 1) deathX = (self.data['cross'] == -1) for ind in self.data[goldenX].index: p.add_layout( Arrow(end=NormalHead(size=10, fill_color="yellowgreen", line_color="yellowgreen"), line_color="yellowgreen", line_width=2, x_start=self.data.loc[ind, 'numerical_index'].astype('float'), x_end=self.data.loc[ind, 'numerical_index'].astype('float'), y_start=self.data.loc[ind, self.long_ma_label] - 0.5, y_end=self.data.loc[ind, self.long_ma_label] - 0.2)) for ind in self.data[deathX].index: p.add_layout( Arrow(end=NormalHead(size=10, fill_color="salmon", line_color="salmon"), line_color="salmon", line_width=2, x_start=self.data.loc[ind, 'numerical_index'].astype('float'), x_end=self.data.loc[ind, 'numerical_index'].astype('float'), y_start=self.data.loc[ind, self.long_ma_label] + 0.5, y_end=self.data.loc[ind, self.long_ma_label] + 0.2)) output_notebook() show(p) return
def getPlot(Pin_Upper_Limit, Pout_Upper_Limit, No_dBm, SImin, n, G, CPo, IIPn, OIPn, DUT, freq): #Plot intercept diagram title = "Interception diagram: " + DUT + ' @ ' + str(freq) + ' MHz' plot = figure(plot_width=800, plot_height=400, title=title) # Plot settings xmin = Pin_Upper_Limit - 20 xmax = IIPn + 10 ymin = No_dBm ymax = OIPn + 10 # Calculations P_in = np.linspace(xmin, xmax, 100) fundamental = P_in + G IMn = PoutIMN(P_in, n, G, IIPn) DR = Pin_Upper_Limit - No_dBm CPi = CPo - G + 1 # Lines plot.line(P_in, fundamental, line_width=2, color="navy", legend_label="Fundamental") # Fundamental plot.line(P_in, IMn, line_width=2, color="red", legend_label="IMn") # IMn level plot.line(P_in, No_dBm, line_width=2, color="orange", legend_label="Noise floor") # Noise floor # Level level_x = np.linspace(xmin, Pin_Upper_Limit, 100) level_y = Pout_Upper_Limit plot.line(level_x, level_y, line_width=2, color="black", line_dash='dotted') # Points plot.circle([IIPn], [OIPn], size=10, color="navy", alpha=0.5) # Intercept point plot.circle([CPi], [CPo], size=10, color="navy", alpha=0.5) # Compression point # Arrows ## Dynamic range arrow shift = 4 plot.add_layout( Arrow(start=NormalHead(size=10), end=NormalHead(size=10), x_start=Pin_Upper_Limit - shift, y_start=No_dBm, x_end=Pin_Upper_Limit - shift, y_end=Pout_Upper_Limit)) ## S/I min arrow plot.add_layout( Arrow(start=NormalHead(size=10), end=NormalHead(size=10), x_start=Pin_Upper_Limit, y_start=Pout_Upper_Limit - SImin, x_end=Pin_Upper_Limit, y_end=Pout_Upper_Limit)) plot.xaxis.axis_label = 'Input Power (dBm)' plot.yaxis.axis_label = 'Output Power (dBm)' plot.legend.location = 'top_left' # Text annotations # Labels with 90 degree rotation source = ColumnDataSource( data=dict(y=[ Pout_Upper_Limit - DR / 2 - 40, Pout_Upper_Limit - DR / 2 - 20, Pout_Upper_Limit - SImin / 2 - 25, Pout_Upper_Limit - SImin / 2 - 10 ], x=[ Pin_Upper_Limit - shift - 2, Pin_Upper_Limit - shift, Pin_Upper_Limit - 2, Pin_Upper_Limit ], names=[ 'Dynamic Range', str("%.1f" % DR) + ' dB', 'Minimum S/I', str(SImin) + ' dB' ])) labels = LabelSet(x='x', y='y', text='names', source=source, angle=90, angle_units='deg', render_mode='canvas') plot.add_layout(labels) # Labels without rotation source = ColumnDataSource(data=dict(y=[CPo + 2, OIPn + 2], x=[CPi - 1, IIPn - 1], names=['CP', 'IP' + str(n)])) labels = LabelSet(x='x', y='y', text='names', source=source, render_mode='canvas') plot.add_layout(labels) return plot
def generateNodeLinkGraph(file): #Reading the file file = file + '.csv' fname = os.path.join(server.config['UPLOAD_FOLDER'], file) f = open(fname, 'r') #Reading first line line1 = f.readline() names = line1[1:].split(';') # Rename duplicates since there are people with the same name seen = {} dupes = [] for index, name in enumerate(names): if name not in seen: seen[name] = 1 else: if seen[name] == 1: dupes.append((index, name)) seen[name] += 1 # add 1, 2 etc after the name for pair in dupes: index = pair[0] name = pair[1] for i in range(seen[name]): names[index] = name + str((i+1)) #print(names[index]) # Read csv df = pd.read_csv(f, names=names, sep=';') # Fix it df = df.reset_index(level=1) names.append("delete") df.columns = names del df["delete"] df.set_index([df.columns], inplace=True) # Get names again for later use names = df.columns.tolist() # Get 150*150 sub matrix since otherwise the plot is very slow.. df = df.head(150)[names[0:150]] names = df.columns.tolist() #Get total amount of nodes N = len(names) node_indices = list(range(N)) #Create list of numeric node indices # Scale for the repeating pattern of the colours scale = math.ceil(N / 256) #Iterate over dataframe and save non-zero edges start = [] #Contains starting node index of each edge end = [] #Contains ending node index of each edge tolerance = 0.75 #Determine which edges are shown and which are not index_count = 0 #Set start node index to 0 for row in df.itertuples(): #For each row in the dataframe index_count += 1 #Increase start node index by 1 element_count = 0 #(Re)set second node index to 0 for element in row: #For each element in each row element_count += 1 #Increase second node index by 1 if type(element) == float: #if element == 1.0: #Code in case for symmetric matrix, effectively halving running time of this loop # break #elif element > tolerance: if element > tolerance and not element == 1.0: start.append(index_count) #Add starting node index to the edge starting list end.append(element_count) #Add ending node index to the edge ending list #Create the plot with two axes, a title and interaction tools #plot = figure(title='Circular Node-Link Diagram', x_range=(0 - (N * 2.1) , N * 2.1), y_range=(0 - (N * 2.1) , N * 2.1), # tools='pan, wheel_zoom, reset', toolbar_location = 'right', frame_height = 400, frame_width = 400, output_backend="webgl") plot = Plot(x_range=Range1d(0 - (N * 2.1) , N * 2.1), y_range=Range1d(0 - (N * 2.1) , N * 2.1), toolbar_location = 'right', frame_height = 400, frame_width = 400, output_backend="webgl") plot.title.text = "Circular Node-Link Diagram" plot.add_tools(PanTool(), BoxZoomTool(), ResetTool()) #Create the graph object graph = GraphRenderer() #Assign the correct data for the edges #graph.edge_renderer.data_source.data = dict( # start = start, # end = end) #graph.edge_renderer.glyph = MultiLine(line_color = Viridis256[200]) #Assign the correct data for the nodes graph.node_renderer.data_source.add(node_indices, 'index') graph.node_renderer.data_source.add(Viridis256 * scale, 'color') graph.node_renderer.glyph = Circle(radius = N * 0.0025, fill_color='color') #Start of circular layout code circ = [i * 2 * math.pi/N for i in node_indices] x = [2 * N * math.cos(i) for i in circ] y = [2 * N * math.sin(i) for i in circ] #Assign the correct x and y values to all nodes graph_layout = dict(zip(node_indices, zip(x, y))) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) #Arrow code test for start_index in start: start_index -= 1 for end_index in end: end_index -= 1 plot.add_layout(Arrow(end = NormalHead(fill_color = Viridis256[200], size = N * 0.1), x_start = x[start_index], y_start = y[start_index], x_end = x[end_index], y_end = y[end_index], line_color = Viridis256[200])) end_index += 1 start_index += 1 #Show the plot plot.renderers.append(graph) script, div = components(plot) return script, div
def show(self, graphstyle='random', graphcolor="connectedOnly", arrows=False, colorGroups=[]): node_indices = list(map(int, self.graphStorage.keys())) plot = figure(title="Network connection graph", x_range=(-1.1, 1.1), y_range=(-1.1, 1.1), tools="", toolbar_location=None) plot.xaxis.visible = False plot.xgrid.visible = False plot.yaxis.visible = False plot.ygrid.visible = False plot.border_fill_color = None plot.outline_line_color = None graph = GraphRenderer() graph.node_renderer.data_source.add(node_indices, 'index') if len(colorGroups) != 0: graphcolor = "perGroup" if graphcolor == "viridis": graph.node_renderer.data_source.add(viridis(len(node_indices)), 'color') elif graphcolor == "connectedOnly": outputArr = [] for node in self.graphStorage: if len(self.graphStorage[node]) > 0: outputArr.append('green') else: outputArr.append('black') graph.node_renderer.data_source.add(outputArr, 'color') elif graphcolor == "perGroup": totalColors = viridis(len(colorGroups)) outputArr = [] for key, array in enumerate(colorGroups): for x in array: outputArr.insert(x, totalColors[key]) graph.node_renderer.data_source.add(outputArr, 'color') else: graph.node_renderer.data_source.add([graphcolor] * len(node_indices), 'color') graph.node_renderer.glyph = Circle(radius=.05, fill_color='color') graph.edge_renderer.glyph = MultiLine(line_color="black", line_alpha=0.8, line_width=5) x = [] y = [] for key in self.graphStorage: for num in self.graphStorage[key]: x.append(key) y.append(num) graph.edge_renderer.data_source.data = dict(start=x, end=y) if graphstyle == "circle": circ = [i * 2 * math.pi / len(node_indices) for i in node_indices] xpos = [math.cos(i) for i in circ] ypos = [math.sin(i) for i in circ] elif graphstyle == "square": pointDistribation = 4 / len(node_indices) if (len(node_indices) < 4): pointDistribation = 1 totalTrack = 0 counter = 0 xpos = [] ypos = [] while (counter < len(node_indices)): if totalTrack <= 1: xPosition = (totalTrack) - .5 xpos.append(xPosition) ypos.append(-.5) elif totalTrack > 1 and totalTrack <= 2: yPosition = (totalTrack) - 1.5 xpos.append(.5) ypos.append(yPosition) elif totalTrack > 2 and totalTrack <= 3: xPosition = (totalTrack) - 2.5 xpos.append(-xPosition) ypos.append(.5) elif totalTrack > 3 and totalTrack <= 4: yPosition = (totalTrack) - 3.5 xpos.append(-.5) ypos.append(-yPosition) totalTrack += pointDistribation counter += 1 elif graphstyle == "random": xpos = [uniform(-1, 1) for i in node_indices] ypos = [uniform(-1, 1) for i in node_indices] graph_layout = dict(zip(node_indices, zip(xpos, ypos))) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) source = ColumnDataSource( dict(xvals=xpos, yvals=ypos, name=node_indices)) labels = LabelSet(x='xvals', y='yvals', text='name', text_align='center', level='glyph', text_baseline='middle', source=source, text_color='white') plot.renderers.append(graph) plot.add_layout(labels) if arrows: for index, link in enumerate(x): plot.add_layout( Arrow(start=NormalHead(size=10), end=NormalHead(size=10), x_start=graph_layout[link][0], y_start=graph_layout[link][1], x_end=graph_layout[y[index]][0], y_end=graph_layout[y[index]][1])) output_file('graph.html') show(plot)
columns=columns2, reorderable=False, sortable=False, selectable=False, index_position=None, width=400, height=400) description_filename = join(dirname(__file__), "description.html") description = LatexDiv(text=open(description_filename).read(), render_as_text=False, width=1200) # adding the vectors to the plot Vector1_glyph = Arrow(end=NormalHead(line_color="#A2AD00", fill_color="#A2AD00", line_width=2, size=10), x_start='xS', y_start='yS', x_end='xE', y_end='yE', source=Vector1_source, line_color="#A2AD00", line_width=3) Vector2_glyph = Arrow(end=NormalHead(line_color="#E37222", fill_color="#E37222", line_width=2, size=10), x_start='xS', y_start='yS', x_end='xE',
xE = Vector1 * cos(theta1) yE = Vector1 * sin(theta1) #Vector_source.data = dict(xS=[0],yS=[0],xE=[xE],yE=[yE]) Vector_source.stream(dict(xS=[0], yS=[0], xE=[xE], yE=[yE]), rollover=1) V_label_source.data = dict(x=[xE + 3], y=[yE - 3], V1=[ 'F', ]) ################################### # Figures ################################### Vector1_glyph = Arrow(end=NormalHead(line_color="#A2AD00", fill_color="#A2AD00", line_width=2, size=15), x_start='xS', y_start='yS', x_end='xE', y_end='yE', source=Vector_source, line_color="#A2AD00", line_width=7) Vector2_glyph = Arrow(end=NormalHead(line_color="#0065BD", fill_color="#0065BD", line_width=2, size=15), x_start='xS', y_start='yS', x_end='xE',
select = Select(title="Pokemon:", value=df['name'].tolist()[0], options=df['name'].tolist()) # Create the "Overall" plot. source_overall = ColumnDataSource(df_ranked[['name', 'votes', 'generation', 'generation_color', 'ranking_overall', 'ranking_generation', 'sprite_source']]) pokemon_names = source_overall.data['name'] pokemon_votes = source_overall.data['votes'] # Notice that initializing the figure with y_range=pokemon_names # doesn't allow the option to bound the plot. p_overall = figure(y_range=FactorRange(factors=pokemon_names, bounds=(0, len(pokemon_names))), x_axis_label='Votes', plot_height=PLOT_HEIGHT, tools=tools) r_overall = p_overall.hbar(y='name', left=0, right='votes', height=1, color='generation_color', source=source_overall) p_overall.x_range = Range1d(0, max(pokemon_votes)*1.05, bounds=(0, max(pokemon_votes)*1.05)) p_overall.ygrid.grid_line_color = None y_coord = len(df_ranked) - initial_ranking_overall + 0.5 arrow_overall = Arrow(end=NormalHead(line_color='red', fill_color='red', line_width=0, size=10, line_alpha=0.75, fill_alpha=0.75), line_color='red', line_width=2.5, line_alpha=0.75, x_start=initial_votes + max(pokemon_votes)*0.05, x_end=initial_votes, y_start=y_coord, y_end=y_coord) p_overall.add_layout(arrow_overall) legend = Legend(items=[ LegendItem(label='1', renderers=[r_overall], index=6), LegendItem(label='2', renderers=[r_overall], index=37), LegendItem(label='3', renderers=[r_overall], index=1), LegendItem(label='4', renderers=[r_overall], index=10), LegendItem(label='5', renderers=[r_overall], index=2), LegendItem(label='6', renderers=[r_overall], index=14), LegendItem(label='7', renderers=[r_overall], index=8), ], title='Generation', location='bottom_right') p_overall.add_layout(legend)