Search code examples
pythongraphlayoutnetworkxpyvis

pyvis: is there a way to disable physics without losing graph's layout?


I am trying to vizualize a large network with pyvis and facing two problems:

  1. super long rendering
  2. network instability, i.e. nodes move too fast and it is hard to interact with such a network.

Disabling physics with toggle_physics(False) helps to speed up rendering and makes the network static, but eliminates the layout settings. This is how it looks agter disabling physics: link. As you see, the graph is messy and has no structure. What I want to do is to disable physics but keep the layout settings, i.e. I want my graph to look like a normal network (e.g. similar to spring layout in networkX) with weights taken into account for every edge. Is there a way to do so?

So far I found out that pyvis only has hierarchial layouts, which is not what I need. I think integrating a networkX layout might help but I have no idea how to do this, since networkX allows to set layout as a keyword argument in nx.draw() function, which is not compatible with my case. This is my code in case it helps to understand my problem:

g = nx.Graph()
edges_cards = cards_weights_df.values.tolist()
g.add_weighted_edges_from(edges_cards)

net = Network("1000px", "1800px")
net.from_nx(g)
net.toggle_physics(False)
net.show("graph.html")

Your help is appreciated!


Solution

  • It is possible to pass x and y coordinates to your pyvis nodes (see doc here). You can then create a graph layout with networkx and pass the resulting positions to your pyvis graph. See example below with nx.circular_layout() applied to the karate club network:

    import networkx as nx
    from pyvis.network import Network
    
    G = nx.karate_club_graph()
    pos=nx.circular_layout(G,scale=500)
    
    net = Network()
    net.from_nx(G)
    
    for node in net.get_nodes():
      net.get_node(node)['x']=pos[node][0]
      net.get_node(node)['y']=-pos[node][1] #the minus is needed here to respect networkx y-axis convention 
      net.get_node(node)['physics']=False
      net.get_node(node)['label']=str(node) #set the node label as a string so that it can be displayed
    
    net.toggle_physics(False)
    net.show('net.html')
    

    Here is the result with circular layout:

    enter image description here

    and without any specific layout:

    import networkx as nx
    from pyvis.network import Network
    
    G = nx.karate_club_graph()
    
    net = Network()
    net.from_nx(G)
    
    for node in net.get_nodes():
      net.get_node(node)['physics']=False
      net.get_node(node)['label']=str(node)
    
    net.toggle_physics(False)
    net.show('net.html')
    

    enter image description here