【问题标题】:igraph: tree graph where terminal (not root) nodes are at same level?igraph:终端(非根)节点处于同一级别的树形图?
【发布时间】:2022-09-27 22:10:43
【问题描述】:

我想在 R 中用igraph 绘制一个树形图,所有终端节点都在同一级别,这与默认情况下所有根节点都在同一级别不同。

layout_as_tree 有办法做到这一点,基于根节点。需要指定它们 (root) 以及它们的级别 (rootlevel)。所以我可以使用这个选项,虽然它似乎会涉及一个非常复杂的工作流程 a) 将我的树拆分为子树 b) 找到每个子树的根节点 c) 找到每个子树的最大路径 4) 指定根一级相对对别人...

从终端节点开始有没有更简单的方法?假设我不知道哪些节点是根节点(1 和 11),但只知道哪些节点是终端节点(4:11 和 16:20)。

这是一个示例,但我希望终端节点 4、16 和 17 处于最低级别:

library(igraph)
tree2 <- make_tree(10, 3) + make_tree(10, 2)

plot(tree2, layout=layout_as_tree(tree2, root=c(1,11),
                                  rootlevel=c(2, 1)))

创建于 2022-09-23,reprex v2.0.2

    标签: r graph igraph network-analysis


    【解决方案1】:

    当从下到上计算级别时,解决方案变为:

    require(igraph)
    
    tree2  <- make_tree(10, 3) + make_tree(10, 2)
    tree3  <- set_edge_attr(tree2, name="weight", value=-1) # longest path = shortest negative
    dist   <- (-distances(tree3, v=(V(tree3)), mode="out")) # matrix of VxV distances of shortest paths
    layers <- apply(dist, 1, max)                           # max per row
    layers <- max(layers) - layers                          # shift down
    
    plot(tree3, layout=layout_with_sugiyama(tree3, layers=layers))
    

    如果dist 矩阵不适合内存,则必须进行dfs() 搜索,计算层数。

    【讨论】:

    • 这是一个!非常感谢您发布的所有答案
    【解决方案2】:

    计算根和根级别如下:

    require(igraph) 
    tree2 <- make_tree(10, 3) + make_tree(10, 2)
    
    roots <- V(tree2)[which(degree(tree2, mode="in") == 0)]   # no incoming edges
    dist      <- distances(tree2, roots)                      # all distances from roots
    dist[which(is.infinite(dist))] <- NA                      # remove infinite
    rootlevel  <- apply(dist, 1, max, na.rm = TRUE)           # max per row
    rootlevel  <- max(rootlevel) - rootlevel + 1              # offset
    plot(tree2, layout=layout_as_tree(tree2, root=roots, rootlevel=rootlevel))
    

    如果dist 矩阵不适合内存,则必须进行dfs() 搜索,计算层数。

    【讨论】:

    • 谢谢clp!我的错,我意识到我给出的情节示例很糟糕:4、16 和 17 应该处于最低级别,因为它们是终端节点(已编辑)。实际上,您最初分享的layout_with_sugiyama 的答案似乎正在解决这个问题?
    【解决方案3】:

    这是一种更基本的方法。 在这个解决方案中,我们通过depth-first search 搜索图并递归计算每个顶点的层。

    require(igraph)
    tree2  <- make_tree(10, 3) + make_tree(10, 2)
    
    ## Depth-first search.
    ## Mark node as visited.
    ## Calculate layers indexed by vertex.
    ## Layer of v is
    ##   - equal to zero if there are no descendants and
    ##   - otherwise the largest layer among the descendants plus 1.
    layers <- rep(0L, vcount(tree2))
    visit <- function(g, v){
      if (length(visited)>0L && !visited[v]) {
        visited[v] <<- 1L
    
        max_layer_descendents <- -1L 
        outgoing <- V(g)[.outnei(v)]
        for (w in outgoing) {
          stopifnot(v != w)
          visit(g, w)
          max_layer_descendents <- max(max_layer_descendents, layers[w])
        }
    
        layers[v] <<- max_layer_descendents + 1L
      }
    }
    
    ## mark vertices as non-visited and calculate layers
    visited <- rep(0L, vcount(tree2))
    for (v in V(tree2)) visit(tree2, v)
    layers
    # [1] 2 1 1 0 0 0 0 0 0 0 3 2 1 1 1 0 0 0 0 0
    
    plot(tree2, layout=layout_with_sugiyama(tree2, layers=max(layers)-layers))
    

    【讨论】:

      【解决方案4】:

      另一种解决方案,但以反转所有边缘为代价:

      require(igraph)
      tree2  <- make_tree(10, 3) + make_tree(10, 2)
      
      ## Calculate x,y coordinates by Sugiyama,
      ## flip y coordinate, and plot.
      lyt     <- layout_with_sugiyama(reverse_edges(tree2))$layout
      lyt[,2] <- (1L + max(lyt[,2])) - lyt[,2]
      lyt[,2]
      plot(tree2, layout=lyt)
      

      这使

      [1] 3 2 2 1 1 1 1 1 1 1 4 3 2 2 2 1 1 1 1 1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-30
        • 1970-01-01
        • 2018-06-22
        • 2011-10-30
        • 2012-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多