跳到内容

igraph 是一个用于分析图或网络的快速开源库。该库由 C 编写的核心和高级语言的绑定组成,包括 RPythonMathematica。本指南旨在概述 igraph R 接口中可用的函数。有关详细的函数 API 文档,请查看 https://r.igraph.cn/reference/


注意:在本教程中,我们将交替使用 graphnetwork,以及 vertexnode


安装

要从 CRAN 安装库,请使用

有关依赖项、要求和安装故障排除的更多详细信息,请访问主要的文档页面

用法

要在 R 代码中使用 igraph,必须首先加载库

## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union

现在您可以使用所有 igraph 函数了。

创建图

igraph 提供了多种创建图的方法。最简单的方法是函数 make_empty_graph()

创建图的最常见方法是 make_graph(),它根据指定的边构造网络。例如,要创建一个具有 10 个节点(编号为 110)和两条连接节点 1-21-5 的边的图

g <- make_graph(edges = c(1, 2, 1, 5), n = 10, directed = FALSE)

从 igraph 0.8.0 开始,您还可以通过 igraph 的公式表示法在此处包含文字。在这种情况下,公式的第一项必须以 ~ 字符开头,就像 R 中的常规公式一样。表达式由顶点名称和边运算符组成。边运算符是由 -+ 字符组成的序列,前者用于边,后者用于箭头。边可以任意长,也就是说,您可以使用任意数量的 - 字符来“绘制”它们。如果所有边运算符仅由 - 字符组成,则该图将是无向图,而单个 + 字符表示有向图:也就是说,要创建与上面相同的图

g <- make_graph(~ 1--2, 1--5, 3, 4, 5, 6, 7, 8, 9, 10)

我们可以打印该图以获得其节点和边的摘要

g
## IGRAPH 00a3f39 UN-- 10 2 -- 
## + attr: name (v/c)
## + edges from 00a3f39 (vertex names):
## [1] 1--2 1--5

这意味着:具有 10 个顶点和 2 条边的已命名图,并列出了确切的边。如果图具有 [name] 属性,也会打印出来。


注意: summary() 不会列出边,这对于具有数百万条边的大型图来说很方便


## IGRAPH 00a3f39 UN-- 10 2 -- 
## + attr: name (v/c)

通过仅指定名称,相同的函数 make_graph() 可以创建一些著名的图。例如,您可以创建表示 Zachary 的空手道俱乐部社交网络的图,该图显示了 20 世纪 70 年代美国一所大学空手道俱乐部的 34 名成员之间的友谊

g <- make_graph("Zachary")

要可视化图,可以使用 plot()

plot(g)

本教程稍后将提供有关绘图选项的更详细说明。

顶点和边 ID

顶点和边在 igraph 中具有数字顶点 ID。顶点 ID 始终是连续的,并且从 1 开始。对于具有 n 个顶点的图,顶点 ID 始终在 1 到 n 之间。如果某些操作更改了图中的顶点数,例如通过 induced_subgraph() 创建了子图,则会重新编号顶点以满足此标准。

边也是如此:边 ID 始终在 1 到 m 之间,m 是图中边的总数。


注意: 如果您熟悉 C 核心或 igraphPython 接口,您可能已经注意到在这些语言中,顶点和边 ID 从 0 开始。在 R 接口中,为了与每种语言的约定保持一致,两者都从 1 开始。


除了 ID 之外,还可以为顶点和边分配名称和其他属性。这使得在更改图形时更容易跟踪它们。本教程稍后将显示此模式的示例。

添加/删除顶点和边

让我们继续使用空手道俱乐部图。要将一个或多个顶点添加到现有图中,请使用 add_vertices()

g <- add_vertices(g, 3)

同样,要添加边,可以使用 add_edges()

g <- add_edges(g, edges = c(1, 35, 1, 36, 34, 37))

通过为每条边指定源顶点 ID 和目标顶点 ID 来添加边。此调用添加了三条边,一条连接顶点 135,一条连接顶点 136,一条连接顶点 3437

除了 add_vertices()add_edges() 函数之外,加号运算符还可以用于将顶点或边添加到图中。执行的实际操作取决于右手边参数的类型

