def build_plotly_figure(self, pos=None): if pos is None: # The kamada kawai layout produces a really nice graph but it's # a O(N^2) algorithm. It seems only reasonable to draw the graph # with fewer than ~1000 nodes. if len(self.graph) < 1000: pos = nx.layout.kamada_kawai_layout(self.graph) else: pos = nx.layout.random_layout(self.graph) # Create scatter plot of the position of all notes node_trace = go.Scatter( x=[], y=[], text=[], mode="markers", hoverinfo="text", marker=dict( showscale=True, # colorscale options colorscale="YlGnBu", reversescale=True, color=[], size=10, colorbar=dict( thickness=15, title="Centrality", xanchor="left", titleside="right" ), line=dict(width=2), ), ) for node in self.graph.nodes(): x, y = pos[node] text = "
".join([node, self.graph.nodes[node].get("title", "")]) node_trace["x"] += tuple([x]) node_trace["y"] += tuple([y]) node_trace["text"] += tuple([text]) # Color nodes based on the centrality for node, centrality in nx.degree_centrality(self.graph).items(): node_trace["marker"]["color"] += tuple([centrality]) # Draw the edges as annotations because it's only sane way to draw arrows. edges = [] for from_node, to_node in self.graph.edges(): edges.append( dict( # Tail coordinates ax=pos[from_node][0], ay=pos[from_node][1], axref="x", ayref="y", # Head coordinates x=pos[to_node][0], y=pos[to_node][1], xref="x", yref="y", # Aesthetics arrowwidth=2, arrowcolor="#666", arrowhead=2, # Have the head stop short 5 px for the center point, # i.e., depends on the node marker size. standoff=5, ) ) fig = go.Figure( data=[node_trace], layout=go.Layout( showlegend=False, hovermode="closest", margin=dict(b=20, l=5, r=5, t=40), annotations=edges, xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(showgrid=False, zeroline=False, showticklabels=False), ), ) return fig