How can I plot a tree (and squirrels) in R?

后端 未结 5 1019
悲&欢浪女
悲&欢浪女 2020-12-24 06:32

Here is my tree:

tree = data.frame(branchID = c(1,11,12,111,112,1121,1122), length = c(32, 21, 19, 5, 12, 6, 2))

> tree
  branchID length
1        1              


        
5条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2020-12-24 07:04

    A version that supports trees with more than two branches. A bit work is required to convert to a data.tree structure, and to add the squirrels to it. But once you're there, the plotting is straight forward.

    df <- data.frame(branchID = c(1,11,12,13, 14, 111,112,1121,1122), length = c(32, 21, 12, 8, 19, 5, 12, 6, 2))
    squirrels <- data.frame(branchID = c(1,11,1121,11,111), PositionOnBranch = c(23, 12, 4, 2, 1), squirrel=c("FluffyTail", "Ginger", "NutCracker", "SuperSquirrel", "ChipnDale"), stringsAsFactors = FALSE)
    
    library(magrittr)
    
    #derive pathString from branchID, so we can convert it to data.tree structure
    df$branchID %>%
      as.character %>%
      sapply(function(x) strsplit(x, split = "")) %>%
      sapply(function(x) paste(x, collapse = "/")) ->
      df$pathString
    
    df$type <- "branch"
    
    library(data.tree)
    
    tree <- FromDataFrameTable(df)
    
    #climb, little squirrels!
    for (i in 1:nrow(squirrels)) {
      squirrels[i, 'branchID'] %>%
        as.character %>%
        strsplit(split = "") %>%
        extract2(1) %>%
        extract(-1) -> path
      if (length(path) > 0) branch <- tree$Climb(path)
      else branch <- tree
      #actually, we add the squirrels as branches to our tree
      #What a symbiotic coexistence!
      #advantage: Our SetCoordinates can be re-used as is
      #disadvantage: may be confusing, and it requires us
      #to do some filtering later
      branch$AddChild(squirrels[i, 'squirrel'],
                     length = squirrels[i, 'PositionOnBranch'],
                     type = "squirrel")
    }
    
    
    
    SetCoordinates <- function(node, branch) {
      if (branch$isRoot) {
        node$x0 <- 0
        node$y0 <- 0
      } else {
        node$x0 <- branch$parent$x1
        node$y0 <- branch$parent$y1
      }
    
      #let's hope our squirrels didn't flunk in trigonometry ;-)
      angle <- branch$position / (sum(Get(branch$siblings, "type") == "branch") + 2)
      x <- - node$length * cospi(angle)
      y <- sqrt(node$length^2 - x^2)
      node$x1 <- node$x0 + x
      node$y1 <- node$y0 + y
    }
    
    #let it grow!
    tree$Do(function(node) {
              SetCoordinates(node, node)
              node$lwd <- 10 * (node$root$height - node$level + 1) / node$root$height
            }, filterFun = function(node) node$type == "branch")
    tree$Do(function(node) SetCoordinates(node, node$parent), filterFun = function(node) node$type == "squirrel")
    

    Looking at the data:

    print(tree, "type", "length", "x0", "y0", "x1", "y1")
    

    This prints like so:

                        levelName     type length        x0       y0         x1       y1
    1  1                            branch     32   0.00000  0.00000   0.000000 32.00000
    2   ¦--1                        branch     21   0.00000 32.00000 -16.989357 44.34349
    3   ¦   ¦--1                    branch      5 -16.98936 44.34349 -19.489357 48.67362
    4   ¦   ¦   °--ChipnDale      squirrel      1 -16.98936 44.34349 -17.489357 45.20952
    5   ¦   ¦--2                    branch     12 -16.98936 44.34349 -10.989357 54.73580
    6   ¦   ¦   ¦--1                branch      6 -10.98936 54.73580 -13.989357 59.93195
    7   ¦   ¦   ¦   °--NutCracker squirrel      4 -10.98936 54.73580 -12.989357 58.19990
    8   ¦   ¦   °--2                branch      2 -10.98936 54.73580  -9.989357 56.46785
    9   ¦   ¦--Ginger             squirrel     12   0.00000 32.00000  -9.708204 39.05342
    10  ¦   °--SuperSquirrel      squirrel      2   0.00000 32.00000  -1.618034 33.17557
    11  ¦--2                        branch     12   0.00000 32.00000  -3.708204 43.41268
    12  ¦--3                        branch      8   0.00000 32.00000   2.472136 39.60845
    13  ¦--4                        branch     19   0.00000 32.00000  15.371323 43.16792
    14  °--FluffyTail             squirrel     23   0.00000  0.00000   0.000000 23.00000
    

    Once we're here, plotting is also easy:

    plot(c(min(tree$Get("x0")), max(tree$Get("x1"))),
         c(min(tree$Get("y0")), max(tree$Get("y1"))),
         type='n', asp=1, axes=FALSE, xlab='', ylab='')
    
    tree$Do(function(node) segments(node$x0, node$y0, node$x1, node$y1, lwd = node$lwd),
            filterFun = function(node) node$type == "branch")
    
    tree$Do(function(node) {
              points(node$x1, node$y1, lwd = 8, col = "saddlebrown")
              text(node$x1, node$y1, labels = node$name, pos = 2, cex = 0.7)
            },
            filterFun = function(node) node$type == "squirrel")
    

提交回复
热议问题