来自加权邻接块矩阵的“图形工具”边缘捆绑圆形布局图

`graph-tool` edge bundling circular layout graph from weighted adjacency block matrix

我正在尝试 graph-tool by Tiago Peixoto to build a graph (either directed or undirected) from a given weighted adjacency matrix with a block structure. So far, unsuccessfully. My question partly overlaps with this thread SO,但是,仍然没有明确的解决方案。

假设我有一个函数可以生成我的权重块矩阵 J,其形式为:

每个块 Jij 是一些随机二进制矩阵,其条目来自给定分布。标量 sg 分别表示对角块内连接的权重(即当 i = j 时)并挡住对角线(即 i ≠ j)。

我在 graph_tool 中构建图表如下:

import graph_tool.all as gt

directed = False  # True if we want the graph to be directed 
J = generate_adj_bmatrix(...,s=0.1,g=0.01,directed=directed) # Some function to generate the weighted adjacency matrix (here the matrix will be symmetric since we want the graph undirected)  

# Define graph
G = gt.Graph(directed=directed)
indexes = J.nonzero()
G.add_edge_list(np.transpose(indexes))
# Add weight information
G.ep['weight'] = G.new_ep("double", vals=J[indexes])

如果需要,我还可以将一些 VertexProperty 添加到我的 G 图中,我的节点属于其块。但是我如何将这些信息包含在我可以用来构建圆形图的代码中呢?代码如下(从 graph-tool docs 粘贴到此处):

state = gt.minimize_blockmodel_dl(G) # or should I consider instead state = gt.minimize_nested_blockmodel_dl(G)?
gt.draw_hierarchy(state)
t = gt.get_hierarchy_tree(state)[0]
tpos = pos = gt.radial_tree_layout(t, t.vertex(t.num_vertices() - 1), weighted=True)
cts = gt.get_hierarchy_control_points(G, t, tpos)
pos = G.own_property(tpos)
b = state.levels[0].b
shape = b.copy()
shape.a %= 14    # Have not yet figured out what I need it for
gt.graph_draw(G, pos=pos, vertex_fill_color=b, vertex_shape=shape, 
              edge_control_points=cts,edge_color=[0, 0, 0, 0.3], vertex_anchor=0)

值得注意的是,上面的代码目前挂起的时间似乎太长了。 minimize_blockmodel_dl(G) 行似乎陷入无限循环。理想情况下,我不应该对我的图进行聚类采样,因为根据我对 J 块结构的了解,此信息可能已经作为 属性 提供给顶点。同时,minimize_blockmodel_dl(G) 似乎是访问边缘捆绑选项所必需的,不是吗?

这是我想出的解决方案。

def visualize_network(J,N_sizes):
"""
Visualize a network from weighted block adjacency matrix in a circular layout with FEB.

Input arguments:
-- J : Weighted adjacency matrix (in block-matrix form, but can be any, as far as it is square). 
-- N_sizes : {<block1_label>: size; <block2_label>: size,...} such that node indexes of block n follow immediately those of block n-1.  
"""

import numpy as np
import matplotlib.colors as mcolors
import graph_tool.all as gt

# Generate the graph
G = gt.Graph(directed=True) # In my case, network edges are oriented
eindexes = J.nonzero()
G.add_edge_list(np.transpose(eindexes))
# Add weight information
weight = G.new_ep("double", vals = J[eindexes])

# Assign color to each vertex based on the block it belongs to 
colors = {'B1' : 'k',
          'B2' : 'r',
          'B3' : 'g',
          'B4' : 'b'}
regs = np.asarray(list(N_sizes.keys()))
rindexes = np.cumsum(list(N_sizes.values()))
iidd = regs[np.searchsorted(rindexes,np.arange(np.shape(J)[0]))]
region_id = G.new_vp("string",vals=iidd)
vcolors = [colors[id] for id in iidd]
vertex_color = G.new_vp("string",vals=vcolors)

# Assigns edge colors by out-node.
eid = regs[np.searchsorted(rindexes,np.arange(np.shape(J)[0]))]
ecolors = [mcolors.to_hex(c) for c in regs[np.searchsorted(rindexes,eindexes[0]]] 
edge_color = G.new_ep("string",vals=ecolors)

# Construct a graph in a circular layout with FEB
G = gt.GraphView(G, vfilt=gt.label_largest_component(G))
state = gt.minimize_nested_blockmodel_dl(G)
t = gt.get_hierarchy_tree(state)[0]
tpos = gt.radial_tree_layout(t, t.vertex(t.num_vertices() - 1, use_index=False), weighted=True)
cts = gt.get_hierarchy_control_points(G, t, tpos)
pos = G.own_property(tpos)

gt.graph_draw(G,
              pos = pos,
              vertex_fill_color = vertex_color,
              edge_control_points = cts,
              edge_color = edge_color,
              vertex_anchor = 0)

可以在 this graph-tool 文档页面找到有关圆形布局和这种构建图形方法的其他文档。