def create_graph(): #Find the layout and color choice if radio_layout.active == 0: lay = 'WDegreepos' elif radio_layout.active == 1: lay = 'bwcentralpos' else: lay = 'ccentralpos' if radio_color.active == 0: col = 'DegCol' elif radio_color.active == 1: col = 'Colbw' elif radio_color.active == 2: col = 'friend' elif radio_color.active == 3: col = 'reviewcount' else: col = 'comprank' # Create Network view graph = GraphRenderer() graph.node_renderer.data_source.data = nodes_df(G, col) graph.edge_renderer.data_source.data = edges_df(G) graph.node_renderer.glyph = Circle(size='size', fill_color='Col', line_color="black", line_alpha=0.1, fill_alpha=1) graph.edge_renderer.glyph = MultiLine(line_alpha='alpha', line_width=0.1, line_color="#d8b7a4") graph_layout = dict(nx.get_node_attributes(G, lay)) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) # Glyph properties on selection graph.selection_policy = NodesAndLinkedEdges() graph.inspection_policy = EdgesAndLinkedNodes() graph.node_renderer.selection_glyph = Circle(size=12, fill_color='#0A5EB6', line_color="#002217") graph.edge_renderer.selection_glyph = MultiLine(line_color="#2972BE", line_width=0.5, line_alpha=0.4) # Adding graph to plot plot = figure(title="Yelp Users Layout", x_range=(-6.5, 6.5), y_range=(-6.5, 6.5), plot_width=525, plot_height=525, toolbar_location="above") plot.outline_line_alpha = 0 plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.xaxis.visible = False plot.yaxis.visible = False plot.renderers.append(graph) # Adding graph return row(plot)
def _setup_graph_renderer(self, circle_size, draw_components): # The renderer will have the actual logic for drawing graph_renderer = GraphRenderer() # Saving vertices in an arbitrary but persistent order self.vertex_list = list(self.graph.vertices.keys()) # Add the vertex data as instructions for drawing nodes graph_renderer.node_renderer.data_source.add( [vertex.label for vertex in self.vertex_list], 'index') colors = (self._get_connected_component_colors() if draw_components else self._get_random_colors()) graph_renderer.node_renderer.data_source.add(colors, 'color') # And circles graph_renderer.node_renderer.glyph = Circle(size=circle_size, fill_color='color') graph_renderer.node_renderer.hover_glyph = Circle( size=circle_size, fill_color=Category20[20][9]) graph_renderer.node_renderer.selection_glyph = Circle( size=circle_size, fill_color=Category20[20][6]) # Add the edge [start, end] indices as instructions for drawing edges graph_renderer.edge_renderer.data_source.data = self._get_edge_indexes( ) self.randomize() # Randomize vertex coordinates, and set as layout graph_renderer.layout_provider = StaticLayoutProvider( graph_layout=self.pos) # Attach the prepared renderer to the plot so it can be shown graph_renderer.selection_policy = NodesAndLinkedEdges() graph_renderer.inspection_policy = EdgesAndLinkedNodes() self.plot.renderers.append(graph_renderer) print(graph_renderer.node_renderer) tool = PointDrawTool(renderers=[graph_renderer.node_renderer]) self.plot.add_tools(tool)
def _setup_graph_renderer(self, circle_size): # The renderer will have the actual logic for drawing graph_renderer = GraphRenderer() # Add the vertex data as instructions for drawing nodes\ graph_renderer.node_renderer.data_source.add( [x.label for x in self.graph.vertices.values()], 'index') # Nodes will be random colors self._color_connections(self.graph) graph_renderer.node_renderer.data_source.add(self._assign_colors(), 'color') # And circles graph_renderer.node_renderer.glyph = Circle(size=circle_size, fill_color='color') graph_renderer.node_renderer.selection_glyph = Circle( size=circle_size * 2, fill_color='color') graph_renderer.node_renderer.hover_glyph = Circle(size=circle_size * 2, fill_color='color') # And edges graph_renderer.edge_renderer.glyph = MultiLine(line_color='color', line_alpha=0.8, line_width=2) graph_renderer.edge_renderer.selection_glyph = MultiLine( line_color='color', line_width=5) graph_renderer.edge_renderer.hover_glyph = MultiLine( line_color='color', line_width=5) # Add the edge [start, end] indices as instructions for drawing edges graph_renderer.edge_renderer.data_source.data = self._get_edge_indexes( ) self._assign_pos() # Randomize vertex coordinates, and set as layout graph_renderer.layout_provider = StaticLayoutProvider( graph_layout=self.pos) # Set 'dem policies, bruh graph_renderer.selection_policy = NodesAndLinkedEdges() graph_renderer.inspection_policy = EdgesAndLinkedNodes() # Attach the prepared renderer to the plot so it can be shown self.plot.renderers.append(graph_renderer) self._setup_labels()
def Weighted(doc): args = doc.session_context.request.arguments file = args.get('file')[0] file = str(file.decode('UTF-8')) try: dfread = pd.read_csv("media/" + file, sep=';') print('Loaded data succesfully') except: raise Exception("File does not exist") dfSort = dfread.sort_index() nArr = dfread.index.values dfArr = dfread.values nArrSort = dfSort.index.values nArrSortND = np.asarray(list(dict.fromkeys(nArrSort))) G = nx.Graph() for i in range(len(nArrSortND)): G.add_node(nArrSortND[i]) for x in range(0, len(dfArr) - 1): xVal = x + 1 for y in range(0, x): if dfArr[xVal][y] > 0.0: G.add_edge(nArr[xVal], nArr[y], weight=dfArr[xVal][y]) start_edge = [start_edge for (start_edge, end_edge) in G.edges()] end_edge = [end_edge for (start_edge, end_edge) in G.edges()] weight = list(nx.get_edge_attributes(G, 'weight').values()) edge_df = pd.DataFrame({ 'source': start_edge, 'target': end_edge, 'weight': weight }) nodesEdges = list( dict.fromkeys( np.append(edge_df['source'].values, edge_df['target'].values))) nodesEdges.sort() nodesEdgesSort = np.asarray(nodesEdges) noEdgesArr = [] noEdgesArrNum = [] for i in range(len(nArrSortND)): if nArrSortND[i] not in nodesEdgesSort: noEdgesArr.append(nArrSortND[i]) noEdgesArrNum.append(i) G.remove_nodes_from(noEdgesArr) G_source = from_networkx(G, nx.circular_layout, scale=2, center=(0, 0)) graph = GraphRenderer() # Update loop def update(): selected_array = [] for i in range(len(edge_df)): if edge_df['source'][i] == select.value or edge_df['target'][ i] == select.value: selected_array.append(edge_df.loc[[i]]) selected_df = pd.concat(selected_array) subArr = selected_df.index.values subArrVal = selected_df.values sub_G = nx.Graph() sub_G.clear() for i in range(len(nodesEdgesSort)): sub_G.add_node(nodesEdgesSort[i]) for p in range(len(selected_df)): sub_G.add_edge(selected_df['source'][subArr[p]], selected_df['target'][subArr[p]], weight=selected_df['weight'][subArr[p]]) size = [] alpha = [] weightEdge = [] alpha_hover = [] width = [] edgeName = [] line_color = [] i = 0 k = 0 multiplier = 5 / max(selected_df['weight']) for p in range(len(nArrSortND)): if p not in noEdgesArrNum: if nArrSortND[p] == select.value: size.append(25) else: if nodesEdgesSort[k] in subArrVal: if selected_df['source'][subArr[i]] == select.value: alpha.append((sub_G[select.value][ selected_df['target'][subArr[i]]]['weight']) / (2 / max(selected_df['weight']))) weightEdge.append(sub_G[select.value][ selected_df['target'][subArr[i]]]['weight']) alpha_hover.append(1) width.append(multiplier * sub_G[select.value][ selected_df['target'][subArr[i]]]['weight']) line_color.append('#FF0000') edgeName.append([select.value, nodesEdgesSort[k]]) size.append(5 * multiplier * sub_G[select.value][ selected_df['target'][subArr[i]]]['weight']) else: alpha.append((sub_G[select.value][ selected_df['source'][subArr[i]]]['weight']) / (2 / max(selected_df['weight']))) weightEdge.append(sub_G[select.value][ selected_df['source'][subArr[i]]]['weight']) alpha_hover.append(1) width.append(multiplier * sub_G[select.value][ selected_df['source'][subArr[i]]]['weight']) line_color.append('#FF0000') edgeName.append([select.value, nodesEdgesSort[k]]) size.append(5 * multiplier * sub_G[select.value][ selected_df['source'][subArr[i]]]['weight']) i += 1 else: alpha.append(None) weightEdge.append(None) alpha_hover.append(None) width.append(None) line_color.append(None) edgeName.append([select.value, nodesEdgesSort[k]]) size.append(3) k += 1 sub_graph = from_networkx(sub_G, nx.circular_layout, scale=2, center=(0, 0)) tempnArrSortND1 = nodesEdgesSort[(np.where( nodesEdgesSort == select.value)[0][0]):] tempnArrSortND2 = nodesEdgesSort[:(np.where( nodesEdgesSort == select.value)[0][0])] newnArrSortND = np.append(tempnArrSortND1, tempnArrSortND2) nodeSource = ColumnDataSource(data=dict( size=size, index=nodesEdgesSort, )) edgeSource = ColumnDataSource(data=dict( line_alpha=alpha, line_weight=weightEdge, line_alpha_hover=alpha_hover, line_width=width, line_color=line_color, index=edgeName, start=[select.value] * (len(nodesEdgesSort) - 1), end=newnArrSortND[1:], )) sub_graph.edge_renderer.data_source = edgeSource sub_graph.node_renderer.data_source = nodeSource graph.edge_renderer.data_source.data = sub_graph.edge_renderer.data_source.data graph.node_renderer.data_source.data = sub_graph.node_renderer.data_source.data graph.node_renderer.data_source.add(size, 'size') def selected_points(attr, old, new): selected_idx = graph.node_renderer.selected.indices # does not work print(selected_idx) select = Select(title='names', options=nodesEdgesSort.tolist(), value=nodesEdgesSort[0]) select.on_change('value', lambda attr, old, new: update()) positions = nx.circular_layout(G) plot = figure(title="Meetup Network Analysis", x_range=(-1.1, 1.1), y_range=(-1.1, 1.1), tools="pan,wheel_zoom,box_select,reset,box_zoom", plot_width=600, plot_height=600) graph.layout_provider = StaticLayoutProvider(graph_layout=positions) graph.node_renderer.glyph = Circle(size='size', fill_color="#FCFCFC") graph.node_renderer.selection_glyph = Circle(size='size', fill_color="#000000") graph.node_renderer.hover_glyph = Circle(size='size', fill_color="#22A784") graph.edge_renderer.glyph = MultiLine(line_color='line_color', line_alpha='line_alpha', line_width='line_width') graph.edge_renderer.selection_glyph = MultiLine( line_color='line_color', line_alpha='line_alpha_hover', line_width='line_width') graph.edge_renderer.hover_glyph = MultiLine(line_color='line_color', line_alpha='line_alpha_hover', line_width='line_width') graph.inspection_policy = NodesAndLinkedEdges() and EdgesAndLinkedNodes() graph.selection_policy = NodesAndLinkedEdges() plot.renderers.append(graph) plot.tools.append( HoverTool(tooltips=[("index", "@index"), ("weight", "@line_weight")])) layout = column(select, plot) graph.node_renderer.data_source.selected.on_change("indices", selected_points) doc.add_root(layout) update()
'mean_degree_centrality' : [np.mean(np.array(node_source.data['degree_centrality'])[selected_idx])], 'mean_rel_closeness_centrality' : [np.mean(np.array(node_source.data['rel_closeness_centrality'])[selected_idx])]} # Slider parameters which changes values to update the graph slider = RangeSlider(title="Weights", start=0, end=1, value=(0.25, 0.75), step=0.10) slider.on_change('value', lambda attr, old, new: update()) # Plot object which is updated plot = figure(title="Meetup Network Analysis", x_range=(-1.4,2.6), y_range=(-2.0,2.0), tools = "pan,wheel_zoom,box_select,reset,box_zoom,crosshair", plot_width=800, plot_height=700) # Assign layout for nodes, render graph, and add hover tool graph.node_renderer.data_source.selected.on_change("indices", selected_points) graph.layout_provider = StaticLayoutProvider(graph_layout=positions) graph.node_renderer.glyph = Circle(size='node_size', fill_color='node_color') graph.selection_policy = NodesOnly() plot.renderers.append(graph) plot.tools.append(HoverTool(tooltips=[('Name', '@index')])) # Create Summary Data Table num_format = NumberFormatter(format="0.00") summary_table_title = Div(text="""<b>Summary Statistics</b>""", width=525, height=10) summary_table_cols = [TableColumn(field='summary_stats', title="SummaryStats"), TableColumn(field='mean_member_count', title="Member Count",formatter=num_format), TableColumn(field='mean_degree_centrality', title="Degree Centrality",formatter=num_format), TableColumn(field='mean_rel_closeness_centrality', title="Rel. Closeness Centrality",formatter=num_format)] summary_data_table = DataTable(source=summary_data_table_source, columns=summary_table_cols, width=525, height=80) # Create Data Table data_table_cols = [TableColumn(field="group_name", title="Node Name"),
def show(self): node_indices = [ self.graph.vertices[vertex].value for vertex in self.graph.vertices ] # edge__start = [ # self.graph.vertices[vertex].value for vertex in self.graph.vertices] nodes__and__edges = [ tuple((self.graph.vertices[vertex].value, self.graph.vertices[vertex].edges)) for vertex in self.graph.vertices ] # print('\n vertes: ', edge__start) print('\n nodes__and__edges: ', nodes__and__edges) plot = figure( title="Graph Layout", x_range=(-1, 10), y_range=(-1, 10)) # tools="pan,lasso_select,box_select,poly_select", graph = GraphRenderer() graph.node_renderer.data_source.add(node_indices, 'index') graph.node_renderer.data_source.add([ self.graph.vertices[vertex].color for vertex in self.graph.vertices ], 'color') r = 30 graph.node_renderer.glyph = Circle(size=r, fill_color='color') graph.node_renderer.selection_glyph = Circle( size=r, fill_color=Spectral4[2]) # make the shape of the node selectable graph.node_renderer.hover_glyph = Circle( size=r, fill_color=Spectral4[1]) # hover effect on node start_i = [] end_i = [] for vertex in self.graph.vertices: for end_point in self.graph.vertices[vertex].edges: start_i.append(vertex) end_i.append(end_point) graph.edge_renderer.data_source.data = dict(start=start_i, end=end_i) graph.edge_renderer.glyph = MultiLine( line_color="#CCCCCC", line_alpha=0.8, line_width=5) # make the shape of the edge graph.edge_renderer.selection_glyph = MultiLine( line_color=Spectral4[2], line_width=5) # make the shape of the edge selectable graph.edge_renderer.hover_glyph = MultiLine( line_color=Spectral4[1], line_width=5) # hover effect on node x = [self.graph.vertices[vertex].x for vertex in self.graph.vertices] y = [self.graph.vertices[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) # will cause the start and end nodes of an edge to also be inspected upon hovering an edge with the HoverTool graph.inspection_policy = EdgesAndLinkedNodes() # will cause a selected node to also select the associated edges graph.selection_policy = NodesAndLinkedEdges() plot.renderers.append(graph) labelSource = ColumnDataSource(data=dict(x=x, y=y, names=node_indices)) labels = LabelSet(x='x', y='y', text='names', level='glyph', text_align='center', text_baseline='middle', source=labelSource, render_mode='canvas') # calculate the ave distance, from starting_node (x, y) to ending node (x, y) w_x = [((self.graph.vertices[end_i[i]].x - self.graph.vertices[start_i[i]].x) / 2) + self.graph.vertices[start_i[i]].x for (i, x) in enumerate(start_i)] w_y = [((self.graph.vertices[end_i[i]].y - self.graph.vertices[start_i[i]].y) / 2) + self.graph.vertices[start_i[i]].y for (i, x) in enumerate(start_i)] # calculate wighted edge w_name = [abs(end_i[i] - start_i[i]) for (i, x) in enumerate(start_i)] weight_labelSource = ColumnDataSource( data=dict(x=w_x, y=w_y, names=w_name)) weight_labels = LabelSet(x='x', y='y', text='names', text_color="red", level='glyph', text_align='center', text_baseline='middle', source=weight_labelSource, render_mode='canvas') plot.add_layout(labels) plot.add_layout(weight_labels) plot.add_tools(HoverTool(tooltips=None), TapTool(), BoxSelectTool()) # add the hover output_file('graph.html') show(plot)
for edge_path, angles in zip(edge_list, angle_list): sx, sy = graph_layout[edge_path[0]] ex, ey = graph_layout[edge_path[1]] input_angle, output_angle, d = angles bezier_xs, bezier_ys = get_bezier_points([[sx, sy], [ex, ey]], input_angle, output_angle, d, num_points=100) xs.append(bezier_xs) ys.append(bezier_ys) graph.edge_renderer.data_source.data['xs'] = xs graph.edge_renderer.data_source.data['ys'] = ys graph.selection_policy = NodesAndLinkedEdges() graph.inspection_policy = EdgesAndLinkedNodes() plot.renderers.append(graph) source = ColumnDataSource( data=dict(x_pos=x, y_pos=y, labels=['σ₀', 'σ₁', 'σ₂'])) # add labels labels = LabelSet(x='x_pos', y='y_pos', text='labels', level='guide', x_offset=-15, y_offset=-15, source=source,
def make_figure(nodes, edges, correlation_edges, pos): # define gplot gplot = figure(title=None, x_range=(-2, 2), y_range=(-2, 2), tools="reset,save", plot_width=900, plot_height=900, match_aspect=False) graph = GraphRenderer() # add nodes light_node = Ellipse(height=RADIUS, width=RADIUS, fill_color="color", line_color="#000000", line_width=5) heavy_node = Ellipse(height=RADIUS, width=RADIUS, fill_color="color", line_color="#000000", line_width=7) for k in nodes: graph.node_renderer.data_source.add(nodes[k], k) graph.node_renderer.glyph = light_node graph.node_renderer.hover_glyph = heavy_node graph.node_renderer.selection_glyph = heavy_node graph.node_renderer.nonselection_glyph = light_node # add directed edges graph.edge_renderer.name = "edges" for k in correlation_edges: graph.edge_renderer.data_source.add(correlation_edges[k], k) light_edge = MultiLine(line_width="width", line_color="color", line_alpha="alpha") heavy_edge = MultiLine(line_width="width", line_color="color", line_alpha=1) graph.edge_renderer.glyph = light_edge graph.edge_renderer.hover_glyph = heavy_edge graph.edge_renderer.selection_glyph = light_edge graph.edge_renderer.nonselection_glyph = light_edge # arrows arrow = NormalHead(fill_color="#000000", line_color=None, size=8) arrow_source = ColumnDataSource(dict(x_start=[], y_start=[], x_end=[], y_end=[])) gplot.add_layout( Arrow( end=arrow, source=arrow_source, x_start="x_start", y_start="y_start", x_end="x_end", y_end="y_end" ) ) # add labels p_ind = np.linspace(0, 1-1/len(pos), len(pos)) * np.pi * 2 xr = 1.1 * np.cos(p_ind) yr = 1.1 * np.sin(p_ind) rad = np.arctan2(yr, xr) gplot.text(xr, yr, nodes["index"], angle=rad, text_font_size="9pt", text_align="left", text_baseline="middle") # render graph.layout_provider = StaticLayoutProvider(graph_layout=pos) graph.inspection_policy = EdgesAndLinkedNodes() graph.selection_policy = NodesAndLinkedEdges() # widgets edges_original = ColumnDataSource(edges) slider = Slider(start=0.0, end=1.0, value=0.0, step=0.1, title="absolute correlation coefficient is greater than") checkbox = CheckboxButtonGroup( labels=EDGE_LABELS, active=[0] ) callback = CustomJS( args=dict( graph=graph, edges_original=edges_original, arrow_source=arrow_source, checkbox=checkbox, slider=slider ), code=""" var e = graph.edge_renderer.data_source.data; var n = graph.node_renderer.data_source.data; var a = arrow_source.data; var o = edges_original.data; var cb = checkbox.active; var sv = slider.value; var ns = graph.node_renderer.data_source.selected.indices; if (ns.length > 0) { var nn = n['index'][ns[0]]; for (var key in o) { var vals = []; for (var i = 0; i < o['start'].length; ++i) { if ((o['start'][i] == nn || o['end'][i] == nn) && (Math.abs(o['r'][i]) > sv) && (cb.indexOf(o['type'][i]) > -1)) { vals.push(o[key][i]); } } e[key] = vals; } a['x_start'].length = 0; a['y_start'].length = 0; a['x_end'].length = 0; a['y_end'].length = 0; for (var i = 0; i < o['start'].length; ++i) { if ((o['start'][i] == nn || o['end'][i] == nn) && (Math.abs(o['r'][i]) > sv) && (cb.indexOf(o['type'][i]) > -1)) { if (o['e_arrow'][i] === 1) { var l = o['xs'][i].length; a['x_start'].push(o['xs'][i][l - 2]); a['y_start'].push(o['ys'][i][l - 2]); a['x_end'].push(o['xs'][i][l - 1]); a['y_end'].push(o['ys'][i][l - 1]); } if (o['b_arrow'][i] === 1) { a['x_start'].push(o['xs'][i][1]); a['y_start'].push(o['ys'][i][1]); a['x_end'].push(o['xs'][i][0]); a['y_end'].push(o['ys'][i][0]); } } } } else { for (var key in o) { var vals = []; for (var i = 0; i < o['start'].length; ++i) { if ((Math.abs(o['r'][i]) > sv) && (cb.indexOf(o['type'][i]) > -1)) { vals.push(o[key][i]); } } e[key] = vals; } a['x_start'].length = 0; a['y_start'].length = 0; a['x_end'].length = 0; a['y_end'].length = 0; for (var i = 0; i < o['start'].length; ++i) { if ((Math.abs(o['r'][i]) > sv) && (cb.indexOf(o['type'][i]) > -1)) { if (o['e_arrow'][i] === 1) { var l = o['xs'][i].length; a['x_start'].push(o['xs'][i][l - 2]); a['y_start'].push(o['ys'][i][l - 2]); a['x_end'].push(o['xs'][i][l - 1]); a['y_end'].push(o['ys'][i][l - 1]); } if (o['b_arrow'][i] === 1) { a['x_start'].push(o['xs'][i][1]); a['y_start'].push(o['ys'][i][1]); a['x_end'].push(o['xs'][i][0]); a['y_end'].push(o['ys'][i][0]); } } } } graph.edge_renderer.data_source.change.emit(); arrow_source.change.emit(); """) slider.js_on_change("value", callback) checkbox.js_on_change("active", callback) graph.node_renderer.data_source.selected.js_on_change("indices", callback) hover = HoverTool( tooltips=[ ("node", "@start"), ("node", "@end"), ("type", "@type_name"), ("pearson", "@r{0.3f}"), ("p-value", "@pval"), ], renderers=[graph] ) gplot.background_fill_color = BACKGROUND gplot.xgrid.grid_line_color = None gplot.ygrid.grid_line_color = None gplot.axis.visible = False gplot.add_tools(hover, TapTool()) gplot.toolbar.logo = None gplot.toolbar_location = None gplot.border_fill_color = None gplot.outline_line_color = None gplot.renderers.append(graph) return { "gplot": gplot, "widgets": widgetbox(slider, checkbox, width=450) }
def create_graph(): #Find the layout and color choice if radio_layout.active == 0: lay = 'WDegreepos' elif radio_layout.active == 1: lay = 'bwcentralpos' else: lay = 'ccentralpos' if radio_color.active == 0: col = 'DegCol' elif radio_color.active == 1: col = 'Colbw' elif radio_color.active == 2: col = 'friend' elif radio_color.active == 3: col = 'reviewcount' else: col = 'comprank' # Create Network view graph = GraphRenderer() graph.node_renderer.data_source.data = nodes_df(G, col) graph.edge_renderer.data_source.data = edges_df(G) graph.node_renderer.glyph = Circle(size='size', fill_color='Col', line_color="black", line_alpha = 0.1, fill_alpha=1) graph.edge_renderer.glyph = MultiLine(line_alpha='alpha', line_width=0.1, line_color="#d8b7a4") graph_layout = dict(nx.get_node_attributes(G, lay)) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) # Glyph properties on selection graph.selection_policy = NodesAndLinkedEdges() graph.inspection_policy = EdgesAndLinkedNodes() graph.node_renderer.selection_glyph = Circle(size=12, fill_color='#0A5EB6', line_color="#002217") graph.edge_renderer.selection_glyph = MultiLine(line_color="#2972BE", line_width=0.5, line_alpha=0.4) x = ['1','2','3','4','5'] y = [0,0,0,0,0] s2 = ColumnDataSource(data=dict(x=x, y=y)) hplot = figure(title="Rating by user", y_axis_label='% of Ratings Given', x_axis_label="Ratings", toolbar_location=None, tools="", x_range=['1','2','3','4','5'], y_range=(0, 50), plot_width=250, plot_height=250) hplot.vbar(x='x', top='y', source=s2, width=1, line_color="#ffffff") hplot.outline_line_alpha = 0 hplot.yaxis.axis_line_color = "#a7a7a7" hplot.yaxis.major_tick_line_color = "#a7a7a7" hplot.yaxis.minor_tick_line_color = None hplot.ygrid.grid_line_color = None hplot.xgrid.grid_line_color = None hplot.xaxis.axis_line_color = "#a7a7a7" hplot.xaxis.minor_tick_line_color = None hplot.xaxis.major_tick_line_color = "#a7a7a7" # callback = CustomJS(args=dict(source=graph.node_renderer.data_source), code = # """ # console.log(cb_obj) # var inds = cb_data.source.selected['1d'].indices # window.alert(inds) # """) true_source = ColumnDataSource(data=dict(x=[0,1,10,35,10,0,5,25,8,3,3,4,10,7,1])) callback = CustomJS(args=dict(s1=graph.node_renderer.data_source,s2=s2, ts=true_source), code= """ var inds = cb_data.source.selected['1d'].indices // .source is an on object of cb_data //window.alert(inds) var data = s2.data var tsdata = ts.data var ynew = tsdata['x'] data['y'] = [] if (inds<150){ for (var i = 0; i < 5; i++) { data['y'].push(ynew[i+5]) } } else if (inds <300){ for (var i = 0; i < 5; i++) { data['y'].push(ynew[i]) } } else { for (var i = 0; i < 5; i++) { data['y'].push(ynew[i+10]) } } s2.change.emit(); """) # Adding graph to plot plot = figure(title="Yelp Users Layout", x_range=(-6.5, 6.5), y_range=(-6.5, 6.5), plot_width=525, plot_height=525, toolbar_location="above") plot.outline_line_alpha = 0 plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.xaxis.visible = False plot.yaxis.visible = False plot.renderers.append(graph) # Adding graph plot.add_tools(TapTool(callback=callback)) return row(plot,hplot)
def drawInteractiveNW(df, nw=None, edgesdf=None, color_attr="Cluster", label_attr="name", title="Interactive Network Visualization", plotfile=None, inline=False): def buildNetworkX(linksdf, id1='Source', id2='Target', directed=False): linkdata = [(getattr(link, id1), getattr(link, id2)) for link in linksdf.itertuples()] g = nx.DiGraph() if directed else nx.Graph() g.add_edges_from(linkdata) return g if inline: output_notebook() if plotfile: output_file(plotfile+".html") if nw is None: if edgesdf is None: print("Must specify either network or edges DataFrame") return nw = buildNetworkX(edgesdf) node_colors, edge_colors, attr_colors = dn.getCategoricalColors(nw, df, color_attr, None, True, None) xmin = df['x'].min() xmax = df['x'].max() ymin = df['y'].min() ymax = df['y'].max() rng = max((xmax-xmin), (ymax-ymin)) nNodes = len(df) size = 4*rng/math.sqrt(nNodes) node_indices = list(range(nNodes)) tooltips=[ (label_attr, "@"+label_attr), (color_attr, "@"+color_attr) ] plot = figure(title=title, plot_width=800, plot_height=800, x_range=(xmin-size, xmax+size), y_range=(ymin-size, ymax+size), tools="pan,wheel_zoom,box_zoom,reset", toolbar_location="right", output_backend="webgl") plot.add_tools(HoverTool(tooltips=tooltips), TapTool(), BoxSelectTool()) graph = GraphRenderer() # set node renderer and data graph.node_renderer.glyph = Circle(size=size, fill_color="fill_color", line_color='gray') graph.node_renderer.selection_glyph = Circle(size=size, fill_color="fill_color", line_color='black', line_width=2) graph.node_renderer.hover_glyph = Circle(size=size, fill_color="fill_color", line_color='black') graph.node_renderer.data_source.data = {'index': node_indices, label_attr: df[label_attr].tolist(), 'fill_color': node_colors, color_attr: df[color_attr].fillna('').tolist(), 'x': df['x'].tolist(), 'y': df['y'].tolist(), } # set edge renderer and data graph.edge_renderer.glyph = MultiLine(line_color="line_color", line_width=1) graph.edge_renderer.data_source.data = {'start': [e[0] for e in nw.edges], 'end': [e[1] for e in nw.edges], 'line_color': edge_colors } # set layout graph_layout = dict(zip(node_indices, zip(df['x'], df['y']))) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) # set legend by adding dummy glyph with legend plot.circle( x='x', y='y', radius=0.0, color='fill_color', legend=field(color_attr), source=graph.node_renderer.data_source.data) plot.legend.location = "top_left" plot.legend.padding = 0 plot.legend.margin = 0 graph.selection_policy = NodesAndLinkedEdges() # hide axes and grids plot.xaxis.visible = False plot.yaxis.visible = False plot.xgrid.visible = False plot.ygrid.visible = False plot.renderers.append(graph) show(plot)
def circle_layout_graph(node_df, edge_df, node_data_cols=[], node_index_name="id", use_node_df_index=True, node_fill_by="index", node_line_by="index", node_line_width=3, scale_nodes_by=None, log_scale_nodes_by=None, node_properties={}, default_line_color="#111111", hover_fill_color="#00ff00", hover_line_color="#00aa00", selected_fill_color="#ff0000", selected_line_color="#ff0000", edge_start_col="node1", edge_end_col="node2", edge_weight_col="total_weight", edge_data_cols=[], use_alpha=True, log_weight=True, node_fill_palette=cc.glasbey_dark, node_line_palette=cc.glasbey_light, layout_origin=np.zeros(2), layout_radius=1.0, circular_arcs=True, circle_k=3, hover_tooltips={"id": "@index"}): """ Return a `bokeh.GraphRenderer` object and list of tools that display the graph specified by the input dataframes. Required arguments are `node_df`, `edge_df` which specify the structure of the graph. The column `node_df[node_index_name]` or `node.index` will be used as the graph renderer index. Other columns can be stored in the graph renderer by specifying a list `node_data_cols` (default empty list `[]`). `node_fill_by` and `node_line_by` specify how colors are chosen for the nodes. Valid options are the default "index", or a list of columns in `node_df`. In the first case, the specified palettes[1] will be repeated to match the length of the node index. Otherwise each unique combination of values in those columns will be mapped to a color in the palette (repeating if necessary). The dataframe will be sorted by the fill color columns, if specified. [1] A `bokeh` palette is a list of strings, each a hex code for a color; see https://docs.bokeh.org/en/latest/docs/reference/palettes.html """ graph = GraphRenderer() n_nodes = node_df.shape[0] # set up fill color, if specified if node_fill_by == "index": node_df["fill_color"] = repeat_to_match_lengths(node_fill_palette, n_nodes) elif node_fill_by is not None: node_df = node_df.sort_values(by=node_fill_by) uniques_df = pd.DataFrame(node_df[node_fill_by].value_counts()) uniques_df["fill_color"] = repeat_to_match_lengths(node_fill_palette, uniques_df.shape[0]) node_df = node_df.merge(uniques_df[["fill_color"]], left_on=node_fill_by, right_index=True) del uniques_df if "fill_color" in node_df.columns and "fill_color" not in node_data_cols: node_data_cols.append("fill_color") # set up line color, if specified if node_line_by == "index": node_df["line_color"] = repeat_to_match_lengths(node_line_palette, n_nodes) elif node_line_by is not None: uniques_df = pd.DataFrame(node_df[node_line_by].value_counts()) uniques_df["line_color"] = repeat_to_match_lengths(node_line_palette, uniques_df.shape[0]) node_df = node_df.merge(uniques_df[["line_color"]], left_on=node_line_by, right_index=True) del uniques_df if "line_color" in node_df.columns and "line_color" not in node_data_cols: node_data_cols.append("line_color") # Use the node DF as the data source for the node renderer if len(node_data_cols) == 0: node_data_cols = node_df.columns graph.node_renderer.data_source.data = node_df[node_data_cols] if use_node_df_index: node_index = node_df.index else: node_index = node_df[node_index_name] graph.node_renderer.data_source.data["index"] = node_index # add node layout info if "theta" not in node_df.columns: theta = np.linspace(0, 2 * np.pi, n_nodes + 1)[:-1] else: theta = node_df['theta'] nodes_x = layout_origin[0] + layout_radius * np.cos(theta) nodes_y = layout_origin[1] + layout_radius * np.sin(theta) graph_layout = dict(zip(node_index, zip(nodes_x, nodes_y))) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) # add edges edge_data = {"start": edge_df[edge_start_col], "end": edge_df[edge_end_col], **{k: edge_df[k] for k in edge_data_cols}} if edge_weight_col is not None: edge_data["weight"] = edge_df[edge_weight_col] else: edge_data["weight"] = np.ones(edge_df.shape[0]) if log_weight: edge_data["weight"] = np.log(edge_data["weight"]) + 1 if use_alpha: edge_data["alpha"] = edge_data["weight"] / np.max(edge_data["weight"]) graph.edge_renderer.data_source.data = edge_data # style the nodes if log_scale_nodes_by is not None: graph.node_renderer.data_source.data["radius"] = sin(2 * pi / n_nodes / 3) * np.log(node_df[log_scale_nodes_by]) / np.log(node_df[log_scale_nodes_by]).max() elif scale_nodes_by is not None: graph.node_renderer.data_source.data["radius"] = sin(2 * pi / n_nodes / 3) * node_df[scale_nodes_by] / node_df[scale_nodes_by].max() else: graph.node_renderer.data_source.data["radius"] = [sin(2 * pi / n_nodes / 3)] * n_nodes graph.node_renderer.glyph = Circle(radius="radius", fill_color="fill_color", line_color="line_color", line_width=node_line_width, **node_properties) graph.node_renderer.hover_glyph = Circle(radius="radius", fill_color=hover_fill_color, line_color=hover_line_color, line_width=node_line_width, **node_properties) graph.node_renderer.selection_glyph = Circle(radius="radius", fill_color=selected_fill_color, line_color=selected_line_color, line_width=node_line_width, **node_properties) graph.edge_renderer.glyph = MultiLine(line_color=default_line_color, line_width="weight", line_alpha="alpha") graph.edge_renderer.hover_glyph = MultiLine(line_color=hover_line_color, line_width="weight", line_alpha=1.0) graph.edge_renderer.selection_glyph = MultiLine(line_color=selected_line_color, line_width="weight", line_alpha=1.0) graph.selection_policy = NodesAndLinkedEdges() graph.inspection_policy = NodesAndLinkedEdges() if circular_arcs: xs, ys = [], [] for start_index, end_index in zip(graph.edge_renderer.data_source.data["start"], graph.edge_renderer.data_source.data["end"]): Q = np.array(graph_layout[start_index]) R = np.array(graph_layout[end_index]) circle_xs, circle_ys = inverted_circle_arc(layout_origin, Q, R, circle_k) xs.append(circle_xs) ys.append(circle_ys) graph.edge_renderer.data_source.data['xs'] = xs graph.edge_renderer.data_source.data['ys'] = ys tools = [TapTool(), HoverTool(tooltips=[(k, v) for k, v in hover_tooltips.items()])] return graph, tools
def breakdown_flowchart_graph(df, columns=None, x_coords=None, bar_width=1, gap=3, palette=cc.glasbey_dark, hover_line_color="#ff0000", line_cap="butt", line_width_mode="clamp", max_line_width=100, circle_k=3, hover_tooltips={}): """ Given a dataframe with categorical data across columns, produce a breakdown figure which shows how things regroup from one column to the next. By default, uses all columns in `data_df` which can potentially cause problems `line_width_mode = "clamp"` will apply min(w, max_line_width) to the edge widths, any other option will just use the actual edge width (might make the graph unreadable though) """ graph = GraphRenderer() # handle missing parameters if columns is None: columns = df.columns if x_coords is None: x_coords = [gap * i for i in range(len(columns))] # set up the node data node_index = [] node_x, node_y, node_height = [], [], [] col_name, col_value = [], [] for c, x in zip(columns, x_coords): val_counts = df[c].value_counts() new_indices = index_to_unique_list(val_counts.index, c) node_index += new_indices col_name += [c] * len(new_indices) col_value += val_counts.index.to_list() node_x += [x] * len(new_indices) node_y += list(val_counts.values.cumsum() - val_counts.values / 2) node_height += val_counts.values.tolist() n_nodes = len(node_index) graph = GraphRenderer() palette = repeat_to_match_lengths(palette, n_nodes) # add the node renderer graph.node_renderer.data_source.data = {"index": node_index, "col_name": col_name, "col_value": col_value, "height": node_height, "color": palette, "node_x": node_x, "node_y": node_y} graph_layout = dict(zip(node_index, zip(node_x, node_y))) graph.layout_provider = StaticLayoutProvider(graph_layout=graph_layout) color_mapper = dict(zip(node_index, palette)) # used for coloring edges # style the nodes graph.node_renderer.glyph = Rect(width=bar_width, height="height", fill_color="color") graph.node_renderer.hover_glyph = Rect(width=bar_width, height="height", fill_color="color", line_color=hover_line_color, line_width=2) graph.node_renderer.selection_glyph = Rect(width=bar_width, height="height", fill_color="color") # construct the edges and their paths start, end = [], [] xs, ys = [], [] edge_width, edge_color = [], [] for c0, c1 in zip(columns[:-1], columns[1:]): vc = df[[c0, c1]].value_counts() new_starts = index_to_unique_list(vc.index.get_level_values(0), c0) new_ends = index_to_unique_list(vc.index.get_level_values(1), c1) for s, e in zip(new_starts, new_ends): P = np.array(graph_layout[s]) Q = np.array(graph_layout[e]) curve_xs, curve_ys = flowchart_quarter_circle_curve(P, Q, bar_width / 2, circle_k) xs.append(curve_xs) ys.append(curve_ys) start += new_starts end += new_ends if line_width_mode == "clamp": edge_width += [min(v, max_line_width) for v in vc.values] else: edge_width += vc.values.tolist() edge_color += [color_mapper[s] for s in new_starts] # add the edge data to the renderer graph.edge_renderer.data_source.data = {"start": start, "end": end, "line_width": edge_width, "xs": xs, "ys": ys, "color": edge_color} graph.edge_renderer.glyph = MultiLine(line_width="line_width", line_color="color", line_alpha=0.5, line_cap=line_cap) graph.edge_renderer.hover_glyph = MultiLine(line_width="line_width", line_color="color", line_alpha=1.0, line_cap=line_cap) graph.edge_renderer.selection_glyph = MultiLine(line_width="line_width", line_color="color", line_alpha=1.0, line_cap=line_cap) graph.edge_renderer.nonselection_glyph = MultiLine(line_width="line_width", line_color="color", line_alpha=0.2, line_cap=line_cap) graph.selection_policy = NodesAndLinkedEdges() graph.inspection_policy = NodesAndLinkedEdges() tools = [TapTool(), HoverTool(tooltips=[(k, v) for k, v in hover_tooltips.items()])] suggested_x_range = (min(node_x) - bar_width / 2, max(node_x) + bar_width / 2) suggested_y_range = (0, max(y + h / 2 for y, h in zip(node_y, node_height))) return graph, tools, (suggested_x_range, suggested_y_range)