Bokeh中的网络图形:在鼠标悬停在节点上时显示节点的连接

时间:2016-08-16 21:38:40

标签: python graph callback bokeh

我正在使用Bokeh创建NetworkX图形的交互式可视化。当我用鼠标悬停在该节点上时,我想要做的是显示连接到特定节点的所有边。

在Bokeh用户指南中,example或多或少地做了我想要的,但我对此解决方案不满意有两个原因:

  1. 在每个悬停事件中新绘制线段,这意味着它们显示在节点圈,看起来很难看。 (由于线条和节点颜色相同,因此在示例中不明显。)
  2. 我的图表是加权的,边缘的宽度取决于其重量。 (据我所知)没有办法让突出显示的边缘达到正确的宽度。
  3. 所以,我尝试了另一种方法:从头开始绘制所有边,但将visible属性设置为False。然后创建一个字典,其中节点索引为键,并且连接到该节点的边列表为值。当节点被鼠标悬停时,该节点的边缘应将其visible属性更改为True。看起来或多或少是这样的:

    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
    

    这不起作用,我对如何解决它感到有些困惑。特别是对cb_data的使用对我来说是一个谜 - 尽管有很多谷歌搜索我还没有找到一个清晰而全面的参考,包括cb_data包含哪些信息,以什么格式,以及如何访问它。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

您可以添加悬停工具以突出显示悬停时连接的边缘,还可以将默认线alpha设置为零:

import networkx as nx

from bokeh.models import Range1d, MultiLine, Circle, HoverTool
from bokeh.models.graphs import from_networkx, EdgesAndLinkedNodes
from bokeh.plotting import figure, show

G=nx.karate_club_graph()

plot = figure(plot_width=400, plot_height=400,
            x_range=Range1d(-1.1,1.1), y_range=Range1d(-1.1,1.1))
plot.add_tools(HoverTool(tooltips=None))

r = from_networkx(G, nx.circular_layout, scale=1, center=(0,0))

r.node_renderer.glyph = Circle(size=15, fill_color='#2b83ba')
r.node_renderer.hover_glyph = Circle(size=15, fill_color='#abdda4')

r.edge_renderer.glyph = MultiLine(line_alpha=0, line_width=5)  # zero line alpha
r.edge_renderer.hover_glyph = MultiLine(line_color='#abdda4', line_width=5)

r.inspection_policy = EdgesAndLinkedNodes()
plot.renderers.append(r)

show(plot)

enter image description here