g <- g + edges(c(1, 35, 1, 36, 34, 37))

您可以使用 add_vertex()add_edge()(单数)一次添加一个顶点/边。

警告: 如果您需要向图中添加多条边,则一次调用 add_edges() 比重复调用 add_edge() 添加一条新边效率更高。删除边和顶点时也是如此。

如果您尝试将边添加到具有无效 ID 的顶点(即,当图只有 37 个顶点时,您尝试将边添加到顶点 38),则 igraph 会显示错误

g <- add_edges(g, edges = c(38, 37))
## Error in add_edges(g, edges = c(38, 37)): At vendor/cigraph/src/graph/type_indexededgelist.c:261 : Out-of-range vertex IDs when adding edges. Invalid vertex ID

让我们向图中添加更多顶点和边。在 igraph 中,我们可以使用 magrittr 包,它提供了一种使用运算符 %>% 链接命令的机制

g <- g %>%
  add_edges(edges = c(1, 34)) %>%
  add_vertices(3) %>%
  add_edges(edges = c(38, 39, 39, 40, 40, 38, 40, 37))
g
## IGRAPH e53bf1a U--- 40 86 -- Zachary
## + attr: name (g/c)
## + edges from e53bf1a:
##  [1]  1-- 2  1-- 3  1-- 4  1-- 5  1-- 6  1-- 7  1-- 8  1-- 9  1--11  1--12
## [11]  1--13  1--14  1--18  1--20  1--22  1--32  2-- 3  2-- 4  2-- 8  2--14
## [21]  2--18  2--20  2--22  2--31  3-- 4  3-- 8  3--28  3--29  3--33  3--10
## [31]  3-- 9  3--14  4-- 8  4--13  4--14  5-- 7  5--11  6-- 7  6--11  6--17
## [41]  7--17  9--31  9--33  9--34 10--34 14--34 15--33 15--34 16--33 16--34
## [51] 19--33 19--34 20--34 21--33 21--34 23--33 23--34 24--26 24--28 24--33
## [61] 24--34 24--30 25--26 25--28 25--32 26--32 27--30 27--34 28--34 29--32
## [71] 29--34 30--33 30--34 31--33 31--34 32--33 32--34 33--34  1--35  1--36
## + ... omitted several edges

现在我们有一个具有 40 个顶点和 86 条边的无向图。顶点和边 ID 始终是连续的,因此如果您删除一个顶点,所有后续顶点都将被重新编号。重新编号顶点时,边不会重新编号,但它们的源顶点和目标顶点会。使用 delete_vertices()delete_edges() 执行这些操作。例如,要删除连接顶点 1-34 的边,请获取其 ID,然后将其删除

edge_id_to_delete <- get_edge_ids(g, c(1, 34))
edge_id_to_delete
## [1] 82
g <- delete_edges(g, edge_id_to_delete)

例如,要创建一个断环

g <- make_ring(10) %>% delete_edges("10|1")
plot(g)

上面的示例表明,您还可以使用包含由管道符号 | 连接的源顶点和目标顶点的 ID 的字符串来引用边。上面的示例中的 "10|1" 表示连接顶点 10 和顶点 1 的边。当然,您也可以直接使用边 ID,或使用 get_edge_ids() 函数检索它们

g <- make_ring(5)
g <- delete_edges(g, get_edge_ids(g, c(1, 5, 4, 5)))
plot(g)

作为另一个示例,让我们创建一个弦图。请记住,如果一个图的四个或更多节点的每个循环都有一条弦,该弦是连接循环中不相邻的两个节点的边,则该图是弦图(或三角化图)。首先,让我们使用 graph_from_literal() 创建初始图

g1 <- graph_from_literal(
  A - B:C:I, B - A:C:D, 
  C - A:B:E:H, 
  D - B:E:F,
  E - C:D:F:H, 
  F - D:E:G, 
  G - F:H, 
  H - C:E:G:I,
  I - A:H
)
plot(g1)

