图的类型
Graph类是无向图的基类,无向图能有自己的属性或参数,不包含重边,允许有回路,节点可以是任何hash的python对象,节点和边可以保存key/value属性对。该类的构造函数为Graph(data=None,**attr),其中data可以是边列表,或任意一个Networkx的图对象,默认为none;attr是关键字参数,例如key=value对形式的属性。
MultiGraph是可以有重边的无向图,其它和Graph类似。其构造函数MultiGraph(data=None, *attr)。
DiGraph是有向图的基类,有向图可以有数自己的属性或参数,不包含重边,允许有回路;节点可以是任何hash的python对象,边和节点可含key/value属性对。该类的构造函数DiGraph(data=None,**attr),其中data可以是边列表,或任意一个Networkx的图对象,默认为none;attr是关键字参数,例如key=value对形式的属性。
MultiDiGraph是可以有重边的有向图,其它和DiGraph类似。其构造函数MultiDiGraph(data=None, *attr)。
图的创建
import networkx as nx G=nx.Graph() #创建了一个没有节点和边的空图
这里的图Graph是由一系列节点及节点对(或者说边、链接)组成。在Networx中,节点可以是任何可以被hash的对象,包括文本字符串、图片、XML对象、Graph和自定义的节点等。
图的节点
图可以以多种方式进行增长。Networkx提供多个图生成功能用于读写图。
一次增加一个节点:
G.add_node(1)
通过包含节点的容器增加节点:#可以是列表、字典、文件的某些行、其它图等
列表
G.add_nodes_from([2,3])
其它图
G.add_nodes_from(H) #H is a graph object here
图的边
一次增加一条边:>>>G.add_edge(1,2)
通过包含边的容器增加:
列表>>>G.add_edges_from([(1,2),(1,3)])
边集合>>>G.add_edges_from(H.edges()) #H is also a graph here
属性
对于图,边和节点都能将key/value对作为自己的属性,保存在相关的dictionary中。该关联字典默认为空,但是能通过add_edge,add_node或操作进行修改。
添加图的属性:
G=nx.Graph(day="Friday")
添加节点的属性:#主要的方法是add_node()和add_nodes_from()
G.add_node(1,time='5pm') #给节点1加属性对time:5pm G.add_nodes_from([3], time='2pm') #对前一个参数中的所有节点,添加属性对time:2pm G.node[1]['room']=714 #为G中的节点1添加属性对room:714
添加边的属性:#主要方法是add_edge(),add_edges()和G.edge
G.add_edge(1,2,'weight'=4.7) #为1和2之间的边,添加属性weight:4.7 G.add_edges_from([(3,4),(4,5)],color='red') #为连接3和4、4和5的边添加属性对color:red G[1][2]['weight']=4.7 G.edge[1][2]['weight']=4
其它
len(G) #返回G中节点数目 n in G #检查节点n是否在G中,如在,返回true。
相关函数
初始化:G=nx.Graph()
图相关属性的函数:
nx.degree(G)// 计算图的密度,其值为边数m除以图中可能边数(即n(n-1)/2)
nx.degree_centrality(G)//节点度中心系数。通过节点的度表示节点在图中的重要性,默认情况下会进行归一化,其值表达为节点度d(u)除以n-1(其中n-1就是归一化使用的常量)。这里由于可能存在循环,所以该值可能大于1.
nx.closeness_centrality(G)//节点距离中心系数。通过距离来表示节点在图中的重要性,一般是指节点到其他节点的平均路径的倒数,这里还乘以了n-1。该值越大表示节点到其他节点的距离越近,即中心性越高。
nx.betweenness_centrality(G)//节点介数中心系数。在无向图中,该值表示为节点作占最短路径的个数除以((n-1)(n-2)/2);在有向图中,该值表达为节点作占最短路径个数除以((n-1)(n-2))。
nx.transitivity(G)//图或网络的传递性。即图或网络中,认识同一个节点的两个节点也可能认识双方,计算公式为3*图中三角形的个数/三元组个数(该三元组个数是有公共顶点的边对数,这样就好数了)。
nx.clustering(G)//图或网络中节点的聚类系数。计算公式为:节点u的两个邻居节点间的边数除以((d(u)(d(u)-1)/2)。
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
二、建立图或网络
1、无向图
在PythonWin 的Shell里输入:
import networkx as nx #导入NetworkX包,为了少打几个字母,将其重命名为nx G = nx.Graph() #建立一个空的无向图G G.add_node(1) #添加一个节点1 G.add_edge(2,3) #添加一条边2-3(隐含着添加了两个节点2、3) G.add_edge(3,2) #对于无向图,边3-2与边2-3被认为是一条边 print G.nodes() #输出全部的节点: [1, 2, 3] print G.edges() #输出全部的边:[(2, 3)] print G.number_of_edges() #输出边的数量:1
这样就可以建立一个简单的无向图了。如果你的数据是存在文件里的,可以循环从文件中读取节点和边添加到G中。
2、有向图
有向图的建立方式和无向图基本类似,只是在上述代码的第二行,将G = nx.Graph() 改为 G = nx.DiGraph() 。需要注意的是,此时再添加边3-2与边2-3,则被认为是两条不同的边(可以试着运行上述代码,自己查看结果)。
同时,有向图和无向图是可以相互转化的,分别用到Graph.to_undirected() 和 Graph.to_directed()两个方法。
3、加权图(网络)
有向图和无向图都可以给边赋予权重,用到的方法是add_weighted_edges_from,它接受1个或多个三元组[u,v,w]作为参数,其中u是起点,v是终点,w是权重。例如:
G.add_weighted_edges_from([(0,1,3.0),(1,2,7.5)])
添加0-1和1-2两条边,权重分别是3.0和7.5。
如果想读取权重,可以使用get_edge_data方法,它接受两个参数u和v,即边的起讫点。例如:
print G.get_edge_data(1,2) #输出{'weight': 7.5},这是一个字典结构,可以查看python语法了解它的用法。
三、调用图算法
NetworkX 提供了常用的图论经典算法,例如DFS、BFS、最短路、最小生成树、最大流等等,非常丰富,如果不做复杂网络,只作图论方面的工作,也可以应用 NetworkX作为基本的开发包。具体的算法调用方法我就不一一介绍了,
可以浏览NX的在线手册http://networkx.lanl.gov /reference/algorithms.html,
对每个算法都提供了详细的帮助文档和示例。
下面只给出一个最短路算法的例子:
path=nx.all_pairs_shortest_path(G) #调用多源最短路径算法,计算图G所有节点间的最短路径 print path[0][2] #输出节点0、2之间的最短路径序列: [0, 1, 2]
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
三、网络可视化
科学可视化是利用计算机图形学来创建视觉图像,帮助人们理解那些采取错综复杂而又往往规模庞大的数字呈现形式的科学概念或结果。对于复杂网络研究来说,可视化技术同样重要,它有助于呈现或解释复杂网络数据和模型,进而从中发现(或许是从数据中不易发现的)各种模式、特点和关系。
在我的另一篇博文《推荐一个复杂网络可视化的网站》中,介绍了www.visualcomplexity.com这个网站,上边有大量复杂网络和复杂系统的图片,五彩缤纷,令人叹为观止。有的朋友可能会想,这些图形是否都是使用一些专业的平面设计软件制作的呢?其实,通过使用NetworkX,我们同样可以制作出精美的复杂网络图形,它提供了非常丰富的网络可视化功能。下边这幅动画就是用从NetworkX网站上下载的图片拼合而成的,感兴趣的朋友可以到http://networkx.lanl.gov/gallery.html这个地址去查看生成这些图形的源代码。
在这篇笔记中,我将简单地介绍使用NetworkX绘制复杂网络图形的基本方法。当然在这方面我也是初学,只略懂一些皮毛,希望能起到抛砖引玉的作用:)
一、基本绘图流程
在NetworkX中,绘制一个网络使用nx.draw()方法,它至少接受一个参数:即你希望绘制的网络G。实际上这个方法非常复杂,它可以指定20多个关键字参数,后边会介绍一些常用的参数,我们先从最简单的情况入手,看看下边的例子:
import networkx as nx #导入networkx包 import matplotlib.pyplot as plt #导入绘图包matplotlib(需要安装,方法见第一篇笔记) G =nx.random_graphs.barabasi_albert_graph(100,1) #生成一个BA无标度网络G nx.draw(G) #绘制网络G plt.savefig("ba.png") #输出方式1: 将图像存为一个png格式的图片文件 plt.show() #输出方式2: 在窗口中显示这幅图像
运行上述代码的结果如下:
这样,用短短的几行代码就完成了一个最基本的网络图形绘制,而且生成了一个功能丰富的窗体。窗口左下方的工具栏可以对图像进行放大、缩小、平移、保存等操作,可以自己动手试一下。同时,在源文件的目录下还生成了一个png格式的图片文件,可以把它插入报告或论文中,是不是很方便呢?
二、运用样式
上边的代码虽然简单,但生成的图形略显单调。NetworkX提供了一系列样式参数,可以用来修饰和美化图形,达到我们想要的效果。常用的参数包括:
- `node_size`: 指定节点的尺寸大小(默认是300,单位未知,就是上图中那么大的点)
- `node_color`: 指定节点的颜色 (默认是红色,可以用字符串简单标识颜色,例如'r'为红色,'b'为绿色等,具体可查看手册)
- `node_shape`: 节点的形状(默认是圆形,用字符串'o'标识,具体可查看手册)
- `alpha`: 透明度 (默认是1.0,不透明,0为完全透明)
- `width`: 边的宽度 (默认为1.0)
- `edge_color`: 边的颜色(默认为黑色)
- `style`: 边的样式(默认为实现,可选: solid|dashed|dotted,dashdot)
- `with_labels`: 节点是否带标签(默认为True)
- `font_size`: 节点标签字体大小 (默认为12)
- `font_color`: 节点标签字体颜色(默认为黑色)
灵活运用上述参数,可以绘制不同样式的网络图形,例如:nx.draw(G,node_size = 30,with_labels = False) 是绘制节点尺寸为30、不带标签的网络图。
三、运用布局
NetworkX在绘制网络图形方面提供了布局的功能,可以指定节点排列的形式。这些布局包括:
circular_layout:节点在一个圆环上均匀分布
random_layout:节点随机分布
shell_layout:节点在同心圆上分布
spring_layout: 用Fruchterman-Reingold算法排列节点(这个算法我不了解,样子类似多中心放射状)
spectral_layout:根据图的拉普拉斯特征向量排列节点?我也不是太明白
布局用pos参数指定,例如:nx.draw(G,pos = nx.circular_layout(G))。在上一篇笔记中,四个不同的模型分别是用四种布局绘制的,可以到那里去看一下效果,此处就不再重复写代码了。
另外,也可以单独为图中的每个节点指定一个位置(x、y坐标),不过比较复杂,我还没有这样做过。感兴趣的朋友可以看一下NetworkX文档中的一个例子:http://networkx.lanl.gov/examples/drawing/knuth_miles.html。
四、添加文本
用 plt.title()方法可以为图形添加一个标题,该方法接受一个字符串作为参数,fontsize参数用来指定标题的大小。例如:plt.title("BA Networks", fontsize = 20)。如果要在任意位置添加文本,则可以采用plt.text()方法。事实上这些功能(包括前边的图形保存等功能)并不是由NetworkX提供的,从包的名字上可以看出,这些绘图函数都是由matplotlib这个包提供的。NetworkX只是把与复杂网络绘图相关的功能重新包装了一下,让用户调用更方便而已。
需要补充的一点是,matplotlib并不直接支持中文文本,如果想输出中文,走正规方法还是挺麻烦的(见http://blog.csdn.net/KongDong/archive/2009/07/10/4338826.aspx)。不过有聪明的网友提出了一种偷梁换柱的解决方案:换字体。只要把一个中文字体文件(ttf文件)更名为Vera.ttf,拷贝到matplotlib的字体目录中覆盖原有文件,就可以输出中文了,具体细节见http://hi.baidu.com/ucherish/blog/item/63155e52b68c90070df3e3ff.html 。
五、小结
这篇笔记简单介绍了用NetworkX绘制复杂网络图形的方法,实际上NetworkX的制图能力是很强的(主要是matplotlib的功劳),本文所介绍的功能只是其中最基础的一部分,更多功能还有待我们一起去发掘。再次推荐 http://networkx.lanl.gov/gallery.html上的绘图示例代码,能看懂弄清这些代码,用NetworkX绘图应该就难不住你了:)