How to make a circular Sankey chart in R?

139 Views Asked by At

I am currently working on a project where I need to create a circular Sankey chart in R, similar in appearance to the transformative maps used by the World Economic Forum. Is there a solution available for this?

A small example of the type of data I am using would look like this:

Point_from (Inner circle) Point_to (Outer Circle) Value Info
A D 1 BLUE
A E 1 BLUE
B E 3 GREEN
B F 1 BLUE
C G 1 BLUE

In this example, we have points connected by values (strength of the connection), and each connection has a one extra indicator associated with it (information on the link - to be explored in an interactive manner).

If anyone has any insights, R code examples, or recommendations for packages in R that would be suitable for creating a circular Sankey chart like this, I would greatly appreciate your help.

Thank you in advance :)

I was not able to find any solution with suitable outputs, neither material online/tutorials explaining how it can be done. I wasn't able to make the sankey chart scrip from networkD3 circular. Another option would be to do a network analysis, maybe? But I wasn't able to position the points in a circular manner (the base of the network graph was done using this example https://ladal.edu.au/net.html ).

1

There are 1 best solutions below

0
Allan Cameron On

It seems that you are looking for a circular graph. You could use the tidygraph and ggraph ecosystem to generate something like this:

library(tidygraph)
library(ggraph)
library(ggforce)

data.frame(from = 'z', to = unique(df$from), Value = 0, Info = NA) |>
  rbind(df) |>
  as_tbl_graph() |>
  ggraph(layout = 'tree', circular = TRUE) +
  geom_circle(aes(x0 = 0, y0 = 0, r = 1), size = 0.1, color = 'gray') +
  geom_circle(aes(x0 = 0, y0 = 0, r = 0.5), size = 0.1, color = 'gray') +
  geom_edge_elbow(aes(width = Value, color = Info), alpha = 0.5) +
  geom_node_point(aes(size = ifelse(name == 'z', NA, 10)),
                  shape = 21, fill = 'white') +
  geom_node_text(aes(label = ifelse(name == 'z', '', name))) +
  theme_graph() +
  theme(legend.position = 'none') +
  scale_edge_color_manual(values = c(BLUE = 'blue3', GREEN = 'green4'),
                          na.value = 'transparent') +
  scale_size_identity()

enter image description here

Data from question in reproducible format

df <- structure(list(from = c("A", "A", "B", "B", "C"), to = c("D", 
"E", "E", "F", "G"), Value = c(1L, 1L, 3L, 1L, 1L), Info = c("BLUE", 
"BLUE", "GREEN", "BLUE", "BLUE")), class = "data.frame", row.names = c(NA, 
-5L))