在上面的示例中,: 运算符用于定义顶点集。如果边运算符连接两个顶点集,则第一个集中的每个顶点将连接到第二个集中的每个顶点。然后我们使用 is_chordal() 来评估我们的图是否是弦图,并搜索缺少哪些边来填充图

is_chordal(g1, fillin = TRUE)
## $chordal
## [1] FALSE
## 
## $fillin
##  [1] 2 6 8 7 5 7 2 7 6 1 7 1
## 
## $newgraph
## NULL

然后,我们可以添加使初始图成为弦图所需的边,只需一行代码

chordal_graph <- add_edges(g1, is_chordal(g1, fillin = TRUE)$fillin)
plot(chordal_graph)

构造图

除了 make_empty_graph()make_graph()make_graph_from_literal() 之外,igraph 还包括许多其他用于构造图的函数。有些是确定性的,也就是说,它们每次都会生成相同的图,例如 make_tree()

graph1 <- make_tree(127, 2, mode = "undirected")
summary(graph1)
## IGRAPH 641fc76 U--- 127 126 -- Tree
## + attr: name (g/c), children (g/n), mode (g/c)

这将生成一个具有 127 个顶点的规则树图,每个顶点有两个子节点。无论您调用 make_tree() 多少次,如果您使用相同的参数,生成的图将始终相同

graph2 <- make_tree(127, 2, mode = "undirected")
identical_graphs(graph1, graph2)
## [1] TRUE

其他函数随机地生成图,这意味着它们每次都会生成不同的图。例如 sample_grg()

graph1 <- sample_grg(100, 0.2)
summary(graph1)
## IGRAPH ae34a8f U--- 100 499 -- Geometric random graph
## + attr: name (g/c), radius (g/n), torus (g/l)

这将生成一个几何随机图:n 个点在单位正方形内随机且均匀地选择,并且彼此之间的距离小于预定义距离 d 的点对通过边连接。如果您使用相同的参数生成 GRG,它们将是不同的

graph2 <- sample_grg(100, 0.2)
identical_graphs(graph1, graph2)
## [1] FALSE

一种稍微宽松的检查图是否等效的方法是通过 isomorphic。如果两个图具有相同数量的组件(顶点和边)并且在顶点和边之间保持一对一的对应关系,则称它们是同构的,也就是说,它们以相同的方式连接。

isomorphic(graph1, graph2)
## [1] FALSE

对于大型图,检查同构可能需要一段时间(在这种情况下,可以通过检查两个图的度序列来快速给出答案)。identical_graph()isomorphic() 具有更严格的标准:两个图必须具有相同的顶点和边列表,顺序完全相同,方向相同,并且两个图还必须具有相同的图、顶点和边属性。

设置和检索属性

除了 ID 之外,顶点和边还可以具有属性,例如名称、绘图坐标、元数据和权重。图本身也可以具有这样的属性(例如名称,它将显示在 summary() 中)。从某种意义上说,每个图、顶点和边都可以用作 R 命名空间来存储和检索这些属性。

为了演示属性的使用,让我们创建一个简单的社交网络

g <- make_graph(
  ~ Alice - Boris:Himari:Moshe, Himari - Alice:Nang:Moshe:Samira,
  Ibrahim - Nang:Moshe, Nang - Samira
)

每个顶点代表一个人,因此我们想要存储年龄、性别以及两个人之间的连接类型(is_formal() 指的是一个人或另一个人之间的连接是正式的还是非正式的,分别是同事或朋友)。$ 运算符是获取和设置图属性的快捷方式。它比 graph_attr()set_graph_attr() 更短,并且同样可读。

V(g)$age <- c(25, 31, 18, 23, 47, 22, 50)
V(g)$gender <- c("f", "m", "f", "m", "m", "f", "m")
E(g)$is_formal <- c(FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE)
summary(g)
## IGRAPH 3656e28 UN-- 7 9 -- 
## + attr: name (v/c), age (v/n), gender (v/c), is_formal (e/l)

V()E() 分别是获取所有顶点和边的序列的标准方法。这将属性一次分配给所有顶点/边。生成我们的社交网络的另一种方法是使用 set_vertex_attr()set_edge_attr() 以及运算符 %>%

