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?

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? Commented May 18, 2015 at 0:33
  • From the plot, they could disappear from the tree also. Commented May 18, 2015 at 17:44

2 Answers 2

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() 
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.