如何将节点属性从NetworkX传递到bokeh

时间:2018-10-05 20:47:01

标签: python bokeh networkx

我正在寻找一种将NetworkX节点构造中所定义的颜色传递给Bokeh图的方法。

有很多很棒的方法可以在生成散景图后在Bokeh图中实现颜色,例如this,但是此解决方案要求我根据属性将变换应用于整个数据集。

我想做一些更简单的事情,并根据我在NetworkX中分配的颜色和大小来分配颜色和大小。我通常在NetworkX中将节点集1绘制为红色,然后将节点集2绘制为蓝色,然后通过它们的相互边缘进行连接。虽然节点的颜色和大小没有传递给matplotlib,但当我将文件另存为graphml时,它 IS 传递给了gephi,所以这些数据都在某个地方。

import networkx as nx
from bokeh.io import show, output_file
from bokeh.plotting import figure,show
from bokeh.models.graphs import from_networkx #I haven't been able to use this!
from bokeh.io import output_notebook
from bokeh.models import HoverTool, ColumnDataSource
from bokeh.resources import CDN
from bokeh.embed import file_html

Dataset1 = ['A','B','C','D','E','F']
Dataset2 = ['ONE','TWO','THREE','FOUR','FIVE','TWENTY_EIGHT']
Edgelist = [('A','ONE'),('B','ONE'),('E','ONE'),('A','TWO'),('A','THREE'),('A','FOUR'),('C','THREE'),('D','FIVE'),('D',"TWENTY_EIGHT")]
G = nx.Graph()
G.add_nodes_from(Dataset1,color= 'green')  
G.add_nodes_from(Dataset2,color='blue') 
G.add_edges_from(Edgelist,weight=0.8)
layout = nx.draw_spring(G, with_labels=True)
nx.write_graphml(G,"TEST.graphML")
network = nx.read_graphml("TEST.graphML")

#start Bokeh code
layout = nx.spring_layout(network,k=1.1/sqrt(network.number_of_nodes()),iterations=100) #pass the NX file to a spring layout

nodes, nodes_coordinates = zip(*sorted(layout.items()))
nodes_xs, nodes_ys = list(zip(*nodes_coordinates))
nodes_source = ColumnDataSource(dict(x=nodes_xs, y=nodes_ys,name=nodes)) #Can this pass the color? 

hover = HoverTool(tooltips=[('name', '@name')]) #would like to know how to add in more values here manually

plot = figure(plot_width=800, plot_height=400,tools=['tap', hover, 'box_zoom', 'reset'])

r_circles = plot.circle('x', 'y', source=nodes_source, size=10, color='orange', level = 'overlay')#this function sets the color of the nodes, but how to set based on the name of the node? 


def get_edges_specs(_network, _layout): 
    d = dict(xs=[], ys=[], alphas=[])
    weights = [d['weight'] for u, v, d in _network.edges(data=True)]
    max_weight = max(weights)
    calc_alpha = lambda h: 0.1 + 0.6 * (h / max_weight)

    # example: { ..., ('user47', 'da_bjoerni', {'weight': 3}), ... }
    for u, v, data in _network.edges(data=True):
        d['xs'].append([_layout[u][0], _layout[v][0]])
        d['ys'].append([_layout[u][1], _layout[v][1]])
        d['alphas'].append(calc_alpha(data['weight']))
    return d

lines_source = ColumnDataSource(get_edges_specs(network, layout))

r_lines = plot.multi_line('xs', 'ys', line_width=1.5,
                      alpha='alphas', color='navy',
                      source=lines_source)#This function sets the color of the edges

show(plot)

在gephi中打开时,颜色会保留: From Gephi

  1. 我不太了解如何使用bokeh的from_networkx函数获取这些值。似乎这没有像预期那样传递属性。实际传递的是什么,我该如何传递颜色?

  2. 是否有更好的方法通过构造的ColumnDataSource分配更多属性?我在想类似于将其传递到数据框,添加颜色列,然后重新生成ColumnDataSource的方法,因此我可以为每个节点值使用'@node_color'检索颜色。

  3. 我有每个数据集的列表,因此可以通过某种方式进行过滤,例如:

    if node_id in list1:
        node_color = "red"
        node_size = 10
    if node_id in list2:
        node_color = "blue"
        node_size = 20
    

我对bokeh还是很陌生,尽管看起来这些应该是简单的任务,但是我完全迷失了文档。仅使用散景来生成网络可能会更好?

2 个答案:

答案 0 :(得分:0)

了解

我看到的每个人通过各种属性设置的color属性(例如中心度等)都是通过颜色映射实例完成的,但是将节点集设置为不同的颜色或大小并不是必需的。

这里的关键是ColumnDataSource(CDS)的构造方式。通过使用以下行:

nodes_source = ColumnDataSource(dict(x=nodes_xs, y=nodes_ys,name=nodes)

没有分配颜色或尺寸作为属性。更糟糕的是,我无法看到CDS的实际外观。 (据我所知,您可以通过调用CDS.to_df()将其查看为熊猫DF。)因此,我进行了实验,发现可以通过以下方式添加列:

node_color=pd.DataFrame.from_dict({k:v for k,v in network.nodes(data=True)},orient='index').color.tolist()
color = tuple(node_color)

nodes_source = ColumnDataSource(dict(x=nodes_xs, y=nodes_ys,name=nodes, _color_= color)

这分配了我从networkX检索到的属性,作为每个节点的ID值的函数,将其传递给元组,然后将其放置在CDS中,这将通过要求Bokeh构造从中检索数据来进行检索。姓名的列将以* STRING **的形式传递:

plot = figure(plot_width=800, plot_height=400,tools=['tap', hover, 'box_zoom', 'reset'])

r_circles = plot.circle('x', 'y', source=nodes_source, size=10,fill_color="_color_", level = 'overlay')

要回答所有3个问题:

  1. from_networkx检索节点的所有特征,至少是通过from_graphml()函数检索的。

  2. 分配columndatavalue的简单方法是将其传递给元组,如上所示,其中带有color属性。但是,在这里您可以将内容添加到CDS中,然后可以从悬停工具中获取内容。对我来说,这将非常有用。

  3. 使用所需的所有属性构造熊猫DF,然后使用CDS.from_df()函数将其传递到CDS进行bokeh分析。

答案 1 :(得分:0)

也许这个问题的答案可以帮助您:https://stackoverflow.com/a/54475870/8123623

创建一个dict,其中节点是键,颜色是值。

colors = [...]
colors = dict(zip(network.nodes, colors))
nx.set_node_attributes(network, {k:v for k,v in colors.items()},'colors' )
graph.node_renderer.glyph = Circle(size=5, fill_color='colors')

这就是使用from_network()

的方法
graph = from_networkx(G, nx.dot, scale=1, center=(0,0))