g <- make_graph(
  ~ Alice - Boris:Himari:Moshe, Himari - Alice:Nang:Moshe:Samira,
  Ibrahim - Nang:Moshe, Nang - Samira
) %>%
  set_vertex_attr("age", value = c(25, 31, 18, 23, 47, 22, 50)) %>%
  set_vertex_attr("gender", value = c("f", "m", "f", "m", "m", "f", "m")) %>%
  set_edge_attr("is_formal", value = c(FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE))
summary(g)

要为单个顶点/边分配或修改属性

E(g)$is_formal
## [1] FALSE FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE FALSE
E(g)$is_formal[1] <- TRUE
E(g)$is_formal
## [1]  TRUE FALSE  TRUE  TRUE  TRUE FALSE  TRUE FALSE FALSE

属性值可以设置为任何 R 对象,但请注意,以某些文件格式存储图可能会导致复杂属性值的丢失。顶点、边和图本身都可以用于设置属性,例如向图中添加日期

g$date <- c("2022-02-11")
graph_attr(g, "date")
## [1] "2022-02-11"

要检索属性,您还可以使用 graph_attr()vertex_attr()edge_attr()。要查找顶点的 ID,您可以使用函数 match()

match(c("Ibrahim"), V(g)$name)
## [1] 7

要将属性分配给顶点或边的子集,您可以使用

V(g)$name[1:3] <- c("Alejandra", "Bruno", "Carmina")
V(g)
## + 7/7 vertices, named, from 3656e28:
## [1] Alejandra Bruno     Carmina   Moshe     Nang      Samira    Ibrahim

要删除属性

g <- delete_vertex_attr(g, "gender")
V(g)$gender
## NULL

如果您想使用所有属性将图保存在 R 中,请使用 saveRDS()(然后使用 readRDS() 检索它)。

图的结构属性

igraph 提供了一大组函数来计算图的各种结构属性。记录所有这些函数超出了本教程的范围,因此本节仅介绍其中的几个函数以用于说明目的。我们将使用上一节中构建的小型社交网络。

人们可以想到的最简单的属性可能是。顶点的度等于与其相邻的边数。在有向网络的情况下,我们还可以定义入度(指向顶点的边数)和出度(源自顶点的边数)。igraph 能够使用简单的语法计算所有这些

## Alejandra     Bruno   Carmina     Moshe      Nang    Samira   Ibrahim 
##         3         1         4         3         3         2         2

如果该图是有向图,我们将能够使用 degree(mode = "in")degree(mode = "out") 分别计算入度和出度。如果您只想计算顶点子集的度,还可以将单个顶点 ID 或顶点 ID 列表传递给 degree()

degree(g, 7)
## Ibrahim 
##       2
degree(g, v = c(3, 4, 5))
## Carmina   Moshe    Nang 
##       4       3       3

大多数接受顶点 ID 的函数也接受顶点名称name 顶点属性的值),只要这些名称是唯一的

degree(g, v = c("Carmina", "Moshe", "Nang"))
## Carmina   Moshe    Nang 
##       4       3       3

它也适用于单个顶点

degree(g, "Bruno")
## Bruno 
##     1

igraph 可以计算的大多数结构属性都使用类似的语法。对于顶点属性,这些函数接受顶点 ID、顶点名称或顶点 ID 或名称的列表(如果省略它们,则默认为所有顶点的集合)。对于边属性,这些函数接受单个边 ID 或边 ID 的列表。


注意:对于某些度量,仅针对少数顶点或边而不是整个图计算它们没有意义,因为无论如何都需要相同的时间。在这种情况下,这些函数将不接受顶点或边 ID,但您仍然可以使用标准操作稍后限制结果列表。一个这样的示例是特征向量中心性 (evcent())。


除了度之外,igraph 还包括内置例程来计算许多其他中心性属性,包括顶点和边介数 (edge_betweenness()) 或 Google 的 PageRank (page_rank()),仅举几例。在这里,我们仅说明边介数

## [1] 6 6 4 3 4 4 4 2 3

现在我们还可以找出哪些连接具有最高的介数中心性

