Search code examples
pythonnetworkxbokeh

Highlighting the neighborhood of a node on selection


I created a graph using networkx and I am trying to plot it using bokeh. Currently, I am able to highlight the node that I clicked on, as well as the edges linked to the selected node.

To reproduce the example, see the following code inspired from the official bokeh tutorial:

from bokeh.models.graphs import NodesAndLinkedEdges
from bokeh.models import Circle, MultiLine,TapTool
from bokeh.io import show, output_notebook
from bokeh.plotting import figure
import networkx as nx
from bokeh.models import Range1d, Plot
from bokeh.plotting import from_networkx


G = nx.gnm_random_graph(15, 30)

plot = Plot(x_range=Range1d(-2, 2), y_range=Range1d(-2 ,2))

graph = from_networkx(G, nx.spring_layout, scale=1.8, center=(0,0))
plot.renderers.append(graph)

graph.node_renderer.glyph = Circle(size=25, fill_color='#2b83ba')
graph.edge_renderer.glyph = MultiLine(line_color="#cccccc", line_alpha=0.8, line_width=2)

graph.node_renderer.selection_glyph = Circle(size=25, fill_color='#abdda4')
graph.edge_renderer.selection_glyph = MultiLine(line_color='#abdda4', line_width=4)

graph.selection_policy = NodesAndLinkedEdges()

plot.add_tools(TapTool())

show(plot)

I would like to be able to highlight not only the linked edges, but also the neighbors of the selected node. Does anybody knows how to do so? Thanks! I've looked through all the policies available for selection, but none of them allows me to do so.


Solution

  • I am open to any other package as well.

    In netgraph, the InteractiveGraph class implements your desired behaviour by default.

    enter image description here

    #!/usr/bin/env python
    import matplotlib.pyplot as plt
    import networkx as nx
    
    from netgraph import InteractiveGraph # pip install netgraph
    
    G = nx.gnm_random_graph(15, 30, seed=1)
    plot = InteractiveGraph(G, node_color='#2b83ba', edge_color="#cccccc", edge_alpha=0.8)
    plt.show()
    

    You can also implement arbitrary "policies" using the EmphasizeOnHoverGraph parent class. Here an MWE that demonstrates a range of possible behaviours:

    import matplotlib.pyplot as plt
    from netgraph._main import EmphasizeOnHoverGraph
    
    edges = [(0, 1), (1, 2), (2, 0)]
    mapping = {
        0 : [],                        # nothing is highlighted / everything is de-emphasized
        1 : [1],                       # only the node being hovered over is highlighted
        2 : [2, (1, 2), (2, 0), 1, 2], # the node, its neighbours and connecting edges are highlighted (same as default behaviour)
        (0, 1) : [(2, 0)],             # another edge is highlighted
        (1, 2) : [(1, 2), 1, 2],       # the edge, and its source and target nodes are highlighted (same as default behaviour)
        # (2, 0)                       # nothing happens when hovering over edge (2, 0)
    }
    fig, ax = plt.subplots(figsize=(10, 10))
    plot = EmphasizeOnHoverGraph(edges, mouseover_highlight_mapping=mapping, node_labels=True, edge_labels=True, ax=ax)
    plt.show()