Search code examples
pythonqtpyqtpyqt6netgraph

How to retrieve information on a graph while building it using EditableGraph of netgraph


I'm new to Qt and Netgraph, and I'd like to develop a Qt application with graph construction at its core. NetGraph's EditableGraph function meets my expectations and seems great. However, I also need to continuously update another structure based on the graph incrementally while it is constructed. For instance, I want to print the nodes and arcs of the graph as they are created.

Is it possible to retrieve the graph structure during its construction by EditableGraph and process it incrementally?

Otherwise I would have to design an interactive graph construction function with this functionality.


Solution

  • Accessing relevant data structures

    The EditableGraph class (like all classes derived from Graph) maintains several data structures to keep track of all plot elements.

    • node_positions maps nodes to their (x, y) coordinates (their center),
    • edge_paths maps edges to their coordinate paths,
    • node_artists / edge_artists map nodes / edges to the corresponding matplotlib.patches.PathPatch artists,
    • node_label_artists / edge_label_artists map node / edge labels to the corresponding matplotlib.text.Text instances.

    The matplotlib patch artists can themselves be queried to determine their visual properties such as their color, e.g. my_editable_graph_instance.node_artists[42].get_facecolor(). The same holds for the label artists.

    from netgraph import EditableGraph
    
    g = EditableGraph([(0, 1)], node_labels=True, edge_labels=True)
    
    print(g.node_positions)
    # {0: array([0.95, 0.5 ]), 1: array([0.05, 0.5 ])}
    
    print(g.edge_paths)
    # {(0, 1): array([[0.95, 0.5 ], [0.05, 0.5 ]])} 
    
    print(g.node_artists)
    # {0: <netgraph._artists.NodeArtist at 0x7f7d5d2d68e0>,
    #  1: <netgraph._artists.NodeArtist at 0x7f7d5d2d6b80>}
    
    print(g.node_artists[0].get_facecolor())
    # (1.0, 1.0, 1.0, 1.0)
    
    print(g.node_label_artists)
    # {0: Text(0.05, 0.5, '0'), 1: Text(0.9500000000000001, 0.5, '1')}
    
    print(g.node_label_artists[0].get_weight())
    # normal
    
    print(g.edge_artists)
    # {(0, 1): <netgraph._artists.EdgeArtist at 0x7f7d0f0c89a0>}
    
    print(g.edge_label_artists)
    # {(0, 1): Text(0.5, 0.5, '(0, 1)')}
    

    Update logic

    The data structures are updated on key press events (insert/+ and delete/-), but to prevent race conditions, you may want to hook into draw events instead as the canvas is redrawn after all data structures are up-to-date.

    import matplotlib.pyplot as plt
    
    from netgraph import EditableGraph
    
    fig, ax = plt.subplots()
    g = EditableGraph([(0, 1)], ax=ax)
    
    def trigger_update(event):
        # Here should go your logic to update your own data structures.
        # For this mock-up, we just print some information.
        print(g.node_positions)
        print(g.edge_paths)
    
    fig.canvas.mpl_connect('draw_event', trigger_update)
    
    plt.show()
    

    Addendum:

    This project may be of interest, as it uses Netgraph within a Qt application. I imagine they faced many of the same issues as you will / do.