ebs <- edge_betweenness(g)
as_edgelist(g)[ebs == max(ebs), ]
##      [,1]        [,2]     
## [1,] "Alejandra" "Bruno"  
## [2,] "Alejandra" "Carmina"

基于属性查询顶点和边

选择顶点

想象一下,在给定的社交网络中,您想找出谁的度最大。您可以使用到目前为止介绍的工具和 which.max() 函数来实现此目的

## Carmina 
##       3

另一个示例是仅选择具有奇数 ID 而不选择偶数 ID 的顶点,使用 V() 函数

graph <- graph.full(n = 10)
## Warning: `graph.full()` was deprecated in igraph 2.1.0.
##  Please use `make_full_graph()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
only_odd_vertices <- which(V(graph) %% 2 == 1)
length(only_odd_vertices)
## [1] 5

当然,可以通过位置索引选择顶点或边

seq <- V(graph)[2, 3, 7]
seq
## + 3/10 vertices, from a0c145b:
## [1] 2 3 7
seq <- seq[1, 3] # filtering an existing vertex set
seq
## + 2/10 vertices, from a0c145b:
## [1] 2 7

选择不存在的顶点会导致错误

seq <- V(graph)[2, 3, 7, "foo", 3.5]
## Error in simple_vs_index(x, ii, na_ok) : Unknown vertex selected

属性名称也可以按原样在 V()E() 的索引括号中使用。这可以与 R 使用布尔向量进行索引的能力相结合,以获得非常简洁和可读的表达式来检索图的顶点或边集的子集。例如,以下命令为您提供了我们的社交网络中年龄小于 30 岁的人的姓名

V(g)[age < 30]$name
## [1] "Alejandra" "Carmina"   "Moshe"     "Samira"

当然,< 不是唯一可以用于此目的的布尔运算符。其他可能性包括以下

运算符 含义
== 属性/属性值必须等于
!= 属性/属性值必须不等于
< 属性/属性值必须小于
<= 属性/属性值必须小于或等于
> 属性/属性值必须大于
>= 属性/属性值必须大于或等于
%in% 属性/属性值必须包含在

您还可以使用 Negate() 函数从 %in% 创建一个“not in”运算符

`%notin%` <- Negate(`%in%`)

如果属性的名称与 igraph 函数的名称相同,您应该小心,因为语法可能会变得有些混乱。例如,如果有一个名为 degree 的属性表示每个人考试的成绩,则不应将其与计算网络中顶点的度的 igraph 函数混淆

V(g)$degree <- c("A", "B", "B+", "A+", "C", "A", "B")
V(g)$degree[degree(g) == 3]
## [1] "A"  "A+" "C"
V(g)$name[degree(g) == 3]
## [1] "Alejandra" "Moshe"     "Nang"

选择边

可以像选择顶点一样基于属性选择边。如上所述,获取边的标准方法是 E。此外,还有一些用于选择边的特殊结构属性。

使用 .from() 允许您根据边的源顶点过滤边序列。例如,要选择所有源自 Carmina(顶点索引为 3)的边

E(g)[.from(3)]
## + 4/9 edges from 3656e28 (vertex names):
## [1] Alejandra--Carmina Carmina  --Moshe   Carmina  --Nang    Carmina  --Samira

当然,它也适用于顶点名称

E(g)[.from("Carmina")]
## + 4/9 edges from 3656e28 (vertex names):
## [1] Alejandra--Carmina Carmina  --Moshe   Carmina  --Nang    Carmina  --Samira

使用 .to() 根据目标顶点过滤边序列。如果图是有向图,则这与 .from() 不同,而对于无向图,它会给出相同的答案。使用 .inc() 仅选择那些入射到单个顶点或至少一个顶点的边,而不考虑边的方向。

%--% 运算符可用于选择特定顶点组之间的边,忽略有向图中的边方向。例如,以下表达式选择 Carmina(顶点索引 3)、Nang(顶点索引 5)和 Samira(顶点索引 6)之间的所有边

E(g)[3:5 %--% 5:6]
## + 3/9 edges from 3656e28 (vertex names):
## [1] Carmina--Nang   Carmina--Samira Nang   --Samira

