Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customize sankey diagram design in networkd3

I found this diagram that I like from a research paper: https://www.researchgate.net/figure/Sankey-diagram-visualization-of-the-flow-of-data-from-coding-through-to-interpretation_fig1_338907991

enter image description here

I tried to make some data corresponding to this diagram to recreate:

library(dplyr)
library(tidyr)
library(networkD3)

links <- data.frame(
    source = c(
        "MOOC run 6", "MOOC run 6", "MOOC run 6", "MOOC run 6", "MOOC run 6", 
        "MOOC run 6", "MOOC run 6", "MOOC run 6", "MOOC run 6", "MOOC run 6",
        
        "MOOC run 4", "MOOC run 4", "MOOC run 4", "MOOC run 4", "MOOC run 4", 
        "MOOC run 4", "MOOC run 4", "MOOC run 4",
        
        "MOOC run 7", "MOOC run 7", "MOOC run 7", "MOOC run 7", "MOOC run 7", "MOOC run 7",
        
        "MOOC run 5", "MOOC run 5", "MOOC run 5", "MOOC run 5", "MOOC run 5",
        
        "Questionnaire Q10", "Questionnaire Q10", "Questionnaire Q10", "Questionnaire Q10",
        
        "Questionnaire Q7", "Questionnaire Q7", "Questionnaire Q7",
        
        "Questionnaire Q12", "Questionnaire Q12",
        
        "Diet cannot be generalized", "Prescriptive advice", "Teaching why not just how", 
        "Averse to unconventional practices", "Misinformation and conflicting advice", 
        "Vague recommendations", "Dairy", "Oily fish", "Soy", "Omega-3 fat",
        
        "Cost of specialty products", "Disease prevention", "Plant based", "Gluten", 
        "Depression and anxiety", "Red meat", "Low carbohydrate", "Bread, pasta and potato",
        
        "Fiber", "Trial and error", "Small and progressive changes", "Weight loss",
        "Probiotics", "Structured food lists",
        
        "Poor palatability and enjoyment", "Exercise", "Convenience", "Eating out", "Fatigue and hunger",
        
        "Food availability", "Recipe adaption and food substitutions", "Diabetes", "Organic",
        
        "Supplements", "Observable benefits", "Cholesterol",
        
        "Inflammatory bowel disease", "Free range",
        
        "Health professionals don't provide personalized care", "Pro-inflammatory foods",
        "Nutrition knowledge and education", "Individualized nutrition", "Anti-inflammatory foods",
        "Anti-inflammatory nutrients", "A disease cure", "Diet", "Food access",
        "General health and wellbeing", "Lifestyle influences", 
        "Information overload in the digital age", "Supplements and nutraceuticals",
        "Motivation for long-term dietary change", "Feelings of deprivation",
        "Pro-inflammatory nutrients", "Environmental and animal practices",
        "The role of culture and social norms", "Objective and subjective evidence"
    ),
    
    target = c(
        "Diet cannot be generalized", "Prescriptive advice", "Teaching why not just how", 
        "Averse to unconventional practices", "Misinformation and conflicting advice", 
        "Vague recommendations", "Dairy", "Oily fish", "Soy", "Omega-3 fat",
        
        "Cost of specialty products", "Disease prevention", "Plant based", "Gluten", 
        "Depression and anxiety", "Red meat", "Low carbohydrate", "Bread, pasta and potato",
        
        "Fiber", "Trial and error", "Small and progressive changes", "Weight loss",
        "Probiotics", "Structured food lists",
        
        "Poor palatability and enjoyment", "Exercise", "Convenience", "Eating out", "Fatigue and hunger",
        
        "Food availability", "Recipe adaption and food substitutions", "Diabetes", "Organic",
        
        "Supplements", "Observable benefits", "Cholesterol",
        
        "Inflammatory bowel disease", "Free range",
        
        "Health professionals don't provide personalized care", "Health professionals don't provide personalized care",
        "Nutrition knowledge and education", "Health professionals don't provide personalized care",
        "Information overload in the digital age", "Information overload in the digital age",
        "Pro-inflammatory foods", "Anti-inflammatory foods", "Anti-inflammatory foods", "Anti-inflammatory nutrients",
        
        "Food access", "A disease cure", "Anti-inflammatory foods", "Pro-inflammatory foods",
        "A disease cure", "Pro-inflammatory foods", "Anti-inflammatory diet", "Pro-inflammatory foods",
        
        "Anti-inflammatory nutrients", "Individualized nutrition", "Motivation for long-term dietary change",
        "Motivation for long-term dietary change", "Anti-inflammatory nutrients", "Individualized nutrition",
        
        "Feelings of deprivation", "Lifestyle influences", "Food access", "Lifestyle influences",
        "Feelings of deprivation",
        
        "Food access", "Individualized nutrition", "Diet", "Environmental and animal practices",
        
        "Anti-inflammatory nutrients", "Objective and subjective evidence", "Diet",
        
        "A disease cure", "Environmental and animal practices",
        
        "What I need from health professionals", "A range of nutritional factors influence inflammation",
        "Why is so hard to follow an anti-inflammatory diet", "I need guidance but who do I trust", 
        "A range of nutritional factors influence inflammation", "Anti-inflammatory eating transformed my health",
        "Anti-inflammatory eating transformed my health", "Managing inflammation is more than just diet",
        "Why is so hard to follow an anti-inflammatory diet", "I need guidance but who do I trust",
        "Managing inflammation is more than just diet", "Why is so hard to follow an anti-inflammatory diet",
        "A range of nutritional factors influence inflammation", "Why is so hard to follow an anti-inflammatory diet",
        "Managing inflammation is more than just diet", "A range of nutritional factors influence inflammation",
        "Managing inflammation is more than just diet", "Why is so hard to follow an anti-inflammatory diet",
        "I need guidance but who do I trust"
    ),
    
    value = c(
        5, 4, 4, 4, 3, 3, 3, 3, 3, 3,
        4, 4, 3, 3, 3, 3, 3, 3,
        3, 3, 3, 3, 3, 3,
        3, 3, 3, 3, 3,
        3, 3, 3, 3,
        3, 3, 3,
        3, 3,
        
        4, 3, 4, 3, 4, 3, 5, 4, 3, 4,
        4, 5, 4, 3, 4, 5, 4, 3,
        5, 3, 4, 3, 4, 3,
        4, 3, 4, 3, 4,
        3, 4, 3, 4,
        3, 4, 3,
        4, 3,
        
        7, 8, 5, 5, 7, 7, 6, 5, 5, 5, 
        5, 5, 6, 5, 5, 6, 4, 4, 4
    ),
    
    group = c(
        rep("Data to Code", 38),
        rep("Code to Category", 38),
        rep("Category to Theme", 19)
    )
)

