Search code examples
pythond3.jsnetworkx

How to hyperlink nodes in d3js NetworkX diGraph


I would like to create a NetworkX graph and visualize it using d3js similarly to the javascript example in the NetworkX docs. This graph is very similar to the interactive graph on the NetworkX homepage page.

The example works for me, but I would like to add hyperlinks to the nodes. I think I have node attributes called "xlink:href", but I have not figured out how.

This question was ansered for NewtworkX and visualization with bokeh here. I have not tested this example, since I want to use d3js. The code below is available here.

So far:

import json
import networkx as nx

G = nx.Graph()
G.add_node('Node1')
G.add_node('Node2')
G.add_edge('Node1', 'Node2')

for n in G:
    G.nodes[n]["name"] = "My" + str(n) 
    G.nodes[n]["xlink:href"] = "http://google.com"  # <==<< link Not working

d = nx.json_graph.node_link_data(G)

json.dump(d, open("force/force.json", "w"))
print("Wrote node-link JSON data to force/force.json")

The above produces:

{'directed': False,
 'multigraph': False,
 'graph': {},
 'nodes': [{'name': 'MyNode1',
   'xlink:href': 'http://google.com',
   'id': 'Node1'},
  {'name': 'MyNode2', 'xlink:href': 'http://google.com', 'id': 'Node2'}],
 'links': [{'source': 'Node1', 'target': 'Node2'}]}

Which can be visualized like this:

# Serve the file over http to allow for cross origin requests
import flask
app = flask.Flask(__name__, static_folder="force")

@app.route("/")
def static_proxy():
    return app.send_static_file("force.html")
app.run(port=8001)

enter image description here

Interestingly, the tooltip on the graph displays "Node2" and not "MyNode2".

Links collected while trying to solve this:


Solution

  • Here's a solution using gravis, which accepts graph objects from NetworkX, iGraph, graph-tool and some other Python libraries and can visualize them with either d3.js, vis.js or three.js with a single function call.

    Disclaimer: I'm the developer of gravis. Your use case appears to be 1) creating an interactive graph visualization with d3 and 2) serve it via a web server such as Flask. Since this was part of the motivation to build gravis, I think it might fit well here.

    import gravis as gv
    import networkx as nx
    
    g = nx.Graph()
    g.add_node('Node1')
    g.add_node('Node2')
    g.add_edge('Node1', 'Node2')
    
    for n in g:
        g.nodes[n]["name"] = f"My {n}" 
        g.nodes[n]["hover"] = '<a href="http://google.com">Google</a>'
    
    fig = gv.d3(g, node_label_data_source='name')
    fig.display()
    

    The last line opens a browser window and shows the visualization. Alternatively you can also use fig.to_html() to get a standalone HTML text that you can serve via a web server like Flask. The hyperlink is shown when hovering over a node and can easily be clicked since the pop up disappears with a time delay.

    Yet another use case that can easily be serve is creating embedded graph visualizations in a Jupyter notebook, which may help in prototyping your app: enter image description here

    (The mouse cursor was hidden from the screenshot. It's hovering over node 1, hence the pop up with the hyperlink is visible.)