旋转ggplot树形图标签

5

我想使用dendextend包创建一棵树状图。它可以创建美观的gg树状图,但是当你把它变成“圆形”时,标签就无法跟上。下面提供一个示例。

我的距离对象在这里:http://speedy.sh/JRVBS/mydist.RDS

library(dendextend)
library(ggplot2)
#library(devtools) ; install_github('kassambara/factoextra')
library(factoextra)


clus <- hcut(mydist, k = 6, hc_func = 'hclust', 
             hc_method = 'ward.D2', graph = FALSE, isdiss = TRUE)

dend <- as.dendrogram(clus)
labels(dend) <- paste0(paste0(rep(' ', 3), collapse = ''), labels(dend))
dend <- sort(dend, decreasing = FALSE)

ggd1 <- ggplot(dend %>%
                   set('branches_k_color', k = 6) %>%
                   set('branches_lwd', 0.6) %>%
                   set('labels_colors', k = 6) %>%
                   set('labels_cex', 0.6), 
               theme = theme_minimal(),
               horiz = TRUE)
ggd1 <- ggd1 + theme(panel.grid.major = element_blank(),
                     axis.text = element_blank(),
                     axis.title = element_blank())
ggd1 <- ggd1 + ylim(max(get_branches_heights(dend)), -3)

这基本上给了我这张图片:enter image description here 这非常好。然而,我想把它变成一个圆形,所以使用:

ggd1 + coord_polar(theta = 'x') 

我得到了下面的图表,这非常接近我想要的,但我需要旋转标签。 enter image description here 任何帮助都将不胜感激。我知道dendextend在内部基本上是创建一些数据帧,然后调用geom_segment()geom_text()对它们进行重心图和标签的创建。我相信我可以通过以下方式公开相关的数据框:
back.df1 <- dendextend::as.ggdend(dend)
back.df2 <- dendextend::prepare.ggdend(back.df1)

另一个策略可能是在绘图时使用ggplot(labels = FALSE...),然后以某种方式手动添加geom_text(),以保留颜色但允许使用geom_text(angle = )。我还怀疑各种ggplot巫术的组合可以让我重新创建第一和第二个图,但也控制标签的角度。然而,我不知道如何做到这一点,已经使用dendextend软件包构建了很多内容,理想情况下希望避免使用任何新的软件包来创建树状图对象,因为我真的很喜欢这个标签之外的功能!
解决方案: 我基于Richard Telford的解决方案创建了编辑后的ggplot.ggdend()版本。这与下面答案中提供的版本相同。接下来,我创建了一个函数自动创建角度和hjust向量,以使标签旋转从6点钟到12点钟,以提高可读性。
createAngleHJustCols <- function(labeldf) {        
    nn <- length(labeldf$y)
    halfn <- floor(nn/2)
    firsthalf <- rev(90 + seq(0,360, length.out = nn))
    secondhalf <- rev(-90 + seq(0,360, length.out = nn))
    angle <- numeric(nn)
    angle[1:halfn] <- firsthalf[1:halfn]
    angle[(halfn+1):nn] <- secondhalf[(halfn+1):nn]

    hjust <- numeric(nn)
    hjust[1:halfn] <- 0
    hjust[(halfn+1):nn] <- 1

    return(list(angle = angle, hjust = hjust))
}

然后我使用以下代码生成了这个图:

gdend <- dendextend::as.ggdend(dend %>%
                                   set('branches_k_color', k = 6) %>%
                                   set('branches_lwd', 0.6) %>%
                                   set('labels_colors', k = 6) %>%
                                   set('labels_cex', 0.6))

gdend$labels$angle <- ifelse(horiz, 0, 90)
gdend$labels$hjust <- 0
gdend$labels$vjust <- 0.5

# if polar, change the angle and hjust so that the labels rotate
if(polarplot) {
    newvalues <- createAngleHJustCols(gdend$labels)
    gdend$labels$angle <- newvalues[['angle']]
    gdend$labels$hjust <- newvalues[['hjust']]
}