要使 %--% 运算符与名称一起使用,您可以构建包含名称的字符串向量,然后将这些向量用作操作数。例如,要选择所有将男性连接到女性的边,我们可以在重新添加我们之前删除的性别属性后执行以下操作

V(g)$gender <- c("f", "m", "f", "m", "m", "f", "m")
men <- V(g)[gender == "m"]$name
men
## [1] "Bruno"   "Moshe"   "Nang"    "Ibrahim"
women <- V(g)[gender == "f"]$name
women
## [1] "Alejandra" "Carmina"   "Samira"
E(g)[men %--% women]
## + 5/9 edges from 3656e28 (vertex names):
## [1] Alejandra--Bruno  Alejandra--Moshe  Carmina  --Moshe  Carmina  --Nang  
## [5] Nang     --Samira

将图视为邻接矩阵

邻接矩阵是表示图的另一种方式。在邻接矩阵中,行和列由图顶点标记,矩阵的元素表示顶点 ij 之间的边数。示例图的邻接矩阵是

## 7 x 7 sparse Matrix of class "dgCMatrix"
##           Alejandra Bruno Carmina Moshe Nang Samira Ibrahim
## Alejandra         .     1       1     1    .      .       .
## Bruno             1     .       .     .    .      .       .
## Carmina           1     .       .     1    1      1       .
## Moshe             1     .       1     .    .      .       1
## Nang              .     .       1     .    .      1       1
## Samira            .     .       1     .    1      .       .
## Ibrahim           .     .       .     1    1      .       .

例如,Carmina (1, 0, 0, 1, 1, 1, 0) 直接连接到 Alejandra(顶点索引为 1)、Moshe(索引 4)、Nang(索引 5)和 Samira(索引 6),但不连接到 Bruno(索引 2)或 Ibrahim(索引 7)。

布局和绘图

图是一个抽象的数学对象,在 2D、3D 或任何其他几何空间中没有特定的表示形式。这意味着每当我们想要可视化图时,我们必须首先找到从顶点到二维或三维空间坐标的映射,最好以一种有用和/或令人赏心悦目的方式。图论的一个单独分支,即图绘制,试图通过几种图布局算法来解决这个问题。igraph 实现了相当多的布局算法,并且还能够将它们绘制到屏幕上或 R 本身支持的任何输出格式。

布局算法

igraph 中的布局函数始终以 layout 开头。下表总结了它们

方法名称 算法描述
layout_randomly 完全随机地放置顶点
layout_in_circle 确定性布局,将顶点放置在圆上
layout_on_sphere 确定性布局,将顶点均匀地放置在球体表面上
layout_with_drl 用于大型图的 Drl(分布式递归布局)算法
layout_with_fr Fruchterman-Reingold 力导向算法
layout_with_kk Kamada-Kawai 力导向算法
layout_with_lgl 用于大型图的 LGL(大型图布局)算法
layout_as_tree Reingold-Tilford 树布局,适用于(几乎)树状图
layout_nicely 布局算法,根据图的某些属性自动选择其他算法之一

可以直接使用图作为其第一个参数调用布局算法。它们将返回一个矩阵,该矩阵具有两列,其行数与图中的顶点数一样多;每一行将对应于单个顶点的位置,按顶点 ID 排序。一些算法具有 3D 变体;在这种情况下,它们返回 3 列而不是 2 列。

layout <- layout_with_kk(g)

某些布局算法采用其他参数;例如,在将图布局为树时,指定哪个顶点放置在布局的根目录中可能是有意义的

layout <- layout_as_tree(g, root = 2)

使用布局绘制图

我们可以使用 Kamada-Kawai 布局算法绘制我们的虚拟社交网络,如下所示

layout <- layout_with_kk(g)
plot(g, layout = layout, main = "Social network with the Kamada-Kawai layout algorithm")

这应该打开一个新窗口,显示网络的视觉表示。请记住,由于布局不是确定性的,因此节点的确切位置在您的机器上可能会有所不同。

layout 参数也接受函数;在这种情况下,将使用该图作为其第一个参数调用该函数。这使得可以直接传递布局函数的名称,而无需创建布局变量

