title: Network graphing in Bokeh: displaying a node's connections when hovering over the node
body: <p>I'm using Bokeh to create an interactive visualisation of a NetworkX graph. What I want to do is display all edges connected to a particular node when I hover over that node with the mouse.</p>
  
  <p>In the Bokeh User Guide there's an <a href="http://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-hover" rel="noreferrer">example</a> that does more or less what I want, but I'm not satisfied with this solution for two reasons:</p>
  
  <ol>
  <li>The line segments are newly drawn on each hover event, which means they are shown <em>over</em> the node circles, which looks ugly. (This isn't noticeable in the example since the lines and the nodes are the same colour).</li>
  <li>My graph is weighted, with the width of an edge depending on its weight. There's no way (as far as I'm aware) to get the highlighted edges to the correct width.</li>
  </ol>
  
  <p>So, I've tried another approach: draw all edges from the beginning, but set their <code>visible</code> attributes to <code>False</code>. Then create a dictionary with the node indices as keys and a list of the edges connected to that node as values. When the node is moused over, that node's edges should get their <code>visible</code> attribute changed to <code>True</code>. It looks more or less like this:</p>
  
  <pre><code>global glob_edges_by_node_index
  
  edges_by_node = {}
  
  for edge in G.edges(data=True): # create the segments (G is a preexisting NetworkX graph)
      u,v,d = edge
      x_0 = pos[u][0] # pos is a preexisting dictionary of x and y values for each node
      y_0 = pos[u][1]
      x_1 = pos[v][0]
      y_1 = pos[v][1]
      width = 0.03*d['weight']
      highlit_edge = p.segment(x0=[x_0],x1=[x_1],y0=[y_0],y1=[y_1],color='#379bdd',line_width=width) # p is a preexisting Bokeh figure
      highlit_edge.visible = False # all segments are invisible at the start
      edges_by_node[u].append(highlit_edge) # put the segment into both nodes' dictionary entries
      edges_by_node[v].append(highlit_edge)
  
  
  id_to_index = {}
  edges_by_node_index = {}
  i = 0
  
  for node_id in G.nodes(): # convert the dict keys from their original IDs to the indices seen by Bokeh
      id_to_index[node_id] = i
      edges_by_node_index[i] = edges_by_node[node_id]
      i = i + 1
  
  global glob_edges_by_node_index = edges_by_node_index
  
  nodesource = ColumnDataSource(data=dict(x=x,y=y,sizes=nodesizes,colours=nodecolours)) # refers to preexisting data about the nodes
  cr = p.circle('x','y',color='colours',alpha=0.7,hover_color='colours',hover_alpha=1.0,size='sizes',line_width=1,line_color='#000000',hover_line_color='#000000',source=nodesource) # draw the nodes themselves
  
  p.add_tools(HoverTool(tooltips=None,callback=CustomJS.from_py_func(on_hover),renderers=[cr]))
  
  def on_hover(window=None):
  
      indices = cb_data['index']
      for ind in indices:
          highlit_edges = glob_edges_by_node_index[ind]
          for highlit_edge in highlit_edges:
              highlit_edge.visible = True # set edges to visible if they're in the dict entry of the hovered-over node
  </code></pre>
  
  <p>This does not work, and I'm a bit stumped as to how to fix it. Especially the use of <code>cb_data</code> is a mystery to me – despite lots of Googling I haven't been able to find a clear and comprehensive reference of what information <code>cb_data</code> contains, in what format, and how to access it. Any help would be much appreciated!</p>