Search code examples
pythonpython-3.xgraphnetworkxspringlayout

Python NetworkX: Confining force-directed layout within circular boundary


Python NetworkX has a method spring_layout that simulates a force-directed representation of a NetworkX instance; however, this leads to an adjusted network with nodes that are not confined within a particular boundary shape (e.g., a circle). Below is an example of this (notice how the overall graph shape is arbitrary, albeit smaller clusters are visible):

enter image description here

Is it possible to set a boundary limit such that any node seeking to position itself beyond the set boundary is confined to the boundary edge? Below is an example illustrating this (notice how nodes along the perimeter seem to lie against an invisible circular border):

enter image description here


Solution

  • Maybe you can convert the Cartesian coordinates (x, y) to Polar coordinates (t, r) from pos returned by nx.spring_layout:

    import numpy as np
    import matplotlib.pyplot as plt
    import networkx as nx
    
    # G is your graph
    G = nx.balanced_tree(10, 3)
    pos = nx.spring_layout(G)
    
    # Extract Cartesian coordinates
    x, y = np.vstack(list(pos.values())).T
    
    # Convert to Polar coordinates
    r = np.sqrt(x**2, y**2)
    t = np.arctan2(y, x)
    
    # Create a figure with polar projection
    fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
    
    # Remove some annoying elements
    ax.grid(False)
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    
    # Rebuild the position dictionary
    pos2 = dict(zip(pos.keys(), [np.array(c) for c in zip(t, r)]))
    
    # Draw graph
    nx.draw_networkx(G, pos2, ax=ax, with_labels=False)
    

    Polar coordinates:

    enter image description here

    Cartesian coordinates:

    enter image description here