16

我有一个ggplot,我将因子映射到填充和alpha,如下所示:

set.seed(47)
the_data <- data.frame(value = rpois(6, lambda=20),
                       cat1 = rep(c("A", "B"), each = 3),
                       cat2 = rep(c("X", "Y", "Z"), 2))

ggplot(the_data, aes(y = value, x = cat2, alpha = cat1, fill = cat2)) +
    geom_bar(stat = "identity", position = "dodge") +
    scale_alpha_discrete(range = c(0.5, 1)) +
    theme_bw()

在此处输入图像描述

我为其制作它的人并没有很清楚地发现 alpha 的传说。我认为一个很好的选择是这样的(我在基本图形中一起破解):

在此处输入图像描述

我知道我无法使用高级 ggplot 命令生成这样的图例,但我可以将它grid放入我的情节之上吗?

4

2 回答 2

16

这是一个可能的起点。我创建了两个具有适当图例的不同图 - 一个“明亮”和一个“苍白”。从绘图对象中提取图例。然后使用grid viewports,一个用于情节,一个用于每个图例,将各个部分放在一起。

library(grid)
library(gtable)

# create plot with legend with alpha = 1
g1 <- ggplot(the_data, aes(y = value, x = cat2, alpha = cat1, fill = cat2)) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_alpha_discrete(range = c(0.5, 1)) +
  theme_bw() +
  guides(fill = guide_legend(title = "A",
                             title.hjust = 0.4),
         alpha = FALSE) +
  theme_bw() +
  theme(legend.text = element_blank())

g1

# grab legend
legend_g1 <- gtable_filter(ggplot_gtable(ggplot_build(g1)), "guide-box") 


# create plot with 'pale' legend
g2 <- ggplot(the_data, aes(y = value, x = cat2, alpha = cat1, fill = cat2)) +
  geom_bar(stat = "identity", position = "dodge") +
  scale_alpha_discrete(range = c(0.5, 1)) +
  guides(fill = guide_legend(override.aes = list(alpha = 0.5),
                             title = "B",
                             title.hjust = 0.3),
         alpha = FALSE) +
  theme_bw()
g2

# grab legend
legend_g2 <- gtable_filter(ggplot_gtable(ggplot_build(g2)), "guide-box") 



# arrange plot and legends

# legends to the right

# define plotting regions (viewports)
vp_plot <- viewport(x = 0.4, y = 0.5,
                    width = 0.8, height = 1)

vp_legend_g1 <- viewport(x = 0.85, y = 0.5,
                           width = 0.4, height = 0.4)

vp_legend_g2 <- viewport(x = 0.90, y = 0.5,
                           width = 0.4, height = 0.4)


# clear current device
grid.newpage()

# add objects to the viewports
# plot without legend
print(g1 + theme(legend.position = "none"), vp = vp_plot)
upViewport(0)

pushViewport(vp_legend_g1)
grid.draw(legend_g1)
upViewport(0)

pushViewport(vp_legend_g2)
grid.draw(legend_g2) 

在此处输入图像描述

# legends on top
vp_plot <- viewport(x = 0.5, y = 0.4,
                    width = 1, height = 0.85)

vp_legend_g1 <- viewport(x = 0.5, y = 0.9,
                         width = 0.4, height = 0.4)

vp_legend_g2 <- viewport(x = 0.55, y = 0.9,
                         width = 0.4, height = 0.4)

grid.newpage()

print(g1 + theme(legend.position = "none"), vp = vp_plot)
upViewport(0)

pushViewport(vp_legend_g1)
grid.draw(legend_g1)
upViewport(0)

pushViewport(vp_legend_g2)
grid.draw(legend_g2)  

在此处输入图像描述

于 2013-11-21T21:59:08.060 回答
4

@Henrik

这可能会容易一些,

g1 <- ggplotGrob(p1)
g2 <- ggplotGrob(p2)

leg1 <- gtable_filter(g1, "guide-box") 
leg2 <- gtable_filter(g2, "guide-box") 
leg <- gtable:::cbind_gtable(leg1[["grobs"]][[1]],  leg2[["grobs"]][[1]], "first")

g1$grobs[g1$layout$name == "guide-box"][[1]] <- leg
g1$widths[max(subset(g1$layout, name == "guide-box")[["r"]])] <- list(leg1$width + leg2$width)

grid.newpage()
grid.draw(g1)
于 2013-11-22T12:38:51.010 回答