简体   繁体   English

如何将图例高度设置为与绘图区域的高度相同?

[英]How to set legend height to be the same as the height of the plot area?

I have arranged two plots: a line chart on top and a heatmap below. 我已经安排了两个图:顶部的折线图和下面的热图。

I want the heatmap legend to have the same height as the plot area of the heatmap, ie the same length as the y-axis. 我希望热图图例的高度与热图的绘图区域相同,即与y轴的长度相同。 I know that I can change the height and size of the legend using theme(legend.key.height = unit(...)) , but this would take many trial and errors before I find an adequate setting. 我知道我可以使用theme(legend.key.height = unit(...))更改图例的高度和大小,但在找到适当的设置之前,这将需要许多试验和错误。

Is there a way to specify the height of the legend so that it is exactly the same height of the plot area of the heatmap and would retain that ratio when plotting to a pdf? 有没有办法指定图例的高度,使其与热图的绘图区域的高度完全相同,并在绘制为pdf时保留该比率?

A reproducible example with code I have tried: 我可以尝试使用代码重现的示例:

#Create some test data
pp <- function (n, r = 4) {
  x <- seq(1:100)
  df <- expand.grid(x = x, y = 1:10)
  df$z <- df$x*df$y
  df
}
testD <- pp(20)
#Define groups
colbreaks <- seq(min(testD[ , 3]), max(testD[ , 3] + 1), length = 5)
library(Hmisc)
testD$group <- cut2(testD[ , 3], cuts = c(colbreaks))
detach(package:Hmisc, unload = TRUE)

#Create data for the top plot
testD_agg <- aggregate(.~ x, data=testD[ , c(1, 3)], FUN = sum)

#Bottom plot (heatmap)
library(ggplot2)
library(gtable)

p <- ggplot(testD, aes(x = x, y = y)) +
  geom_tile(aes(fill = group)) +
  scale_fill_manual(values = c("red", "orange", "yellow", "lightgreen")) +
  coord_cartesian(xlim = c(0, 100), ylim = c(0.5, 10.5)) +

  theme_bw() +
  theme(legend.position = "right",
        legend.key = element_blank(),
        legend.text = element_text(colour = "black", size = 12),
        legend.title = element_blank(),
        axis.text.x = element_text(size = 12, angle = 45, vjust = +0.5),
        axis.text.y = element_text(size = 12),
        axis.title = element_text(size = 14),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.margin = unit(c(0, 0, 0, 0), "line"))

#Top plot (line)
p2 <- ggplot(testD_agg, aes(x = x, y = z)) +
  geom_line() +
  xlab(NULL) +
  coord_cartesian(xlim = c(0, 100), ylim = c(0, max(testD_agg$z))) +

  theme_bw() +
  theme(legend.position = "none",
        legend.key = element_blank(),
        legend.text = element_text(colour = "black", size = 12),
        legend.title = element_text(size = 12, face = "plain"),
        axis.text.x = element_blank(),
        axis.text.y = element_text(size = 12),
        axis.title = element_text(size = 14),
        axis.ticks.x = element_blank(),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        plot.margin = unit(c(0.5, 0.5, 0, 0), "line"))

#Create gtables
gp <- ggplotGrob(p) 
gp2 <- ggplotGrob(p2)

#Add space to the right of the top plot with width equal to the legend of the bottomplot 
legend.width <- gp$widths[7:8] #obtain the width of the legend in pff2
gp2 <- gtable_add_cols(gp2, legend.width, 4) #add a colum to pff with with legend.with
#combine the plots
cg <- rbind(gp2, gp, size = "last")
#set the ratio of the plots
panels <- cg$layout$t[grep("panel", cg$layout$name)]
cg$heights[panels] <- unit(c(2,3), "null")
#remove white spacing between plots
cg <- gtable_add_rows(cg, unit(0, "npc"), pos = nrow(gp))

pdf("test.pdf", width = 8, height = 7)
print(grid.draw(cg))
dev.off()

#The following did not help solve my problem but I think I got close
old.height <- cg$grobs[[16]]$heights[2]
#It seems the height of the legend is given in "mm", change to "npc"?
gp$grobs[[8]]$grobs[[1]]$heights <- c(rep(unit(0, "npc"), 3), rep(unit(1/4, "npc"), 4), rep(unit(0, "mm"),1))
#this does allow for adjustment of the heights but not the exact control I need.

My actual data has some more categories, but the gist is the same. 我的实际数据有更多类别,但要点是相同的。 Here is an image produced with the code above and annotated with what I would like to do. 是使用上面的代码生成的图像,并注释了我想要做的事情。

Thanks in advance! 提前致谢! Maarten 马腾

It seems there are two sets of heights that need adjustment: the heights of the legend keys, and the overall height of the legend. 似乎有两组高度需要调整:图例键的高度和图例的整体高度。 Picking up from your cg grob, I extract the legend, make the adjustments to the heights, then insert the legend grob back into the layout. 从你的cg grob中提取,我提取图例,调整高度,然后将图例grob插回到布局中。

leg = gtable_filter(cg, "guide-box")

library(grid)

# Legend keys
leg[[1]][[1]][[1]][[1]]$heights = unit.c(rep(unit(0, "mm"), 3),
                                         rep(unit(1/4, "npc"), 4),
                                         unit(0, "mm"))

# Legend
leg[[1]][[1]]$heights[[3]] = sum(rep(unit(0, "mm"), 3),
                                 rep(unit(1/4, "npc"), 4),
                                 unit(0, "mm"))

# grid.draw(leg)  # Check that heights are correct

cg.new = gtable_add_grob(cg, leg, t = 17, l = 8)

grid.newpage()
grid.draw(cg.new)

在此输入图像描述

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

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