R netWorkD3 Sankey - 通过 js 添加百分比不起作用

发布于 2025-01-11 09:07:34 字数 2767 浏览 1 评论 0原文

我正在使用 networkD3::sankeyNetwork() 使用以下示例数据和脚本在 R 中创建桑基图。我想显示节点标签之外的百分比。

我创建的具有完整数据集的 sankey 有 8 层。我只是在下面的代码中发布了一段数据。

library("networkD3")
library("htmlwidgets")
library("dplyr")

a <- read.csv(header = TRUE, text = "
date,dataCenter,customer,companyID,source,target,value

")

node_names <- unique(c(as.character(a$source), as.character(a$target)))
nodes <- data.frame(name = node_names)
links <- data.frame(source = match(a$source, node_names) - 1,
                    target = match(a$target, node_names) - 1,
                    value = a$value)

# group by source and calculate the percentage of each node
g <- a %>%
  group_by(source) %>%
  summarize(cnt = n()) %>%
  mutate(freq = round(cnt / sum(cnt) * 100, 2)) %>%
  arrange(desc(freq))


nodes$name <- sub('(.*)_\\d+', '\\1', nodes$name)
links$linkgroup <- "linkgrp"
colourScale <- 
  'd3.scaleOrdinal()
     .domain(["linkgrp"])
     .range(["gainsboro"].concat(d3.schemeCategory20))'

p <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
              Target = "target", Value = "value", NodeID = "name",
              fontSize = 9,
              fontFamily = "sans-serif", nodePadding=10,
              margin = list(t=100),
              sinksRight = FALSE, iterations = 0,
              LinkGroup = "linkgroup", 
              colourScale = colourScale)

showLabel_string <- 
  'function(el, x){
    d3.select(el).selectAll(".node text")
      .text(d => d.name + " (" + d.value + ")");}'

addTitle_string <-
  'function(el) { 
    var cols_x = this.sankey.nodes().map(d => d.x+15).filter((v, i, a) => a.indexOf(v) === i).sort(function(a, b){return a - b});
    cols_x.forEach((d, i) => {
    d3.select(el)
    .select("svg")
    .append("text")
    .attr("x", d)
    .attr("y", 0).text("step" + (i + 1))
    .style("font-size", "12px")
    .style("font-family", "sans-serif")
    .style("text-orientation", "upright");})
  }'

p <- htmlwidgets::onRender(x = p, jsCode = showLabel_string)
p <- htmlwidgets::onRender(x = p, jsCode = addTitle_string)
p <- htmlwidgets::prependContent(p, htmltools::tags$h3("Opportunity Marketing User Behavior Monitor"))
p

现在我想显示每个节点标签和计数之外的百分比。我已经通过下面的脚本计算了百分比值,但是如何将其放在节点标签和计数之后?

我意识到下面计算每个节点百分比的方法是不正确的,因为当按“源”列分组时,最后一层中的节点会被遗漏,因为它们仅用作“目标”节点。我在帖子中用新图片更新了预期结果,该图片更清楚地显示了百分比的显示方式。一般来说,该百分比应遵循能量守恒定律。有可能实现吗?

g <- a %>%
  group_by(source) %>%
  summarize(cnt = n()) %>%
  mutate(freq = round(cnt / sum(cnt) * 100, 2)) %>%
  arrange(desc(freq))

预期结果是 输入图片此处描述

I'm creating a sankey chart in R with networkD3::sankeyNetwork() with the below sample data and script. I want to show percentage besides the node label.

the sankey with full dataset i create has 8 layers. i just post piece of data in below code.

library("networkD3")
library("htmlwidgets")
library("dplyr")