all(c(length(links$source), length(links$target), length(links$value), length(links$group)) == nrow(links))

I then continued to make the diagram:

nodes <- data.frame(
    name = unique(c(as.character(links$source), as.character(links$target)))
)

links$IDsource <- match(links$source, nodes$name) - 1
links$IDtarget <- match(links$target, nodes$name) - 1

print(paste("Number of links:", nrow(links)))
print(paste("Number of nodes:", nrow(nodes)))

sankeyNetwork(Links = links, Nodes = nodes,
              Source = "IDsource", Target = "IDtarget",
              Value = "value", NodeID = "name",
              sinksRight = TRUE, nodeWidth = 30, fontSize = 12,
              nodePadding = 10)

However, I can not seem to recreate the same style (e.g. text placement, color palettes, line thickness, etc.) as the above diagram:

enter image description here

Are there any ways to do this in R?

like image 220
stats_noob Avatar asked Dec 06 '25 15:12

stats_noob


1 Answers

links$type <- sub(' .*', '', nodes[links$IDsource + 1, 'name'])

sankeyNetwork(Links = links, Nodes = nodes,
              Source = "IDsource", Target = "IDtarget",
              Value = "value", NodeID = "name",
              LinkGroup = 'type', NodeGroup = NULL,
              sinksRight = TRUE, nodeWidth = 8, fontSize = 11,
              nodePadding = 8, iterations = 0) -> sN




# https://stackoverflow.com/a/66856227
htmlwidgets::onRender(sN, '
  function(el) { 
    var cols_x = this.sankey.nodes().map(d => d.x).filter((v, i, a) => a.indexOf(v) === i).sort(function(a, b){return a - b});
    var labels = ["Data Source", "Example codes", "Categories", "Themes"];
    cols_x.forEach((d, i) => {
      d3.select(el).select("svg")
        .append("text")
        .attr("x", d)
        .attr("y", 12)
        .text(labels[i]);
    })
  }
') 

like image 123
M-- Avatar answered Dec 08 '25 04:12

M--



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!