Remove nodes with mouse click, networkX, python 2.7
Asked Answered
S

2

3

I have written a program in Python 2.7 with networkX which draws a tree with black and white nodes. Here is a minimal example:

import networkx as nx
import matplotlib.pyplot as plt
import numpy

T = nx.Graph()

### Nodes
white, black = [1, 4, 5, 6, 7], [2, 3]
allNodes = white+black

for node in allNodes:      T.add_node(node)

### Edges
T.add_edge(1, 2)
T.add_edge(1, 3)
T.add_edge(2, 4)
T.add_edge(2, 5)
T.add_edge(3, 6)
T.add_edge(3, 7)

### Positions of the nodes
pos={}
pos[1]=numpy.array([ 0,0])
pos[2]=numpy.array([-2,1])
pos[3]=numpy.array([ 2,1])
pos[4]=numpy.array([-3,2])
pos[5]=numpy.array([-1,2])
pos[6]=numpy.array([ 1,2])
pos[7]=numpy.array([ 3,2])

### Draw nodes and edges
nx.draw_networkx_nodes(T, pos, nodelist=black, node_color='k',     node_size=400,     alpha=0.8)
nx.draw_networkx_nodes(T, pos, nodelist=white, node_color='w',     node_size=400,     alpha=0.8)
nx.draw_networkx_edges(T,pos,width=1.0, alpha=0.5)

plt.axis('off')     # Remove the axes
plt.show()          # Show the tree

The code creates a window with a small tree containing 7 nodes and 6 edges. Now I want the nodes to disappear when I click at them with the mouse. How can I do this?

Later my plan is that 2 players alternate in turn by removing leafs or the root in their color (black and white). I.e. player 1 can only remove black leaves or black roots, and player two can only remove white leafs and white roots.

I found these links that could be helpful but couldn't get it to work:

Anyone who knows how to accomplish this or have some tips?

Suspensive answered 17/5, 2015 at 16:38 Comment(2)
I can't help much I'm afraid, but to clarify your question: do you want them to disappear from the plot? or be deleted from the graph?Pomposity
From the plot, they could disappear from the tree also.Suspensive
S
4

I managed to do it! I had to save "fig" and "ax" from the plot (I think it is figure and axes?). Then I could connect a method/function, which I call onClick, to the figure which reacts to mouse clicks ('button_press_event').

Here how to get "fig" and "ax" from the plot and connecting the function/method:

fig, ax = plt.subplots()
fig.canvas.mpl_connect('button_press_event', onClick)

And here is the method that removes the nodes from the graph and the plot

def onClick(event):
    (x,y)   = (event.xdata, event.ydata)

    for i in allNodes:            
        node = pos[i]
        distance = pow(x-node[0],2)+pow(y-node[1],2)
        if distance < 0.1:
            T.remove_node(i)
            if i in black: black.remove(i)
            if i in white: white.remove(i)
            allNodes.remove(i)
            refreshGraph()    

The whole code:

import networkx as nx
import matplotlib.pyplot as plt
import numpy
import numpy as np
import pylab

def refreshGraph():
    plt.clf()
    nx.draw_networkx_nodes(T, pos, nodelist=black, node_color='k', node_size=400, alpha=0.8)
    nx.draw_networkx_nodes(T, pos, nodelist=white, node_color='w', node_size=400, alpha=0.8)
    nx.draw_networkx_edges(T,pos,width=1.0, alpha=0.5)
    plt.axis('off')
    plt.axis((-4,4,-1,3))
    fig.patch.set_facecolor('white')
    plt.show()

def onClick(event):
    (x,y)   = (event.xdata, event.ydata)

    for i in allNodes:            
        node = pos[i]
        distance = pow(x-node[0],2)+pow(y-node[1],2)
        if distance < 0.1:
            T.remove_node(i)
            if i in black: black.remove(i)
            if i in white: white.remove(i)
            allNodes.remove(i)
            refreshGraph()

fig, ax = plt.subplots()
fig.canvas.mpl_connect('button_press_event', onClick)

T = nx.Graph()

### Nodes
white, black = [1, 4, 5, 6, 7], [2, 3]
allNodes = white+black

for node in allNodes:      T.add_node(node)

### Edges
T.add_edge(1, 2)
T.add_edge(1, 3)
T.add_edge(2, 4)
T.add_edge(2, 5)
T.add_edge(3, 6)
T.add_edge(3, 7)

### Positions of the nodes
pos={}
pos[1]=numpy.array([ 0,0])
pos[2]=numpy.array([-2,1])
pos[3]=numpy.array([ 2,1])
pos[4]=numpy.array([-3,2])
pos[5]=numpy.array([-1,2])
pos[6]=numpy.array([ 1,2])
pos[7]=numpy.array([ 3,2])

### Draw nodes and edges
refreshGraph()
Suspensive answered 18/5, 2015 at 17:52 Comment(0)
S
1

I've been looking for example how to construct a networkx graph with mouse clicks and was redirected here. So I refactored a code to make it shorter, bug fixed and optimised. I'm using Python 3.8 and Networkx 2.5.

import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
import scipy.spatial

def onClick(event, G):
    if event.inaxes is not None and len(G.nodes()) > 0:
        nodelist, coords = zip(*nx.get_node_attributes(G, 'pos').items())
        kdtree = scipy.spatial.KDTree(coords)
        xy = np.array([event.xdata, event.ydata])
        close_idx = kdtree.query_ball_point(xy, np.sqrt(0.1))
        for i in close_idx:
            G.remove_node(nodelist[i])
        refreshGraph(G)

def refreshGraph(G):
    plt.clf()
    nx.draw_networkx_nodes(G, pos = nx.get_node_attributes(G, 'pos'), node_color='k', node_size=400, alpha=0.8)
    nx.draw_networkx_edges(G, pos = nx.get_node_attributes(G, 'pos'), width=1.0, alpha=0.5)
    plt.axis('off')
    plt.axis((-4, 4, -1, 3))
    fig.patch.set_facecolor('white')
    plt.show()

#Parameters of graph
nodes = np.array(['A','B','C','D','E','F','G'])
edges = np.array([['A', 'B'], ['A', 'C'], ['B', 'D'], ['B', 'E'], ['C', 'F'], ['C', 'G']])
pos = np.array([[ 0,0], [-2,1], [ 2,1], [-3,2], [-1,2], [ 1,2], [ 3,2]])

G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
nx.set_node_attributes(G, dict(zip(G.nodes(), pos)), 'pos')

fig, ax = plt.subplots()
fig.canvas.mpl_connect('button_press_event', lambda event, G=G: onClick(event, G))
refreshGraph(G)

This is a list of things that were improved here:

  • nodes, edges and pos can be set in one move using numpy arrays.
  • no coloring is used in order to make it MWE.
  • no global storage of nodes is needed outside graph; pos is an attribute of graph itself.
  • graph is a parameter of onClick and refreshGraph hence no global variable is needed to make these functions work
  • lookup of close nodes is optimized with a help of KDtrees, no lag if there are huge amounts of nodes.
  • fixed a bug in calculation of mouse position if a diagram is being clicked outside diagram.
  • deletion of multiple nodes within clicked radius is supported.
Stormy answered 9/9, 2020 at 20:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.