Return nested list with nested level and value

后端 未结 2 775
灰色年华
灰色年华 2021-01-05 07:10

I would like to visualize some deeply nested data using networkD3. I can\'t figure out how to get the data into the right format before sending to rad

相关标签:
2条回答
  • Using a data.table-style 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:      a     b
    #  3:      b     c
    #  4:      c     d
    #  5:      c     e
    #  6:      b     f
    #  7:      f     g
    #  8:      f     h
    #  9:   root     i
    # 10:      i     j
    # 11:      j     k
    

    Now we can use the solution from the other post:

    x = maketreelist(as.data.frame(dt))
    
    > identical(x, my_list)
    # [1] TRUE
    
    0 讨论(0)
  • 2021-01-05 07:58

    As a preface, your data is difficult to work with because critical information is encoded in the order of the values in level. I don't know how you get those values in that order, but consider that there may be a better way to structure that information in the first place, which would make the next task easier.

    Here's a base-y way of converting your data into a data frame with 2 columns, parent and child, then passing that into data.tree functions that can easily convert to the JSON format you need... and then pass it on 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 of achieving 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 a bonus, the current dev version of networkD3 (v0.4.9000) has a new treeNetwork function that takes a data frame with nodeId and parentId columns/variables, which eliminates the need for the 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")
    
    0 讨论(0)
提交回复
热议问题