a <- read.csv(header = TRUE, text = "
date,dataCenter,customer,companyID,source,target,value

")

node_names <- unique(c(as.character(a$source), as.character(a$target)))
nodes <- data.frame(name = node_names)
links <- data.frame(source = match(a$source, node_names) - 1,
                    target = match(a$target, node_names) - 1,
                    value = a$value)

# group by source and calculate the percentage of each node
g <- a %>%
  group_by(source) %>%
  summarize(cnt = n()) %>%
  mutate(freq = round(cnt / sum(cnt) * 100, 2)) %>%
  arrange(desc(freq))


nodes$name <- sub('(.*)_\\d+', '\\1', nodes$name)
links$linkgroup <- "linkgrp"
colourScale <- 
  'd3.scaleOrdinal()
     .domain(["linkgrp"])
     .range(["gainsboro"].concat(d3.schemeCategory20))'

p <- sankeyNetwork(Links = links, Nodes = nodes, Source = "source",
              Target = "target", Value = "value", NodeID = "name",
              fontSize = 9,
              fontFamily = "sans-serif", nodePadding=10,
              margin = list(t=100),
              sinksRight = FALSE, iterations = 0,
              LinkGroup = "linkgroup", 
              colourScale = colourScale)

showLabel_string <- 
  'function(el, x){
    d3.select(el).selectAll(".node text")
      .text(d => d.name + " (" + d.value + ")");}'

addTitle_string <-
  'function(el) { 
    var cols_x = this.sankey.nodes().map(d => d.x+15).filter((v, i, a) => a.indexOf(v) === i).sort(function(a, b){return a - b});
    cols_x.forEach((d, i) => {
    d3.select(el)
    .select("svg")
    .append("text")
    .attr("x", d)
    .attr("y", 0).text("step" + (i + 1))
    .style("font-size", "12px")
    .style("font-family", "sans-serif")
    .style("text-orientation", "upright");})
  }'

p <- htmlwidgets::onRender(x = p, jsCode = showLabel_string)
p <- htmlwidgets::onRender(x = p, jsCode = addTitle_string)
p <- htmlwidgets::prependContent(p, htmltools::tags$h3("Opportunity Marketing User Behavior Monitor"))
p

Now I want to show the percentage besides each node label and count. I have already calculate the percentage value by below scirpt, but how to put it after node label and count?

I realize that below way to calculate the percentage for each node is not correct because when grouping by 'source' column, the nodes in last layer are missed as they are working as 'target' nodes only. I update the expected result with a new picture in the post which is more clear for how the percentage shown. In general, the percentage should follow the conservation of energy. Is it possible to achieved?

g <- a %>%
  group_by(source) %>%
  summarize(cnt = n()) %>%
  mutate(freq = round(cnt / sum(cnt) * 100, 2)) %>%
  arrange(desc(freq))

Expected Result is
enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

趁年轻赶紧闹 2025-01-18 09:07:34

您可以在创建 htmlwidget 之后将变量添加到 nodes data.frame(否则,sankeyNetwork() 将仅保留所需的列)。然后,您可以编辑节点标签文本的自定义代码以包含百分比...

p$x$nodes <- g %>% 
  mutate(name = sub("_[0-9]", "", source)) %>% 
  select(name, freq) %>% 
  right_join(p$x$nodes, by = "name") %>% 
  mutate(freq = ifelse(is.na(freq), "", paste0(freq, "%")))

showLabel_string <- 
  'function(el, x){
    d3.select(el).selectAll(".node text")
      .text(d => d.name + " (" + d.value + ") " + d.freq);}'

在此处输入图像描述

You can add variables to the nodes data.frame after the htmlwidget is created (otherwise, sankeyNetwork() will only keep the required columns). Then you can edit the custom code for the text of the node labels to include the percentage...

p$x$nodes <- g %>% 
  mutate(name = sub("_[0-9]", "", source)) %>% 
  select(name, freq) %>% 
  right_join(p$x$nodes, by = "name") %>% 
  mutate(freq = ifelse(is.na(freq), "", paste0(freq, "%")))

showLabel_string <- 
  'function(el, x){
    d3.select(el).selectAll(".node text")
      .text(d => d.name + " (" + d.value + ") " + d.freq);}'

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文