# Multiple plot function ggplot objects can be passed in ..., or to plotlist
# (as a list of ggplot objects) - cols: Number of columns in layout -
# layout: A matrix specifying the layout. If present, 'cols' is ignored.  If
# the layout is something like matrix(c(1,2,3,3), nrow=2, byrow=TRUE), then
# plot 1 will go in the upper left, 2 will go in the upper right, and 3 will
# go all the way across the bottom.
multiplot <- function(..., plotlist = NULL, file, cols = 1, layout = NULL) {
    library(grid)
    
    # Make a list from the ... arguments and plotlist
    plots <- c(list(...), plotlist)
    
    numPlots = length(plots)
    
    # If layout is NULL, then use 'cols' to determine layout
    if (is.null(layout)) {
        # Make the panel ncol: Number of columns of plots nrow: Number of rows
        # needed, calculated from # of cols
        layout <- matrix(seq(1, cols * ceiling(numPlots/cols)), ncol = cols, 
            nrow = ceiling(numPlots/cols))
    }
    
    if (numPlots == 1) {
        print(plots[[1]])
        
    } else {
        # Set up the page
        grid.newpage()
        pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
        
        # Make each plot, in the correct location
        for (i in 1:numPlots) {
            # Get the i,j matrix positions of the regions that contain this subplot
            matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
            
            print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row, layout.pos.col = matchidx$col))
        }
    }
}
# multiplot(p1, p2, p3, p4, cols=2) gridExtra
# install.packages('gcookbook')
library(ggplot2)
library(gcookbook)
library(plyr)

7.1 添加文本注解

应用annotate(): annotate(geom, x = NULL, y = NULL, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL, xend = NULL, yend = NULL, …, na.rm = FALSE)

p <- ggplot(faithful, aes(x = eruptions, y = waiting)) + geom_point()
p1 <- p + annotate("text", x = 3, y = 48, label = "Group 1")
p2 <- p1 + annotate("text", x = 4.5, y = 66, label = "Group 2", colour = "red")
multiplot(p1, p2, cols = 2)

p + annotate("rect", xmin = 3, xmax = 5.2, ymin = 60, ymax = 100, alpha = 0.2) + 
    annotate("rect", xmin = 1.5, xmax = 3, ymin = 40, ymax = 75, alpha = 0.2)

p + annotate("segment", x = 2.5, xend = 4, y = 45, yend = 75, colour = "blue", 
    size = 3, arrow = arrow(ends = "both"))

p + annotate("pointrange", x = 3, y = 80, ymin = 60, ymax = 100, colour = "red", 
    size = 1.5)

7.2 在注解中使用数学表达式

使用annotate(geom = ‘text’,parse = TRUE)

p <- ggplot(data.frame(x = c(-3, 3)), aes(x = x)) + stat_function(fun = dnorm)
p1 <- p + annotate("text", x = 2, y = 0.3, parse = TRUE, label = "frac(1, sqrt(2 * pi)) * e ^ { -x ^ 2 / 2}")
p2 <- p + annotate("text", x = 0, y = 0.05, parse = TRUE, label = "'Function: ' * y==frac(1, sqrt(2 * pi)) * e ^ { -x ^ 2 / 2}")
multiplot(p1, p2, cols = 2)

7.3 添加直线

p <- ggplot(heightweight, aes(x = ageYear, y = heightIn, colour = sex)) + geom_point()
p + geom_hline(yintercept = 60, colour = "red") + geom_vline(xintercept = 14, 
    colour = "blue") + geom_abline(intercept = 37.4, slope = 1.75, colour = "black")

pg <- ggplot(PlantGrowth, aes(x = group, y = weight)) + geom_point()

给分类散点图添加直线:

pg + geom_vline(xintercept = 2)

pg + geom_vline(xintercept = which(levels(PlantGrowth$group) == "ctrl"))

7.4 添加线段和箭头

library(grid)  # for function arrow()
subclimate <- subset(climate, Source == "Berkeley")
p <- ggplot(subclimate, aes(x = Year, y = Anomaly10y)) + geom_line()
p + annotate("segment", x = 1950, xend = 1980, y = 0.25, yend = 0.25, colour = "red") + 
    annotate("segment", x = 1850, xend = 1820, y = -0.8, yend = -0.95, colour = "blue", 
        size = 2, arrow = arrow()) + annotate("segment", x = 1950, xend = 1980, 
    y = -0.25, yend = -0.25, colour = "black", size = 2, arrow = arrow(ends = "both", 
        angle = 90, length = unit(0.2, "cm")))

7.5 添加矩形阴影

p1 <- p + annotate(geom = "rect", xmin = 1950, xmax = 1980, ymin = -1, ymax = 1, 
    alpha = 0.1, fill = "blue")
p2 <- p + annotate(geom = "rect", xmin = 1950, xmax = 1980, ymin = -Inf, ymax = Inf, 
    alpha = 0.1, fill = "blue")
multiplot(p1, p2, cols = 2)

7.6 高亮某一元素

要高亮一个或多个元素, 需要在数据中创建一个新列并将其映射为颜色

pg <- PlantGrowth
pg$h1 <- "no"
pg$h1[pg$group == "trt2"] <- "yes"
head(pg)
##   weight group h1
## 1   4.17  ctrl no
## 2   5.58  ctrl no
## 3   5.18  ctrl no
## 4   6.11  ctrl no
## 5   4.50  ctrl no
## 6   4.61  ctrl no
p1 <- ggplot(pg, aes(x = group, y = weight, fill = h1)) + geom_boxplot()
p2 <- ggplot(pg, aes(x = group, y = weight, fill = h1)) + geom_boxplot() + scale_fill_manual(values = c("grey85", 
    "#FFDDCC"), guide = FALSE)
multiplot(p1, p2, cols = 2)

7.7 添加误差线

使用geom_errorbar()并将变量映射到ymin和ymax的值

ce <- subset(cabbage_exp, Cultivar == "c39")
p1 <- ggplot(ce, aes(x = Date, y = Weight)) + geom_bar(stat = "identity", fill = "white", 
    colour = "black") + geom_errorbar(aes(ymin = Weight - se, ymax = Weight + 
    se), width = 0.2)
p2 <- ggplot(ce, aes(x = Date, y = Weight)) + geom_line(aes(group = 1)) + geom_point(size = 4) + 
    geom_errorbar(aes(ymin = Weight - se, ymax = Weight + se), width = 0.2)
multiplot(p1, p2, cols = 2)

对分组条形图添加误差线: p1:错误的图 p2:准确的图

p1 <- ggplot(cabbage_exp, aes(x = Date, y = Weight, fill = Cultivar)) + geom_bar(stat = "identity", 
    position = "dodge") + geom_errorbar(aes(ymin = Weight - se, ymax = Weight + 
    se), width = 0.2)

p2 <- ggplot(cabbage_exp, aes(x = Date, y = Weight, fill = Cultivar)) + geom_bar(stat = "identity", 
    position = "dodge") + geom_errorbar(aes(ymin = Weight - se, ymax = Weight + 
    se), width = 0.2, position = position_dodge(0.9))

multiplot(p1, p2, cols = 2)

7.8 向独立分面添加注解

p <- ggplot(mpg, aes(x = displ, y = hwy)) + geom_point() + facet_grid(. ~ drv)
f_labels <- data.frame(drv = c("4", "f", "r"), label = c("4wd", "Front", "Rear"))
p1 <- p + geom_text(x = 6, y = 40, aes(label = label), data = f_labels)
p2 <- p + annotate("text", x = 6, y = 42, label = "label text")
multiplot(p1, p2, cols = 1)