plot(
  g,
  layout = layout_with_fr,
  main = "Social network with the Fruchterman-Reingold layout algorithm"
)

为了改善视觉效果,一个简单的补充是根据性别为顶点着色。我们还应该尝试将标签稍微放在顶点之外,以提高可读性

V(g)$color <- ifelse(V(g)$gender == "m", "yellow", "red")
plot(
  g,
  layout = layout, vertex.label.dist = 3.5,
  main = "Social network - with genders as colors"
)

您还可以将 gender 属性视为一个因子,并使用参数为 plot() 提供颜色,这优先于 color 顶点属性。颜色将自动分配给因子的级别

plot(g, layout = layout, vertex.label.dist = 3.5, vertex.color = as.factor(V(g)$gender))

如上所述,使用 vertex.color 参数,您可以将视觉属性指定为 plot 的参数,而不是使用顶点或边属性。以下图显示了带有粗线的正式联系,而带有细线的非正式联系

plot(g,
  layout = layout, vertex.label.dist = 3.5, vertex.size = 20,
  vertex.color = ifelse(V(g)$gender == "m", "yellow", "red"),
  edge.width = ifelse(E(g)$is_formal, 5, 1)
)

如果您想将图的视觉表示的属性与图本身分开,则后一种方法是首选方法。

总而言之,有一些特殊的顶点和边属性对应于图的视觉表示。这些属性会覆盖 igraph 的默认设置(即颜色、权重、名称、形状、布局等)。以下两个表分别总结了最常用的顶点和边的视觉属性

控制图绘图的顶点属性

属性名称 关键字参数 目的
color vertex.color 顶点的颜色
label vertex.label 顶点的标签。它们将被转换为字符。指定 NA 以省略顶点标签。默认的顶点标签是顶点 ID。
label.cex vertex.label.cex 顶点标签的字体大小,解释为乘法因子,类似于 R 的 text 函数
label.color vertex.label.color 顶点标签的颜色
label.degree vertex.label.degree 它定义了顶点标签相对于顶点中心的位置。它被解释为弧度角,零表示“向右”,‘pi’表示向左,向上是 -pi/2,向下是 pi/2。默认值为 -pi/4
label.dist vertex.label.dist 顶点标签与顶点本身之间的距离,相对于顶点大小
label.family vertex.label.family 顶点的字体系列,类似于 R 的 text 函数
label.font vertex.label.font 顶点字体系列中的字体,类似于 R 的 text 函数
shape vertex.shape 顶点的形状,当前支持“circle”、“square”、“csquare”、“rectangle”、“crectangle”、“vrectangle”、“pie”(请参阅 vertex.shape.pie)、‘sphere’ 和“none”,并且仅由 plot.igraph 命令支持。
size vertex.size 顶点的大小,一个数值标量或向量,在后一种情况下,每个顶点的大小可能不同

控制图绘图的边属性

属性名称 关键字参数 目的
color edge.color 边的颜色
curved edge.curved 一个数值指定边的曲率;零曲率表示直边,负值表示边顺时针弯曲,正值表示相反方向弯曲。TRUE 表示曲率 0.5,FALSE 表示曲率零
arrow.size edge.arrow.size 当前这是一个常量,因此对于每条边都是相同的。如果提交一个向量,则仅使用第一个元素,也就是说,如果这是从边属性获取的,则仅使用第一条边的属性用于所有箭头。
arrow.width edge.arrow.width 箭头的宽度。当前这是一个常量,因此对于每条边都是相同的
width edge.width 边的宽度(以像素为单位)
label edge.label 如果指定,它会向边添加标签。
label.cex edge.label.cex 边标签的字体大小,解释为乘法因子,类似于 R 的 text 函数
label.color edge.label.color 边标签的颜色
label.family edge.label.family 边的字体系列,类似于 R 的 text 函数
label.font edge.label.font 边字体系列中的字体,类似于 R 的 text 函数

plot() 的通用参数

可以将这些设置指定为 plot 函数的参数,以控制绘图的整体外观。

