首页 > 解决方案 > 如果源节点和目标节点具有相同的名称,如何使用 networkD3 创建 sankey 图

问题描述

我正在尝试使用包构建桑基图。

我想我已经以正确的方式设置了数据集,从表格开始。这是我的代码:

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()
)

问题是,鉴于这两个变量具有相同的名称,当我创建节点时,它只包含一组“名称”。

因此,如果有人在两个问题中选择了相同的选项,它最终会具有相同的源和目标(请参见下面的示例)

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

可以想象,结果图很奇怪,因为对两个问题提供相同答案的人显示为返回同一来源的圆圈。

重命名第二个问题中的类别是解决问题的唯一可能性吗?或者我做错了什么?

感谢您的支持!

PS 我已经在 ggplot2 中使用了 ggalluvial 包来创建我想要的图形。但是,它不如使用 networkD3 包获得的图那么好(并且可以导出为 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)

标签: rsankey-diagramhtmlwidgetsnetworkd3

解决方案


networkD3::sankeyNetwork中,节点数据框的索引(行号)是链接和节点数据框之间的键,而不是“名称”。因此,您可以在节点数据框中有多个相同的名称,但如果它们旨在识别不同的节点,它们必须位于不同的行上。

例如,假设您有看起来像这样的数据......

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')


推荐阅读