0

I'm looking to plot the digits of Pi as heirarchical edge bundles, as shown in this image

enter image description here

Here, the digits of Pi are grouped by their colour, and then each digit has an edge drawn to the digit that follows it (i.e., if Pi is 3.141, then 3 would have an edge drawn to 1, 1 would have an edge to 4, and so on through the digits).

This is the code I have so far

library(ggraph)
library(tidygraph)

dat_lagged <- structure(list(line = c(1L, 3L, 4L, 5L, 6L, 7L), digit = c("3", 
"1", "4", "1", "5", "9"), digit_lagged = c("1", "4", "1", "5", 
"9", "2"), group = c("3", "1", "4", "1", "5", "9")), row.names = c(NA, 
-6L), class = c("tbl_df", "tbl", "data.frame"))

from <- as.numeric(dat_lagged$digit)
to <- as.numeric(dat_lagged$digit_lagged)

ggraph(dat_lagged, 'dendrogram', circular = TRUE) +
  geom_conn_bundle(aes(colour = stat(group)),
                   data = get_con(from, to),
                   edge_alpha = 0.25)

However this is throwing the error

Error in if (is.numeric(v) && any(v < 0)) { : 
  missing value where TRUE/FALSE needed
Conor Neilson
  • 1,026
  • 1
  • 11
  • 27

1 Answers1

0

Hey I was able to create something similar using a linear layout. First, create a tbl_graph object from a data.frame with from, to, and the rank of the "from" number.

I use library(Rmpfr) to obtain 1000 pi digits for this.

library(Rmpfr)
digits <- Const("pi",1000)
#convert to string
pistr <- substr(capture.output(digits)[2],5,nchar(capture.output(digits)[2]))
#reformat string type object to from,to list of lists
reform <- lapply(seq(2,nchar(pistr)),function(x) {c(as.numeric(substr(pistr,x-1,x-1)),as.numeric(substr(pistr,x,x)))})
#bind list of lists to dataframe
do.call(rbind,reform) %>% data.frame -> pi1000
#remove NAs introduced by string of decimal .
pi1000 <- pi1000 %>% slice(-1)
#rename columns 
colnames(pi1000) <- c('from','to')
#reintroduce first connection, 3 -> 1
pi1000$from[1] <- 3
#remove final from,to line with missing "to" number
pi1000 <- pi1000 %>% filter(!is.na(from))
#add a rank for each from, to - we will use this to numerically "jitter" the connections later
pi1000$rank <- seq(1,length(pi1000[,1]))

#next, arrange from,to connections by 'from', so that when tbl_graph is called, nodes are ordered numerically
pi1000 <- pi1000 %>% arrange(from)

#convert from,to DF to tbl_graph
#the tbl_graph's edges are converted so that the from,to now refer to the index of the nodes (i.e. x+1)
piggraph <- pi1000 %>% as_tbl_graph

Once the tbl_graph is formatted as such it becomes easier to create the plot with simpler ggraph grammar, but the plot appears to fall apart when set to circular=T. The 'linear' layout lets you control where edges land using a single variable - would love to see an answer that uses a circular format!

piggraph %>% ggraph(layout='linear') + 
    #arc2 creates a plot that can be colored by node by referring to the nodes of the tbl_graph (node.name)
    #add a component rank/length(rank) to make the edges jitter according to when the number happens in pi's sequence
    geom_edge_arc2(aes(x=x+(rank/(length(pi1000$rank))),color=as.factor(node.name))) +
    #add a label for each node and center it with nudge_x
    geom_node_text(aes(label=name),nudge_x = 0.5)

The resulting graph