pythonpython-3.xmatplotlibnetworkxpyvis

How to make edge in networkx a button?


I want that when I press on an edge, a windows with info will pop up.

How to do that? Is it possible?

Example of my code:

my_graph = networkx.Graph()

to_print = set()

for network_profile in network_profiles:
    for connected_profile in network_profile.profile_connections:
        to_print.add((network_profile.ip_address, connected_profile.ip_address))

my_graph.add_edges_from(list(to_print))
networkx.draw(my_graph, with_labels=True, font_weight='bold')
matplotlib.pyplot.show()

Solution

  • I want that when I press on an edge, a windows with info will pop up. How to do that?

    This is called a pick event. For the general case, see the matplotlib tutorial here.

    Is it possible?

    networkx uses matplotlib for plotting, so in principle, yes. However, networkx by default uses a LineCollection object to visualise edges. This makes the standard approach to picking impossible, where each individual artist is mapped to an individual action (as you require), as there is only one artist representing all edges, not one artist per edge.

    I built and maintain netgraph, which is a library specialised for network visualisation (but not analysis like networkx). It works with networkx Graph objects, it also uses matplotlib under the hood, but each edge has its own artist such that picking can easily be implemented in the standard way. However, there are a few built-in ways to display additional data that may satisfy your needs. You can add annotations that are toggled on or off by clicking on the nodes or edges. See the last example on this page. If you want a side-by-side display of tabular data when clicking on a node or an edge, you can follow this example.

    If you do want a separate window to display the information, then you can use tkinter to open a message box on pick like so:

    import tkinter
    import matplotlib.pyplot as plt; plt.ion()
    import networkx as nx
    
    from netgraph import Graph # pip install netgraph
    
    # hide the main tkinter window
    root = tkinter.Tk()
    root.withdraw()
    
    # create network and plot
    fig, ax = plt.subplots()
    g = nx.cubical_graph()
    plot_instance = Graph(g, node_size=5, edge_width=2.5, node_labels=True, node_label_fontdict=dict(weight='bold'), ax=ax)
    
    # map each edge to a desired message; here we use random strings
    random_string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam eu tortor commodo, maximus dui vel, pellentesque ligula. Maecenas tincidunt porta ex nec lacinia. Sed lectus sapien, convallis id arcu ut, porta ultrices ante. Ut mauris nisl, pulvinar in turpis at, euismod iaculis purus. Proin ut fermentum urna. Donec tortor dolor, consectetur vel magna sed, efficitur vehicula neque. Aliquam erat volutpat. Vivamus venenatis lacinia purus vitae varius. Quisque nisl felis, tincidunt ut justo a, faucibus volutpat sapien. Donec vel neque eu turpis ornare venenatis. Aenean imperdiet iaculis dui ac bibendum."
    
    edge_to_message = dict(zip(g.edges, random_string.split('. ')))
    
    # make edge artists pickable and map each edge artist to the corresponding string
    artist_to_message = dict()
    for edge, artist in plot_instance.edge_artists.items():
        artist.set_picker(True)
        artist_to_message[artist] = edge_to_message[edge]
    
    # define the on-pick behaviour
    def on_pick(event):
        title = None
        message = artist_to_message[event.artist]
        tkinter.messagebox.showinfo(title, message)
    
    fig.canvas.mpl_connect('pick_event', on_pick)