2015-06-21 46 views
3

我想在R中创建一个ggplot数字,其中有六个面板。前五个方面应该用条形图表示五个不同的数据子集,最后一个方面应代表整个数据。我还希望在前五个方面有一个固定的Y轴比例尺,但最后一个方面的比例是不同的。我知道目前不可能为ggplot功能(https://github.com/hadley/ggplot2/issues/187)中的每个方面指定单独的ylims,但是我想知道是否可以使用grid和可能的gtable程序包做类似的事情,这两者我都非常熟悉此时此刻。ggplot使用不同规格的ylims

以下是我的尝试。我用另一个图中的一个方面替换最后一个方面。

library("ggplot2") 
library("dplyr") 
library("grid") 

# create data 
set.seed(1) 
d1 <- data_frame(
    value = rnorm(3 * 5, mean = 30, sd = 10), 
    f = rep(LETTERS[1:3], 5), 
    p = rep(paste("Panel", 1:5), each = 3) 
) 
d2 <- d1 %>% 
    mutate(p = "Total") %>% 
    rbind(d1) 

# make initial figures 
plot1 <- ggplot(d2, aes(f, value)) + 
    geom_bar(stat = "identity") + 
    facet_wrap(~ p) + 
    coord_cartesian(ylim = c(0, 50)) 
plot2 <- ggplot(d2, aes(f, value)) + 
    geom_bar(stat = "identity") + 
    facet_wrap(~ p, scales = "free_y") 

# extract their grobs 
g1 <- ggplotGrob(plot1) 
g2 <- ggplotGrob(plot2) 

# replace the final facet of plot1 with the final facet of plot2 
g1[["grobs"]][[7]] <- g2[["grobs"]][[7]] 
g1[["grobs"]][[19]] <- g2[["grobs"]][[19]] 
g1[["grobs"]][[25]] <- g2[["grobs"]][[25]] 

# draw the figure 
grid.newpage() 
grid.draw(g1) 

这就是我得到的。 enter image description here

然而,可以看出,最终刻面的y轴标签与前面刻面重叠。有没有人知道避免重叠的方法,例如,通过使最后的方面变小?

回答

1

一种方法是从“g2”中提取“总计”图,然后将其插入“g1”,但首先从“g1”中删除“总计”图。但是您会注意到x轴刻度标记标签不在所有面之间对齐。

# Load packages 
library(ggplot2) 
library(dplyr) 
library(gtable) 
library(grid) 

# create data 
set.seed(1) 
d1 <- data.frame(
    value = rnorm(3 * 5, mean = 30, sd = 10), 
    f = rep(LETTERS[1:3], 5), 
    p = rep(paste("Panel", 1:5), each = 3) 
) 
d2 <- d1 %>% 
    mutate(p = "Total") %>% 
    rbind(d1) 

# make initial figures 
plot1 <- ggplot(d2, aes(f, value)) + 
    geom_bar(stat = "identity") + 
    facet_wrap(~ p) + 
    coord_cartesian(ylim = c(0, 50)) 
plot2 <- ggplot(d2, aes(f, value)) + 
    geom_bar(stat = "identity") + 
    facet_wrap(~ p, scales = "free_y") 

# Get the ggplot grobs 
g1 <- ggplotGrob(plot1) 
g2 <- ggplotGrob(plot2) 

# Extract "Total" plot from g2 
keep = g2$layout$name %in% c("panel-3-2", "axis-b-3-2", "axis-l-2-3", "strip-t-3-2") 
pos = subset(g2$layout, keep, c(t,l,b,r)) 
g2 = g2[c(min(pos$t):max(pos$b)), c(min(pos$l):max(pos$r))] 

# Remove "Total" plot from g1 
keep = !g1$layout$name %in% c("panel-3-2", "axis-b-3-2", "strip-t-3-2") 
pos = subset(g1$layout, !keep, c(t,l,b,r)) 
g1$grobs <- g1$grobs[keep] 
g1$layout <- g1$layout[keep, ] 

# Insert g2 into g1 
g1 = gtable_add_grob(g1, g2, t=min(pos$t), b=max(pos$b), l=min(pos$l), r=max(pos$r)) 

# Draw it 
grid.newpage() 
grid.draw(g1) 

enter image description here

另一种方法是从“G2”如前提取“总计”的情节,但是其y轴移动到图(使用来自here借用代码的右侧。 (我调整了你的“plot2”,以便刻度标记标签在最终的绘图中更好地对齐)。通过这种方式,“Total”面板占用了与其他面板一样多的空间,因此x轴刻度标记对齐,但“Total”面板的y轴向右伸出。

# Make initial figures 
plot1 <- ggplot(d2, aes(f, value)) + 
    geom_bar(stat = "identity") + 
    facet_wrap(~ p) + 
    coord_cartesian(ylim = c(0, 50)) 
plot2 <- ggplot(d2, aes(f, value)) + 
    geom_bar(stat = "identity") + 
    facet_wrap(~ p, scales = "free_y") + 
    theme(axis.text.y = element_text(hjust = 0)) ## For better formatting of labels 

# extract their grobs 
g1 <- ggplotGrob(plot1) 
g2 <- ggplotGrob(plot2) 

# Extract "Total" plot from g2 
keep = g2$layout$name %in% c("panel-3-2", "axis-b-3-2", "axis-l-2-3", "strip-t-3-2") 
pos = subset(g2$layout, keep, c(t,l,b,r)) 
g2 = g2[c(min(pos$t):max(pos$b)), c(min(pos$l):max(pos$r))] 


# Get the position of the panel in the layout 
panel <- c(subset(g2$layout, grepl("panel", g2$layout$name), se = t:r)) 

# Get the row number of the y-axis in the layout 
rn <- which(grepl("axis-l", g2$layout$name)) 

# Extract the axis (tick marks and axis text from the gtable) 
axis.grob <- g2$grobs[[rn]] 
axisl <- axis.grob$children[[2]] # Two children - get the second 
axisl # Note: two grobs - tick marks and text 

# Reverse the grobs and the widths 
axisl$widths <- rev(axisl$widths) 
axisl$grobs <- rev(axisl$grobs) 

axisl$grobs[[1]]$x <- axisl$grobs[[1]]$x - unit(1, "npc") + unit(2.75, "pt") 

axisl$grobs[[2]]$children[[1]]$x = unit(.15, "npc")  

# Remove the column containing the left axis 
g2 <- g2[, -(panel$r-1)] 

## remove empty panels 
keep = !g1$layout$name %in% c("panel-3-2", "axis-b-3-2", "strip-t-3-2") 
pos = subset(g1$layout, !keep, c(t,l,b,r)) 
g1$grobs <- g1$grobs[keep] 
g1$layout <- g1$layout[keep, ] 

# Insert g2 into g1 
g1 = gtable_add_grob(g1, g2, t = min(pos$t), b = max(pos$b), l = min(pos$l), r = max(pos$r)) 

# Add a new column to g1, and add the revised axisl grob to the new column. 
pos = subset(g1$layout, grepl("panel", g1$layout$name), c(t,l,b,r)) # position of bottom right panel 
g1 <- gtable_add_cols(g1, axisl$widths, max(pos$r)) 
g1 <- gtable_add_grob(g1, axisl, t = max(pos$b), l = max(pos$r)+1, r = max(pos$r)+2) 

# Draw it 
grid.newpage() 
grid.draw(g1) 

enter image description here

+1

谢谢你的完美回答,进一步改进! –