plotly_3.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. def build_plotly_figure(self, pos=None):
  2. """
  3. Creates a Plot.ly Figure that can be view online or offline.
  4. Parameters
  5. ----------
  6. graph : nx.Graph
  7. The network of zettels to visualize
  8. pos : dict
  9. Dictionay of zettel_id : (x, y) coordinates where to draw nodes. If
  10. None, the Kamada Kawai layout will be used.
  11. Returns
  12. -------
  13. fig : plotly Figure
  14. """
  15. if pos is None:
  16. # The kamada kawai layout produces a really nice graph but it's
  17. # a O(N^2) algorithm. It seems only reasonable to draw the graph
  18. # with fewer than ~1000 nodes.
  19. if len(self.graph) < 1000:
  20. pos = nx.layout.kamada_kawai_layout(self.graph)
  21. else:
  22. pos = nx.layout.random_layout(self.graph)
  23. # Create scatter plot of the position of all notes
  24. node_trace = go.Scatter(
  25. x=[],
  26. y=[],
  27. text=[],
  28. mode="markers",
  29. hoverinfo="text",
  30. marker=dict(
  31. showscale=True,
  32. # colorscale options
  33. #'Greys' | 'YlGnBu' | 'Greens' | 'YlOrRd' | 'Bluered' | 'RdBu' |
  34. #'Reds' | 'Blues' | 'Picnic' | 'Rainbow' | 'Portland' | 'Jet' |
  35. #'Hot' | 'Blackbody' | 'Earth' | 'Electric' | 'Viridis' |
  36. colorscale="YlGnBu",
  37. reversescale=True,
  38. color=[],
  39. size=10,
  40. colorbar=dict(
  41. thickness=15, title="Centrality", xanchor="left", titleside="right"
  42. ),
  43. line=dict(width=2),
  44. ),
  45. )
  46. for node in self.graph.nodes():
  47. x, y = pos[node]
  48. text = "<br>".join([node, self.graph.nodes[node].get("title", "")])
  49. node_trace["x"] += tuple([x])
  50. node_trace["y"] += tuple([y])
  51. node_trace["text"] += tuple([text])
  52. # Color nodes based on the centrality
  53. for node, centrality in nx.degree_centrality(self.graph).items():
  54. node_trace["marker"]["color"] += tuple([centrality])
  55. # Draw the edges as annotations because it's only sane way to draw arrows.
  56. edges = []
  57. for from_node, to_node in self.graph.edges():
  58. edges.append(
  59. dict(
  60. # Tail coordinates
  61. ax=pos[from_node][0],
  62. ay=pos[from_node][1],
  63. axref="x",
  64. ayref="y",
  65. # Head coordinates
  66. x=pos[to_node][0],
  67. y=pos[to_node][1],
  68. xref="x",
  69. yref="y",
  70. # Aesthetics
  71. arrowwidth=2,
  72. arrowcolor="#666",
  73. arrowhead=2,
  74. # Have the head stop short 5 px for the center point,
  75. # i.e., depends on the node marker size.
  76. standoff=5,
  77. )
  78. )
  79. fig = go.Figure(
  80. data=[node_trace],
  81. layout=go.Layout(
  82. showlegend=False,
  83. hovermode="closest",
  84. margin=dict(b=20, l=5, r=5, t=40),
  85. annotations=edges,
  86. xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
  87. yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
  88. ),
  89. )
  90. return fig