这几天在用networkx,官方文档是这个,很全也很详细,这里简单记录一些简单的用法和使用过程中的菜鸡看法。
这篇主要记一下networkx基本图创建和如何画图。
环境
Python 3.6.3
networkx 2.4
matplotlib 2.1.0
这里主要介绍一下networkx中定义的图结构,以及以无向图为例的用法。
图的类型
networkx中规定了四种图:无向图、有向图、多重无向图、多重有向图,所有图允许出现自环。
区别:
名称 | 方向 | 多重边 |
---|---|---|
Graph | 无向 | 无 |
DiGraph | 有向 | 无 |
MultiGraph | 无向 | 有 |
MultiDiGraph | 无向 | 有 |
我的实验中用Graph类型的比较多,所以这里先介绍一下无向图Graph的用法。
在networkx里面,图的点、边的都是xxView这样一个结构,有的时候需要转换一下才能直接读取(具体是个什么我也不知道,但是看起来像个字典,我也是这么理解的)
新建无向图
import networkx
# 新建一个空的无向图G
G = nx.Graph()
加入节点
# 一次加入一个结点
G.add_node(0)
# 从列表中加入节点
G.add_nodes_from([1,2])
# 从另一个图H中合并,path_graph(n)表示生成一个n个结点的路径图
H = nx.path_graph(10)
G.add_nodes_from(H)
以第三种方式加入结点时,H可以作为G的一个结点使用。
加入边
# 一次加入一条边
G.add_edge(1,2)
# 从列表中加入边,注意括号
G.add_edges_from([(1,2),(2,3)])
# 从另一个图H中合并
G.add_edges_from(H.edges)
删除
G.remove_node(1)
G.remove_nodes_from([2,3])
G.remove_edge(5,6)
G.remove_edges_from([(7,8),(8,9)])
删除点边和加入点边操作类似,需要注意的是删除一个点时会删除与之连接的所有边。
查看图
# 查看是否有点1
G.has_node(1)
# 查看是否有边(1,2)
G.has_edge(1,2)
# 查看点的数量
G.order()
G.number_of_nodes()
# 查看边的数量
G.size()
G.number_of_edges()
# 查看所有点
list(G.nodes())
# 查看所有边
list(G.edges())
# 查看图中点1的度
list(G.degree[1])
# 查看图中点1的邻居节点
list(G.adj[1])
list(G[1])
查找邻居节点还有一种是返回一个迭代器,返回格式是:(当前节点,{邻居节点:{属性}},一般在后面有循环的时候用。
# 查看点1的邻居节点
nb = G.neighbors(1)
for i in nb:
print(i)
# 查看所有点的邻居节点
nb_all = G.adjacency()
for i in nb_all:
print(i)
添加属性
添加图的属性
# 引用官方文档例子
# 新建一个图,并添加属性
G = nx.Graph(day="Friday")
# 对已有的图添加属性
G.graph['day'] = "Monday"
添加点的属性
# 新建点时添加权重
G.add_node(1, weight = '10')
# 对已有点添加权重
G.nodes[1][['weight'] = 10
添加边的属性
# 假设给边加入权重
G.add_edge(1,2,weight = '10')
G.add_edges_from([(1,2,{'weight':10}),(2,3,{'weight':15})])
G.add_edges_from([(1,2),(1,3)],weight = '10')
G[1][2]['weight'] = 10
G.edges[1,2]['weight'] = 10
前三种是添加边时添加权重,后两种是对已有的边添加权重,用的时候没发现什么区别。当然除了权weight还可以添加其他属性,比如颜色、距离等,上面的属性都可以是任意数据类型。
无向图的基础内容大概就是这些。
有向图——DiGraph
相比较无向图,有向图多了一个方向,并且在边的存储上多了一个predecessor和successor的区别,因此也可以通过G.in_degree(n)和G.out_degree(n)来查询入度和出度,并且G.degree(n)为两者之和。
并且对于一个有向图DG,可以通过DG.to_undirected()和nx.Graph(DG),使其变为无向图。
# 新建一个空的有向图DG
DG = nx.DiGraph()
# 添加的用法和无向图一样
# 添加边的时候注意方向
DG.add_node(0)
DG.add_nodes_from([1,2])
H = nx.path_graph(10)
DG.add_nodes_from(H)
多重无向图——MutiGraph
暂时还没用到,占坑之后填,(咕咕咕
多重有向图——MutiDiGraph
(咕咕咕
创建完一个图就可以开始画图了。
首先导个包,然后生成一个图:
import matplotlib.pyplot as plt
# 生成一个G(n,p)图,表示n个点,两个点之间是否连接互相独立,并且概率为p
G = nx.fast_gnp_random_graph(10,0.5)
首先直接画图:
nx.draw(G)
plt.show()
画出来的图长这样:
如果觉得点这样分布不好看,可以用pos这个位置参数来调整,pos是一个二维数组,每组数据对应一个点的坐标。
networkx里自带的常用分布有:
circular_layout(G[, scale, center, dim]):点分布在一个圆上
random_layout(G[, center, dim, seed]):随机分布
rescale_layout(pos[, scale]):重新在(-scale,scale)范围内分布
shell_layout(G[, nlist, scale, center, dim]):同心圆上分布
spring_layout(G[, k, pos, fixed, …]):Position nodes using Fruchterman-Reingold force-directed algorithm.(不知道什么算法求得的分布,故放上原文)
spectral_layout(G[, weight, scale, center, dim]):用拉普拉斯矩阵的特征向量分布
比如下面是用自带的circular_layout画出来的图:
pos = nx.circular_layout(G)
nx.draw(G,pos,with_labels = True,node_color = 'pink',node_size = 200)
plt.show()
进阶版画图
有时候我们画一个图,比如在着色问题中想规定一些不同的结点颜色,每次只想画这个图中的部分结点或者部分边,这种时候,就需要用到下面的方法了:
# 画点
draw_networkx_nodes(G, pos, nodelist=None, node_size=300, node_color='#1f78b4', node_shape='o', alpha=None,cmap=None,
vmin=None, vmax=None, ax=None, linewidths=None, edgecolors=None, label=None, **kwds)
# 画边
draw_networkx_edges(G, pos, edgelist=None, width=1.0, edge_color='k', style='solid', alpha=None, arrowstyle='-|>', arrowsize=10,
edge_cmap=None, edge_vmin=None, edge_vmax=None, ax=None, arrows=True, label=None, node_size=300, nodelist=None,
node_shape='o', connectionstyle=None, min_source_margin=0, min_target_margin=0, **kwds)
# 标签
draw_networkx_labels(G, pos, labels=None, font_size=12, font_color='k', font_family='sans-serif', font_weight='normal',
alpha=None, bbox=None, ax=None, **kwds)
# 边的标签
draw_networkx_edge_labels(G, pos, edge_labels=None, label_pos=0.5, font_size=10, font_color='k', font_family='sans-serif',
font_weight='normal', alpha=None, bbox=None, ax=None, rotate=True, **kwds)
这些里面一定要有的参数是G和pos,alpha是透明度,cmap是颜色映射,其他的按需画图就行。
先写到这里8,例子下次再加(咕咕咕