ggresult <- newggplot.ggdend(gdend, horiz = TRUE, offset_labels = -2) 
ggresult <- ggresult + ggtitle(plottitle)
ggresult <- ggresult + theme(plot.margin = margin(c(2,2,2,2),
                             axis.text = element_blank(),
                             plot.title = element_text(margin = margin(10,2,2,2)))
ggresult <- ggresult + ylim(max(get_branches_heights(dend)), -5)
ggresult <- ggresult + coord_polar(theta = 'x', direction = 1)

最终产生了这个最终的图表!enter image description here

(我更改了一些数据,因此在图表中可能会出现一些不同的顺序)


你的RDS文件似乎已经损坏。load("mydist.RDS") Error: bad restore file magic number (file may be corrupted) -- no data loaded。最好使用dput并将其包含在你的问题中(除非对象很大)。 - Richard Telford
很不幸,它非常庞大。感谢您的评论/答案,我将尝试一下。此外,我重新上传了'mydist.RDS'文件,我相信之前可能犯了一个错误。 - Brandon
1个回答

3
这是可能的,但你需要先编辑dendextend:::ggplot.ggdend,使其接受angle美学(以及hjustvjust)。
步骤1:编辑dendextend:::ggplot.ggdend
newggplot.ggdend <- function (data, segments = TRUE, labels = TRUE, nodes = TRUE, 
          horiz = FALSE, theme = theme_dendro(), offset_labels = 0, ...) {
  data <- prepare.ggdend(data)
  #angle <- ifelse(horiz, 0, 90)
  #hjust <- ifelse(horiz, 0, 1)
  p <- ggplot()
  if (segments) {
    p <- p + geom_segment(data = data$segments, aes_string(x = "x", y = "y", xend = "xend", yend = "yend", colour = "col", linetype = "lty", size = "lwd"), lineend = "square") + 
      guides(linetype = FALSE, col = FALSE) + scale_colour_identity() + 
      scale_size_identity() + scale_linetype_identity()
  }
  if (nodes) {
    p <- p + geom_point(data = data$nodes, aes_string(x = "x", y = "y", colour = "col", shape = "pch", size = "cex")) + 
      guides(shape = FALSE, col = FALSE, size = FALSE) + 
      scale_shape_identity()
  }
  if (labels) {
    data$labels$cex <- 5 * data$labels$cex
    data$labels$y <- data$labels$y + offset_labels
    p <- p + geom_text(data = data$labels, aes_string(x = "x", y = "y", label = "label", colour = "col", size = "cex", angle = "angle", hjust = "hjust", vjust = "vjust"))#edited
  }
  if (horiz) {
    p <- p + coord_flip() + scale_y_reverse(expand = c(0.2, 0))
  }
  if (!is.null(theme)) {
    p <- p + theme
  }
  p
}

assignInNamespace(x = "ggplot.ggdend", ns = "dendextend", value = newggplot.ggdend)

步骤2:创建数据对象。
gdend <- dendextend::as.ggdend(dend %>%
                        set('branches_k_color', k = 6) %>%
                        set('branches_lwd', 0.6) %>%
                        set('labels_colors', k = 6) %>%
                        set('labels_cex', 0.6),
                      theme = theme_minimal(),
                      horiz = TRUE)
gdend$labels$angle <- seq(90, -270, length = nrow(gdend$labels))
gdend$labels$vjust <- cos(gdend$labels$angle * pi) / (180)
gdend$labels$hjust <- sin(gdend$labels$angle * pi) / (180)

步骤三:绘图
ggd1 <- ggplot(gdend)
ggd1 <- ggd1 + theme(panel.grid.major = element_blank(),
                     axis.text = element_blank(),
                     axis.title = element_blank())
ggd1 <- ggd1 + ylim(max(get_branches_heights(dend)), -3)
ggd1
ggd1 + coord_polar(theta = 'x') 

这看起来不错,我唯一需要做的就是将标签和hjust从6点翻转到12点以提高可读性。我会发布一个例子。 - Brandon
1
嗨,Richard,你有兴趣编辑dendextend中的代码并提交PR吗?(我在这里打开了一个问题:https://github.com/talgalili/dendextend/issues/44)谢谢! - Tal Galili

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接