如果源节点和目标节点具有相同的名称,如何使用 networkD3 创建桑基图
How to create a sankey diagram with networkD3 if source and target nodes have the same names
我正在尝试使用 networkd3 package in r 构建桑基图。
我想我已经以正确的方式设置了数据集,从 table 开始。这是我的代码:
M <- data.frame(as.matrix( table(as.character(df$q4.1),as.character(df$q4.2))))
M <- filter(M, Freq !=0)
q4.1 和 q4.2 是两个类别相同的分类变量。我对可视化从 q4.1 到 q4.2 中的答案的流程很感兴趣。
nodes <- data.frame(
name=c(as.character(M$Var1), as.character(M$Var2)) %>% unique()
)
问题是,鉴于这两个变量具有相同的名称,当我创建节点时,它只包含一组 "names"。
因此,如果有人在两个问题中都选择了相同的选项,那么它最终会具有相同的源和目标(参见下面的示例)
M$IDsource <- match(M$Var1, nodes$name)-1
M$IDtarget <- match(M$Var2, nodes$name)-1
M
Var1 Var2 Freq IDsource IDtarget
No idea No idea 16 7 7
如您所想,结果图很奇怪,因为对两个问题提供相同答案的人显示为返回同一来源的圆圈。
是否只有重命名第二个问题中的类别才能解决问题?或者我做错了什么?
感谢支持!
P.S。我已经在 ggplot2 中使用了 ggalluvial 包来创建我想要的图形。但是,它不像使用 networkD3 包获得的图那么好(并且 exportable 作为 htmlwidget),所以我想用 networkD3 重新创建相同的图。
这是我与 ggalluvial 包一起使用的成功代码。
ggplot(data= M, aes(axis1= Var1, axis2= Var2, y= Freq)) + scale_x_discrete(limits = c("Next 6 months", "Next 12-18 Months"), expand=c(0.1, 0.05)) + geom_alluvium() + geom_stratum() + geom_text(stat="stratum", infer.label = TRUE)
在networkD3::sankeyNetwork
中,节点数据框的索引(行号)是链接和节点数据框之间的键,而不是'name'。因此,您可以在节点数据框中有多个相同的名称,但如果它们是为了标识不同的节点,则它们必须位于不同的行上。
例如,假设您的数据看起来像这样...
library(networkD3)
library(dplyr)
M <- expand.grid(Var1 = LETTERS[1:4],
Var2 = LETTERS[1:4],
stringsAsFactors = F)
M$Freq <- sample(1:100, nrow(M))
M
#> Var1 Var2 Freq
#> 1 A A 81
#> 2 B A 84
#> 3 C A 42
#> 4 D A 71
#> 5 A B 9
#> 6 B B 79
#> 7 C B 82
#> 8 D B 76
#> 9 A C 41
#> 10 B C 63
#> 11 C C 95
#> 12 D C 61
#> 13 A D 33
#> 14 B D 2
#> 15 C D 13
#> 16 D D 38
为值添加一些标识符,以便您可以区分它们来自哪个问题,例如...
M$Var1 <- paste0(M$Var1, '_q41')
M$Var2 <- paste0(M$Var2, '_q42')
M
#> Var1 Var2 Freq
#> 1 A_q41 A_q42 9
#> 2 B_q41 A_q42 86
#> 3 C_q41 A_q42 62
#> 4 D_q41 A_q42 26
#> 5 A_q41 B_q42 44
#> 6 B_q41 B_q42 93
#> 7 C_q41 B_q42 36
#> 8 D_q41 B_q42 51
#> 9 A_q41 C_q42 6
#> 10 B_q41 C_q42 5
#> 11 C_q41 C_q42 21
#> 12 D_q41 C_q42 83
#> 13 A_q41 D_q42 40
#> 14 B_q41 D_q42 77
#> 15 C_q41 D_q42 20
#> 16 D_q41 D_q42 85
做同样的事情来获取节点的唯一列表,然后将链接数据框与它们匹配...
nodes <- data.frame(
name=c(as.character(M$Var1), as.character(M$Var2)) %>% unique()
)
M$IDsource <- match(M$Var1, nodes$name)-1
M$IDtarget <- match(M$Var2, nodes$name)-1
nodes
#> name
#> 1 A_q41
#> 2 B_q41
#> 3 C_q41
#> 4 D_q41
#> 5 A_q42
#> 6 B_q42
#> 7 C_q42
#> 8 D_q42
M
#> Var1 Var2 Freq IDsource IDtarget
#> 1 A_q41 A_q42 9 0 4
#> 2 B_q41 A_q42 86 1 4
#> 3 C_q41 A_q42 62 2 4
#> 4 D_q41 A_q42 26 3 4
#> 5 A_q41 B_q42 44 0 5
#> 6 B_q41 B_q42 93 1 5
#> 7 C_q41 B_q42 36 2 5
#> 8 D_q41 B_q42 51 3 5
#> 9 A_q41 C_q42 6 0 6
#> 10 B_q41 C_q42 5 1 6
#> 11 C_q41 C_q42 21 2 6
#> 12 D_q41 C_q42 83 3 6
#> 13 A_q41 D_q42 40 0 7
#> 14 B_q41 D_q42 77 1 7
#> 15 C_q41 D_q42 20 2 7
#> 16 D_q41 D_q42 85 3 7
如果您不希望问题后缀在 Sankey 输出中可见,您可以在您已经匹配正确索引后立即将其删除...
nodes$name <- sub('_q4[1-2]$', '', nodes$name)
然后打印...
sankeyNetwork(M, nodes, 'IDsource', 'IDtarget', 'Freq', 'name')
我正在尝试使用 networkd3 package in r 构建桑基图。
我想我已经以正确的方式设置了数据集,从 table 开始。这是我的代码:
M <- data.frame(as.matrix( table(as.character(df$q4.1),as.character(df$q4.2))))
M <- filter(M, Freq !=0)
q4.1 和 q4.2 是两个类别相同的分类变量。我对可视化从 q4.1 到 q4.2 中的答案的流程很感兴趣。
nodes <- data.frame(
name=c(as.character(M$Var1), as.character(M$Var2)) %>% unique()
)
问题是,鉴于这两个变量具有相同的名称,当我创建节点时,它只包含一组 "names"。
因此,如果有人在两个问题中都选择了相同的选项,那么它最终会具有相同的源和目标(参见下面的示例)
M$IDsource <- match(M$Var1, nodes$name)-1
M$IDtarget <- match(M$Var2, nodes$name)-1
M
Var1 Var2 Freq IDsource IDtarget
No idea No idea 16 7 7
如您所想,结果图很奇怪,因为对两个问题提供相同答案的人显示为返回同一来源的圆圈。
是否只有重命名第二个问题中的类别才能解决问题?或者我做错了什么?
感谢支持!
P.S。我已经在 ggplot2 中使用了 ggalluvial 包来创建我想要的图形。但是,它不像使用 networkD3 包获得的图那么好(并且 exportable 作为 htmlwidget),所以我想用 networkD3 重新创建相同的图。 这是我与 ggalluvial 包一起使用的成功代码。
ggplot(data= M, aes(axis1= Var1, axis2= Var2, y= Freq)) + scale_x_discrete(limits = c("Next 6 months", "Next 12-18 Months"), expand=c(0.1, 0.05)) + geom_alluvium() + geom_stratum() + geom_text(stat="stratum", infer.label = TRUE)
在networkD3::sankeyNetwork
中,节点数据框的索引(行号)是链接和节点数据框之间的键,而不是'name'。因此,您可以在节点数据框中有多个相同的名称,但如果它们是为了标识不同的节点,则它们必须位于不同的行上。
例如,假设您的数据看起来像这样...
library(networkD3)
library(dplyr)
M <- expand.grid(Var1 = LETTERS[1:4],
Var2 = LETTERS[1:4],
stringsAsFactors = F)
M$Freq <- sample(1:100, nrow(M))
M
#> Var1 Var2 Freq
#> 1 A A 81
#> 2 B A 84
#> 3 C A 42
#> 4 D A 71
#> 5 A B 9
#> 6 B B 79
#> 7 C B 82
#> 8 D B 76
#> 9 A C 41
#> 10 B C 63
#> 11 C C 95
#> 12 D C 61
#> 13 A D 33
#> 14 B D 2
#> 15 C D 13
#> 16 D D 38
为值添加一些标识符,以便您可以区分它们来自哪个问题,例如...
M$Var1 <- paste0(M$Var1, '_q41')
M$Var2 <- paste0(M$Var2, '_q42')
M
#> Var1 Var2 Freq
#> 1 A_q41 A_q42 9
#> 2 B_q41 A_q42 86
#> 3 C_q41 A_q42 62
#> 4 D_q41 A_q42 26
#> 5 A_q41 B_q42 44
#> 6 B_q41 B_q42 93
#> 7 C_q41 B_q42 36
#> 8 D_q41 B_q42 51
#> 9 A_q41 C_q42 6
#> 10 B_q41 C_q42 5
#> 11 C_q41 C_q42 21
#> 12 D_q41 C_q42 83
#> 13 A_q41 D_q42 40
#> 14 B_q41 D_q42 77
#> 15 C_q41 D_q42 20
#> 16 D_q41 D_q42 85
做同样的事情来获取节点的唯一列表,然后将链接数据框与它们匹配...
nodes <- data.frame(
name=c(as.character(M$Var1), as.character(M$Var2)) %>% unique()
)
M$IDsource <- match(M$Var1, nodes$name)-1
M$IDtarget <- match(M$Var2, nodes$name)-1
nodes
#> name
#> 1 A_q41
#> 2 B_q41
#> 3 C_q41
#> 4 D_q41
#> 5 A_q42
#> 6 B_q42
#> 7 C_q42
#> 8 D_q42
M
#> Var1 Var2 Freq IDsource IDtarget
#> 1 A_q41 A_q42 9 0 4
#> 2 B_q41 A_q42 86 1 4
#> 3 C_q41 A_q42 62 2 4
#> 4 D_q41 A_q42 26 3 4
#> 5 A_q41 B_q42 44 0 5
#> 6 B_q41 B_q42 93 1 5
#> 7 C_q41 B_q42 36 2 5
#> 8 D_q41 B_q42 51 3 5
#> 9 A_q41 C_q42 6 0 6
#> 10 B_q41 C_q42 5 1 6
#> 11 C_q41 C_q42 21 2 6
#> 12 D_q41 C_q42 83 3 6
#> 13 A_q41 D_q42 40 0 7
#> 14 B_q41 D_q42 77 1 7
#> 15 C_q41 D_q42 20 2 7
#> 16 D_q41 D_q42 85 3 7
如果您不希望问题后缀在 Sankey 输出中可见,您可以在您已经匹配正确索引后立即将其删除...
nodes$name <- sub('_q4[1-2]$', '', nodes$name)
然后打印...
sankeyNetwork(M, nodes, 'IDsource', 'IDtarget', 'Freq', 'name')