Return a nested list with a nested level and value

I would like to visualize some deeply nested data using networkD3 . I can’t figure out how to get the data in the right format before sending to radialNetwork .

Here are some sample data:

 level <- c(1, 2, 3, 4, 4, 3, 4, 4, 1, 2, 3) value <- letters[1:11] 

where level indicates the socket level and value is the name of the node. Using these two vectors, I need to get the data in the following format:

 my_list <- list( name = "root", children = list( list( name = value[1], ## a children = list(list( name = value[2], ## b children = list(list( name = value[3], ## c children = list( list(name = value[4]), ## d list(name = value[5]) ## e ) ), list( name = value[6], ## f children = list( list(name = value[7]), ## g list(name = value[8]) ## h ) )) )) ), list( name = value[9], ## i children = list(list( name = value[10], ## j children = list(list( name = value[11] ## k )) )) ) ) ) 

Here is the dewaxed object:

 > dput(my_list) # structure(list(name = "root", # children = list( # structure(list( # name = "a", # children = list(structure( # list(name = "b", # children = list( # structure(list( # name = "c", children = list( # structure(list(name = "d"), .Names = "name"), # structure(list(name = "e"), .Names = "name") # ) # ), .Names = c("name", # "children")), structure(list( # name = "f", children = list( # structure(list(name = "g"), .Names = "name"), # structure(list(name = "h"), .Names = "name") # ) # ), .Names = c("name", # "children")) # )), .Names = c("name", "children") # )) # ), .Names = c("name", # "children")), structure(list( # name = "i", children = list(structure( # list(name = "j", children = list(structure( # list(name = "k"), .Names = "name" # ))), .Names = c("name", # "children") # )) # ), .Names = c("name", "children")) # )), # .Names = c("name", # "children")) 

Then I can pass it to the final build function:

 library(networkD3) radialNetwork(List = my_list) 

The result will look something like this:

enter image description here


Question: How to create a nested list?

Note. As @ zx8754 pointed out, there is already a solution in this SO post , but data.frame is required for input. Due to inconsistency in my level , I don't see an easy way to turn it into data.frame .

+6
r recursion nested-lists networkd3
source share
2 answers

Using data.table merge:

 library(data.table) dt = data.table(idx=1:length(value), level, parent=value) dt = dt[dt[, .(i=idx, level=level-1, child=parent)], on=.(level, idx < i), mult='last'] dt[is.na(parent), parent:= 'root'][, c('idx','level'):= NULL] > dt # parent child # 1: root a # 2: ab # 3: bc # 4: cd # 5: ce # 6: bf # 7: fg # 8: fh # 9: root i # 10: ij # 11: jk 

Now we can use the solution from another message:

 x = maketreelist(as.data.frame(dt)) > identical(x, my_list) # [1] TRUE 
+3
source share

As a preface, your data is difficult to work because critical information is encoded in the order of values ​​in level . I don’t know how you get these values ​​in this order, but consider that there may be a better way to structure this information in the first place, which will facilitate the next task.

Here's a base -y way to convert your data into a data frame with two columns, parent and child , and then pass this to the data.tree functions, which can easily convert to the JSON format you need ... and then pass it to radialNetwork ...

 level <- c(1, 2, 3, 4, 4, 3, 4, 4, 1, 2, 3) value <- letters[1:11] library(data.tree) library(networkD3) parent_idx <- sapply(1:length(level), function(n) rev(which(level[1:n] < level[n]))[1]) df <- data.frame(parent = value[parent_idx], child = value, stringsAsFactors = F) df$parent[is.na(df$parent)] <- "" list <- ToListExplicit(FromDataFrameNetwork(df), unname = T) radialNetwork(list) 

Here's a tidyverse way to achieve the same ...

 level <- c(1, 2, 3, 4, 4, 3, 4, 4, 1, 2, 3) value <- letters[1:11] library(tidyverse) library(data.tree) library(networkD3) data.frame(level, value, stringsAsFactors = F) %>% mutate(row = row_number()) %>% mutate(level2 = level, value2 = value) %>% spread(level2, value2) %>% mutate(`0` = "") %>% arrange(row) %>% fill(-level, -value, -row) %>% gather(parent_level, parent, -level, -value, -row) %>% filter(parent_level == level - 1) %>% arrange(row) %>% select(parent, child = value) %>% data.tree::FromDataFrameNetwork() %>% data.tree::ToListExplicit(unname = TRUE) %>% radialNetwork() 

and for the bonus, the current version of dev networkD3 (v0.4.9000) has a new treeNetwork function that accepts a data frame with columns / variables nodeId and parentId , which eliminates the need for data.tree fucntions to convert to JSON, so something like this works .. .

 level <- c(1, 2, 3, 4, 4, 3, 4, 4, 1, 2, 3) value <- letters[1:11] library(tidyverse) library(networkD3) data.frame(level, value, stringsAsFactors = F) %>% mutate(row = row_number()) %>% mutate(level2 = level, value2 = value) %>% spread(level2, value2) %>% mutate(`0` = "root") %>% arrange(row) %>% fill(-level, -value, -row) %>% gather(parent_level, parent, -level, -value, -row) %>% filter(parent_level == level - 1) %>% arrange(row) %>% select(nodeId = value, parentId = parent) %>% rbind(data.frame(nodeId = "root", parentId = NA)) %>% mutate(name = nodeId) %>% treeNetwork(direction = "radial") 
+1
source share

All Articles