关键字参数 目的
layout 要使用的布局。它可以是 Layout 的实例、包含 X-Y 坐标的元组列表或布局算法的名称。默认值为 auto,它会根据图的大小和连通性自动选择布局算法。
margin 绘图下方、上方、左侧和右侧的空白量,它是长度为 4 的数字向量。

igraph 和外部世界

如果没有某种导入/导出功能,任何图模块都不会完整,这些功能使软件包能够与外部程序和工具包进行通信。igraph 也不例外:它提供了读取最常见的图格式并将图保存到文件中以遵守这些格式规范的功能。用于从文件读取和写入的主要函数分别是 read_graph()write_graph()。下表总结了 igraph 可以读取或写入的格式

格式 简称 读取函数 写入函数
邻接表(又名 LGL lgl read_graph(file, format = c("lgl")) write_graph(graph, file, format = c("lgl"))
邻接矩阵 adjacency graph_from_adjacency_matrix(adjmatrix, mode = c("directed", "undirected", "max", "min", "upper","lower", "plus"), weighted = NULL, diag = TRUE, add.colnames = NULL, add.rownames = NA) as.matrix(graph, "adjacency")
DIMACS dimacs read_graph(file, format = c("dimacs")) write_graph(graph, file, format = c("dimacs"))
边列表 edgelist read_graph(file, format = c("edgelist")) write_graph(graph, file, format = c("edgelist"))
GraphViz dot 尚不支持 write_graph(graph, file, format = c("dot"))
GML gml read_graph(file, format = c("gml")) write_graph(graph, file, format = c("gml"))
GraphML graphml read_graph(file, format = c("graphml")) write_graph(graph, file, format = c("graphml"))
LEDA leda 尚不支持 write_graph(graph, file, format = c("leda"))
带标签的边列表(又名 NCOL ncol read_graph(file, format = c("ncol")) write_graph(graph, file, format = c("ncol"))
Pajek 格式 pajek read_graph(file, format = c("pajek")) write_graph(graph, file, format = c("pajek"))

注意: 每种文件格式都有其自身的局限性。例如,并非所有格式都可以存储属性。如果您想以可以从外部包读取的格式保存 igraph 图,并且想要保留数字和字符串属性,那么最好的选择可能是 GraphML 或 GML。如果没有属性,边列表和 NCOL 也不错(NCOL 支持顶点名称和边权重)。


下一步去哪里

本教程是对 R 中 igraph 的简要介绍。我们衷心希望您喜欢阅读它,并且它对您自己的网络分析有用。

有关特定功能的详细描述,请参见 https://r.igraph.cn/reference/。如有关于如何使用 igraph 的问题,请访问我们的 论坛。要报告错误,请打开一个 Github issue。请不要直接在 Github 上提出使用问题,因为它主要是为开发人员而不是用户准备的。

会话信息

为了方便重现,上面代码的会话信息如下

## R version 4.5.1 (2025-06-13)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.2 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
## 
## locale:
##  [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
##  [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
##  [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
## [10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   
## 
## time zone: UTC
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] igraph_2.1.4.9069
## 
## loaded via a namespace (and not attached):
##  [1] crayon_1.5.3       vctrs_0.6.5        cli_3.6.5          knitr_1.50        
##  [5] rlang_1.1.6        xfun_0.52          textshaping_1.0.1  jsonlite_2.0.0    
##  [9] glue_1.8.0         htmltools_0.5.8.1  ragg_1.4.0         sass_0.4.10       
## [13] rmarkdown_2.29     grid_4.5.1         evaluate_1.0.4     jquerylib_0.1.4   
## [17] fastmap_1.2.0      yaml_2.3.10        lifecycle_1.0.4    compiler_4.5.1    
## [21] fs_1.6.6           htmlwidgets_1.6.4  pkgconfig_2.0.3    lattice_0.22-7    
## [25] systemfonts_1.2.3  digest_0.6.37      R6_2.6.1           pillar_1.11.0     
## [29] magrittr_2.0.3     Matrix_1.7-3       bslib_0.9.0        tools_4.5.1       
## [33] pkgdown_2.1.3.9000 cachem_1.1.0       desc_1.4.3