最近需要繪製一些網路演示圖,沒找到合適的繪圖工具,找了半天感覺學習成本都挺高的,感覺還是用Python搞效率高一些。之前用igraph的時候湊巧看過networkx,覺得和igraph-python相比,這個庫至少是給人類用的,而且這個包好像是內置Graphviz的,不如我也用這個加matplotlib去繪圖試試。

今天試著畫一個二分網路無向圖,並且用圈圈表現出其社團關係,顏色表示節點種類。


1. 創建網路

G = nx.Graph()

G.add_node(1)

G.add_nodes_from([2, 3])

#注意如果加進去臨邊有未出現的節點,會自動創建節點
G.add_edge(1, 2)

G.add_edge(1, 2)

#實際上edges是個hash的key,還可以對應一個value
G.add_edge(n1, n2, object=x)

G.add_edges_from([(1, 2), (1, 3)])

list(G.adj[1])

G.degree[1]

G.remove_node(2)
G.remove_edge(1, 3)

2. 為節點添加屬性

G[1][3][color] = "blue"
G.edges[1, 2][color] = "red"

3. 快速遍歷所有臨邊

FG = nx.Graph()
FG.add_weighted_edges_from([(1, 2, 0.125), (1, 3, 0.75), (2, 4, 1.2), (3, 4, 0.375)])
for n, nbrs in FG.adj.items():
for nbr, eattr in nbrs.items():
wt = eattr[weight]
if wt < 0.5: print((%d, %d, %.3f) % (n, nbr, wt))

4. 為圖,節點,邊添加屬性

G = nx.Graph(day="Friday")
G.graph

5. 為節點添加屬性

G.add_node(1, time=5pm)
G.add_nodes_from([3], time=2pm)
G.nodes[1]

G.nodes[1][room] = 714
G.nodes.data()

6. 為臨邊添加屬性

G.add_edge(1, 2, weight=4.7 )
G.add_edges_from([(3, 4), (4, 5)], color=red)
G.add_edges_from([(1, 2, {color: blue}), (2, 3, {weight: 8})])
G[1][2][weight] = 4.7
G.edges[3, 4][weight] = 4.2

#注意的是weight這個屬性不能胡亂用,這個是演算法庫裡面處理時看做臨邊權重的屬性,必須是數值型的。

7. 創建有向圖

DG = nx.DiGraph()
DG.add_weighted_edges_from([(1, 2, 0.5), (3, 1, 0.75)])
#這個方向是按照第一個元素->第二個元素的
DG.out_degree(1, weight=weight) #0.5
DG.degree(1, weight=weight) #1.25

H = nx.Graph(DG)#有向圖轉為無向圖

8. 創建multigraph

>>> MG = nx.MultiGraph()
>>> MG.add_weighted_edges_from([(1, 2, 0.5), (1, 2, 0.75), (2, 3, 0.5)])
>>> dict(MG.degree(weight=weight))
{1: 1.25, 2: 1.75, 3: 0.5}
>>> GG = nx.Graph()
>>> for n, nbrs in MG.adjacency():
... for nbr, edict in nbrs.items():
... minvalue = min([d[weight] for d in edict.values()])
... GG.add_edge(n, nbr, weight = minvalue)
...
>>> nx.shortest_path(GG, 1, 3)
[1, 2, 3]

9. 基礎做圖

G = nx.petersen_graph()
plt.subplot(121)

nx.draw(G, with_labels=True, font_weight=bold)
plt.subplot(122)

#這個draw_shell好像是按照某種叫shell的布局繪製
nx.draw_shell(G, nlist=[range(5, 10), range(5)], with_labels=True, font_weight=bold)

#傳入選項
options = {
node_color: black,
node_size: 100,
width: 3,
}
# 四種布局
plt.subplot(221)
nx.draw_random(G, **options)

plt.subplot(222)
nx.draw_circular(G, **options)

plt.subplot(223)
nx.draw_spectral(G, **options)

plt.subplot(224)
nx.draw_shell(G, nlist=[range(5,10), range(5)], **options)


1. 實戰

1.1 畫一個二分網路圖,兩類節點不同顏色,每個節點上有id,臨邊的顏色代表值,然後畫兩個區域。

B = nx.Graph()

B.add_nodes_from([u1,u2,u3,u4], bipartite=user)
B.add_nodes_from([i1,i2,i3], bipartite=item)

B.add_edge(u1,i1,weight=3)
B.add_edge(u1,i2,weight=4)
B.add_edge(u2,i1,weight=5)
B.add_edge(u2,i3,weight=1)
B.add_edge(u3,i3,weight=3)
B.add_edge(u4,i3,weight=4)

from networkx.algorithms import bipartite
import matplotlib as mpl
#區域就算了 搞了一下午還是沒搗鼓出來怎麼畫
X = [u1,u2,u3,u4]
Y = [i1,i2,i3]
Edges = []
pos = dict()
pos.update( (n, (1, i)) for i, n in enumerate(X) )
pos.update( (n, (2, i+0.5)) for i, n in enumerate(Y) )
nx.draw_networkx_nodes(B, pos, nodelist=X, node_color=slategray,alpha=0.95, node_size = 350, with_labels=False)
nx.draw_networkx_nodes(B, pos, nodelist=Y, node_color=steelblue,alpha=0.95, node_size = 350, with_labels=False)
nx.draw_networkx_labels(B,pos)
colors = [ B.edges[u,i][weight] for u,i in B.edges]
edges = nx.draw_networkx_edges(B, pos = pos, edge_color = colors,
width_=3, edge_cmap=plt.cm.Blues, with_labels=False, edge_vmin = 0, alpha=0.9)
pc = mpl.collections.PatchCollection(Edges, cmap=plt.cm.Blues)
pc.set_array(colors)
plt.colorbar(pc)
ax = plt.gca()
ax.set_axis_off()
plt.show()

推薦閱讀:

相关文章