二、图的创建
图分有向图和无向图,所以图的创建有各自的实现方式。
1、手工创建图:
1-1 通过文本创建:graph_from_literal
通过每项提供两个顶点名(或ID号)作为一条边的格式,手动创建图,顶点间用减号表示无向边,此时减号的数量不限,一个减号或N个减号都代表两个顶点间存在一条无向边;用加号表示有向边箭头所在的位置。如果函数的参数为空,会创建一个空图。
函数参数中,用来表示顶点name的实参,不需要用引号引起来。
如果图中需要孤立点,只输入顶点名即可。
> graph_from_literal()
IGRAPH 1932ffc U--- 0 0 --
+ edges from 1932ffc:
> g <- graph_from_literal(
+ Alice - Bob - Cecil - Alice,
+ Daniel - Cecil - Eugene,
+ Cecil - Gordon
+ )
> g
IGRAPH 503ae37 UN-- 6 6 --
+ attr: name (v/c)
+ edges from 503ae37 (vertex names):
[1] Alice--Bob Alice--Cecil Bob --Cecil Cecil--Daniel Cecil--Eugene
[6] Cecil--Gordon> graph_from_literal( A--B, C--D, E--F, G--H, I, J, K ) %>% print_all()
IGRAPH a5903c8 UN-- 11 4 --
+ attr: name (v/c)
+ edges from a5903c8 (vertex names):
[1] A--B C--D E--F G--H
:
可以用来定义顶点的集合,用:
连接的顶点属于同一个集合,彼此之间没有边连接,但集合中的每个顶点,与用加号或减号连接的另一个集合中的每一个顶点,都有边连接
> g <- graph_from_literal( A:B:C:D -- T:E:W )
> V(g)$color <- rep(c('red','green'),c(4,3))
> plot(g)
对igraph来说,顶点的name属性值是字符型就可以,所以,也可以将顶点name的值设置为符号,当然这在实践中意义不大:
1-2 搭积木式之加函数:+
如前所述,顶点和边是图的基本元素,并且边是基于顶点形成的关系描述,所以,一定手动创建图,必须先有顶点。
前面说的graph_from_literal
函数,在一个函数内部完成了顶点和边的设置。搭积木的完善图则把顶点和边的创建或删除分离,各自定义了独立的函数,使用户可以“纯手工”打造图。
在已有的图上(只要类是“igraph”就可以,所以这个图可以是一个全空的图),对顶点和边都可以用+ | -
函数,甚至可以直接将一个图加到另一个图上。
前面说过,要用集合的理念来思考图的操作:
- 命名图+命名图:如果两者都是命名图,则执行并集
union
操作
g <- make_ring(10) %>% set_vertex_attr('name',value = letters[1:10])
g2 <- make_ring(5) %>% set_vertex_attr('name',value = letters[1:5])
plot(g+g2)
- 无名图+无名图:如果两者都是无名图,则执行不相交并
disjoint_union
操作
g <- make_ring(10)
g2 <- make_ring(5)
disjoint_union(g,g2) %>% plot()
- 命名图+无名图:如果一个图是命名图,另一个是无名图,结果还是不相交并,但无名图的顶点标签是空
g <- make_ring(10) %>% set_vertex_attr('name',value = letters[1:10])
g2 <- make_ring(5)
plot(g+g2)
- 图+数字:在图中添加数字指定数量的顶点,只添加顶点,不添加边。如果图是无名图,plot的结果显示顶点ID,如果图是命名图,新添加的顶点没有标签。
> par(mfrow=c(1,2))
> g <- make_ring(10)
> plot(g+5)
> title('无名图')
> g <- make_ring(10) %>% set_vertex_attr('name',value = letters[1:10])
> plot(g+5)
> title('命名图')
- 图+字符向量:将字符向量视为顶点的name,在图中添加相应数量的顶点,只添加顶点,不添加边。如果图是无名图,plot时新添加的顶点显示标签,原有的顶点标签显示为空;如果图是命名图,全部显示标签。
- 图+vertice():向图添加参数中提供的顶点,并可以同时设置新添加顶点的属性,这也是本函数的主要用途。
注意:此时,vertice()中的参数默认是新添加顶点的name,即便输入的是数字,也被用作顶点的name,而不是id
g <- make_ring(10) %>% set_vertex_attr('color',value = 'green')%>% set_vertex_attr('name',value = letters[1:10])
plot(g+vertices(1:5,color='red'))
- 图+edges(): 因为边必须依赖顶点而存在,所以新添加的边必须基于图中已有的顶点。如果想添加图中原有顶点之外的顶点的边,必须先添加顶点。
g <- make_ring(10) %>% set_edge_attr('color',value='blue') %>% set_edge_attr('weight',value=4)
(g+edges(sample(1:10,4),color='red',weight=20)) %>% plot()
如果图是无名图,只能用顶点ID设置边,如果是命名图,可以用name属性设置边,当然也可以用顶点ID设置边
- 图+path():安装path()指定的路径添加边。当然,这些顶点必须已经存在于图中
1-3 通过函数添加顶点:add_vertices
与`+vertice()类似,在设置添加顶点数量的同时,可设置顶点属性,两者的区别是:
图 + vertice()
中+是个函数,不需要管道运算符;
add_vertices本身是个函数,需要与管道运算符连用。
make_ring(10) %>% set_vertex_attr('color',value='green') %>% add_vertices(5,color='red') %>% plot()
1-4 通过函数添加边:add_edges
一般与管道运算符连用,可以同时设置边的属性。注意,如果要一次添加多条边,需要用c()
函数将这些边包裹起来。
make_empty_graph(10) %>% set_edge_attr('color',value = 'blue') %>% add_edges(c(1,3,2,4,6,9),color='red') %>% plot()
1-5 删除顶点:delete_vertices
可以通过顶点ID或name删除指定的顶点
如果原图是无名图,通过顶点ID删除顶点后,新图的顶点ID被重新分配
g <- make_ring(10) %>% set_vertex_attr('color',value = 'green') %>% set_vertex_attr(index=7:9,name='color',value = 'red')
plot(g)
g %>% delete_vertices(7:9) %>% plot()
title('删除后所有顶点ID被重新分配')
如果是命名图,新图仍然保留原顶点名
g <- make_(ring(10),with_vertex_(name=letters[1:10]))
plot(g)
g %>% delete_vertices(7:9) %>% plot()
1-6 删除边: delete_edges
- 用边ID指定要删除的边。注意,这里一个坑,前面习惯了用顶点了表述边,主观认为把函数中的参数设置为
c(1,2,5,6)
,会删除顶点1和顶点2之间的边、以及顶点5和顶点6之间的边,一个删除两条边。其实不然,本函数的这个参数,如果直接输入数字的话,igraph把这些数字看作边的ID号,所以,这样设置会删除4条边,不是2条。
g <- make_ring(10)
plot(g)
g %>% delete_edges(c(1,2,5,6)
) %>% plot()
- 想用顶点来指定要删除的边,用
"a|b"
或"3|4"
的格式。注意需要用引号引起来。
g <- make_ring(10)
plot(g)
g %>% delete_edges(c('1|2','5|6')
) %>% plot()
- 或者用
get.edge.ids
函数,也可以将参数中相邻的两个数字解释为顶点的ID,并返回正确的边ID,效果与前面一样。
> get.edge.ids(g,c(1,2,5,6))
[1] 1 5
g %>% delete_edges(get.edge.ids(g,c(1,2,5,6))
) %>% plot()