简体   繁体   English

旋转 ggplot 树状图的标签

[英]Rotate labels for ggplot dendrogram

I am trying to create a dendrogram using the package dendextend.我正在尝试使用包 dendexend 创建一个树状图。 It creates really nice gg dendrograms but unfortunately when you turn it into a "circle", the labels do not keep up.它创建了非常好的 gg 树状图,但不幸的是,当你把它变成一个“圆圈”时,标签跟不上。 I'll provide an example below.我将在下面提供一个示例。

My distance object is here: http://speedy.sh/JRVBS/mydist.RDS我的距离对象在这里: 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)

This basically gives me this image:这基本上给了我这个形象: 在此处输入图片说明 Which is great.这很棒。 However, I want to turn this into a circle, and so use:但是,我想把它变成一个圆圈,所以使用:

ggd1 + coord_polar(theta = 'x') 

And I get this graph below.我在下面得到了这张图。 This is close to exactly what I want, but I just need to rotate the labels.这与我想要的非常接近,但我只需要旋转标签。 在此处输入图片说明

Any help is appreciated.任何帮助表示赞赏。 I know that under the hood dendextend is basically creating a few data.frames and then calling geom_segment() and geom_text() on them to create the dendrogram and labels.我知道在引擎盖下 dendextend 基本上是创建一些 data.frames,然后在它们上调用geom_segment()geom_text()来创建树状图和标签。 I believe I can expose the associated data.frame as follows:我相信我可以公开相关的 data.frame 如下:

back.df1 <- dendextend::as.ggdend(dend)
back.df2 <- dendextend::prepare.ggdend(back.df1)

Another tactic would possibly to be to use ggplot(labels = FALSE...) when plotting, and then to add geom_text() manually in some way that preserves the coloring but allows me to use geom_text(angle = ) .另一种策略可能是在绘图时使用ggplot(labels = FALSE...) ,然后以某种方式手动添加geom_text()以保留着色但允许我使用geom_text(angle = )

I also suspect some combination of various ggplot wizardry would allow me to take back.df2 and create the 1st and second plots again, but also control the angle of the labels.我还怀疑各种 ggplot 魔法的某种组合可以让我收回back.df2并再次创建第一个和第二个图,但也可以控制标签的角度。 However, I do not know how to do any of this, and have built out a lot already using the dendextend package and would ideally like to avoid having to use any new package for creating dendrogram objects because I really like this outside of the labels!但是,我不知道如何做到这一点,并且已经使用 dendextend 包构建了很多东西,并且理想情况下希望避免使用任何新包来创建树状图对象,因为我真的很喜欢标签之外的这个!


SOLUTION解决方案

I based this off the solution from Richard Telford below.我基于下面 Richard Telford 的解决方案。 I first created an edited version of the ggplot.ggdend() .我首先创建了ggplot.ggdend()的编辑版本。 This is identical to the one provided in the answer below.这与以下答案中提供的相同。 I next created a function to automatically create the angle and hjust vectors so that the labels rotation switches from 6 o'clock to 12 o'clock to improve readability.我接下来创建了一个函数来自动创建角度和 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))
}

I then produced the plot using the following code:然后我使用以下代码生成了绘图:

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)

And that ultimately produced this final plot!这最终产生了这个最终的情节! 在此处输入图片说明

(I changed a couple things in the data so some of the order may appear different in the plot) (我更改了数据中的一些内容,因此图中的某些顺序可能会有所不同)

This is possible, but you need to edit dendextend:::ggplot.ggdend first to make it accept the angle aesthetic (and also hjust and vjust )这是可能的,但您需要首先编辑dendextend:::ggplot.ggdend以使其接受angle美学(以及hjustvjust

Step 1: edit dendextend:::ggplot.ggdend第 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)

Step 2: Make the data object第 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)

Step 3: plot第 3 步:绘图

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') 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM