How to add image to ggplot2 under the grid? - r

The most popular (and simplest) way to adding image to the ggplot2 graph is annotation_custom:
library(ggplot2)
library(png)
library(grid)
img <- readPNG(system.file("img", "Rlogo.png", package="png"), TRUE)
gpp <- rasterGrob(img, interpolate=TRUE)
gpp$width <- unit(1, "npc")
gpp$height <- unit(1, "npc")
df <- data.frame(x=seq(1,2,0.01),y=seq(1,2,0.01))
ggplot(df,aes(x=x,y=y)) +
annotation_custom(gpp, xmin=1, xmax=2.5, ymin=1, ymax=1.5) +
geom_point()
In this way, image will be placed over the scale grid.
How to place image under the grid, but with bindings to the coords, not to the borders of the plot?

It's possible in the development version of ggplot2.
How to install it see this answer: https://stackoverflow.com/a/9656182/4265407
Minimal working example:
library(devtools)
dev_mode(on=T)
library(ggplot2)
library(png)
library(grid)
img <- readPNG(system.file("img", "Rlogo.png", package="png"), TRUE)
gpp <- rasterGrob(img, interpolate=TRUE)
gpp$width <- unit(1, "npc")
gpp$height <- unit(1, "npc")
df <- data.frame(x=seq(1,2,0.01),y=seq(1,2,0.01))
ggplot(df,aes(x=x,y=y)) +
annotation_custom(gpp, xmin=1, xmax=2.5, ymin=1, ymax=1.5) +
geom_point() + theme(panel.ontop=TRUE,
panel.background = element_rect(colour = NA,fill="transparent"))

Related

Change orientation of grob background gradient

I was surprised that the following simple grob created from a vector of colors works almost as requested.
However, I would like to make the gradient left to right, not top to bottom.
library(ggplot2)
library(grid)
grad = colorRampPalette(c("red", "yellow"))(10)
ggplot(df, aes(x,y)) +
annotation_custom(rasterGrob(grad,
width=unit(1,"npc"),
height=unit(1,"npc"))) +
scale_x_continuous(limits = c(0,1)) +
scale_y_continuous(limits = c(0,1))
Answer is t
You have to transpose your grad vector (input to rasterGrob):
library(ggplot2)
ggplot() +
annotation_custom(rasterGrob(t(grad),
width = unit(1, "npc"), height = unit(1, "npc")))

adjust image size to ggplot2 grid

I need to plot over an image. The problem I have is that my PNG image doesn't adjust to grid:
library(webshot)
library(png)
webshot("http://www.doctormetrics.com/","doctor.png")
img <- readPNG("doctor.png")
dim(img)
x11()
g <- rasterGrob(img, interpolate=TRUE)
qplot(1:2, 1:2, geom="blank") +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_point()
You could do
library(webshot)
library(png)
library(ggplot2)
library(grid)
webshot("http://www.doctormetrics.com/",tf<-tempfile(fileext = ".png"))
img <- readPNG(tf)
g <- rasterGrob(img, interpolate=TRUE, height = 1, width = 1)
ggplot() +
annotation_custom(g, xmin=1, xmax=2, ymin=1, ymax=2) +
geom_point(aes(x,y), data.frame(x=1:2, y=1:2)) +
coord_fixed(ratio = nrow(img)/ncol(img))

Arrange ggplot plots (grobs with same widths) using gtable to create 2x2 layout

I am attempting to use grobs and gtable to arrange 4 (ggplot2) plots into a 2x2 grid. I don't know how to set widths, and also a non- 1xn, or nx1 arrangement.
Using this code:
data(iris)
a <- ggplot(iris, aes(x=Species, y=Petal.Width)) + geom_boxplot(color="black") + ylab(expression(Foo~Bar~(g~cm^{-3})))
b <- ggplot(iris, aes(x=Species, y=Petal.Length*100)) + geom_boxplot(color="black") + ylab("foobar (mm)")
c <- ggplot(iris, aes(x=Species, y=Sepal.Width)) + geom_boxplot(color="black") + ylab("foobar (%)")
d <- ggplot(iris, aes(x=Species, y=log10(Sepal.Length))) + geom_boxplot(color="black") + ylab("foobar (cm)")
plots <- list(a,b,c,d)
grobs = lapply(plots, ggplotGrob)
g = do.call(rbind, c(grobs, size="first"))
g$widths = do.call(unit.pmax, lapply(grobs, "[[", "widths"))
grid.newpage()
grid.draw(g)
I can create the following 1x4 arrangement.
If I use grid.arrange for two columns, on the 4 plots, the plots are of different widths.
How can I bind plots into a gtable for a 4 x 4 arrangement?
# I thought maybe I could cbind, then rbind, but this does not work
plots1 <- list(a,b)
plots2 <- list(c,d)
grobs1 = lapply(plots1, ggplotGrob)
grobs2 = lapply(plots2, ggplotGrob)
g1 = do.call(cbind, c(grobs1, size="first"))
g2 = do.call(cbind, c(grobs2, size="first"))
# g3 = do.call(rbind, c(g1,g2, size="first")) #this does not work
I think you already had the answer.
Your last line returns an error, but a small edit results in a combined plot where widths within columns are the same:
g3 = do.call(rbind, c(list(g1,g2), size="first")) #combine g1 and g2 into a list
A sidenote for aesthetics/reference:
If your x-axis is the same, you can drop it from the top two plots.
library(ggplot2); library(gridExtra); library(grid)
# Tweak the margins to use up empty space. Margins: Top, Right, Bottom, Left
# For reference: a1= top left, b1= top right
# c1= bottom left, d1= bottom right
a1 <- a + theme(axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x= element_blank(),
plot.margin= unit(c(1, 1, -0.5, 0.5), "lines") )
b1 <- b + theme(axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x= element_blank(),
plot.margin= unit(c(1, 1, -0.5, 0.5), "lines") )
c1 <- c + theme(plot.margin= unit(c(0, 1, 0.5, 0.5), "lines") )
d1 <- d + theme(plot.margin= unit(c(0, 1, 0.5, 0.5), "lines") )
grobz <- lapply(list(a1, b1, c1, d1), ggplotGrob)
grobz.plot <- arrangeGrob( grobs = list(rbind(grobz[[1]], grobz[[3]], size = "last"),
rbind(grobz[[2]], grobz[[4]], size = "last")),
ncol = 2)
grid.draw(grobz.plot)
These StackOverflow questions are helpful in aligning plots:
Using rbind in gtable to set plot width (Baptiste) [link]
Relative panel heights in gtable (Baptiste) [link]
Plot widths and legends [link]
Pretty similar to the above, but using gtable functions*
library(ggplot2)
pl <- list(ggplot() + xlab("x"),
ggplot() + ylab("y"),
ggplot() + ylab("y"),
ggplot() + ggtitle("title") + xlab("x"))
library(grid)
library(gridExtra)
gl <- lapply(pl, ggplotGrob)
# gt <- cbind(rbind(gl[[1]], gl[[3]]),
# rbind(gl[[2]], gl[[4]]))
# alternative to remove x-axes of top row of plots
gt <- cbind(rbind(gl[[1]][1:3,], gl[[3]]),
rbind(gl[[2]][1:3,], gl[[4]]))
grid.newpage()
grid.draw(gt)
*: actually, since gtable doesn't allow the use of pmax when comparing units, this is using a drop-in replacement from the dev version of gridExtra.
would this work for you
library(cowplot)
library(ggplot2)
data(iris)
a <- ggplot(iris, aes(x=Species, y=Petal.Width)) + geom_boxplot(color="black") + ylab(expression(Foo~Bar~(g~cm^{-3}))) + theme_grey()
b <- ggplot(iris, aes(x=Species, y=Petal.Length*100)) + geom_boxplot(color="black") + ylab("foobar (mm)") + theme_grey()
c <- ggplot(iris, aes(x=Species, y=Sepal.Width)) + geom_boxplot(color="black") + ylab("foobar (%)") + theme_grey()
d <- ggplot(iris, aes(x=Species, y=log10(Sepal.Length))) + geom_boxplot(color="black") + ylab("foobar (cm)") + theme_grey()
plot_grid(a,b, c, d, ncol=2,align="v")

problems with arrangeGrob under R version 3.2.2

I 've updated my R version including all packages and the function arrangeGrob (Package gridExtra) has changed.
On my old version R version 3.1.3 I used it as the following to make corner labels:
loading r packages
library(ggplot2)
library(grid)
library(gridExtra)
example data
a <- 1:20
b <- sample(a, 20)
c <- sample(b, 20)
d <- sample(c, 20)
create a data frame
mydata <- data.frame(a, b, c, d)
create example plots
myplot1 <- ggplot(mydata, aes(x=a, y=b)) + geom_point()
myplot2 <- ggplot(mydata, aes(x=b, y=c)) + geom_point()
myplot3 <- ggplot(mydata, aes(x=c, y=d)) + geom_point()
myplot4 <- ggplot(mydata, aes(x=d, y=a)) + geom_point()
set corner labels
myplot1 <- arrangeGrob(myplot1, main = textGrob("A", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
myplot2 <- arrangeGrob(myplot2, main = textGrob("B", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
myplot3 <- arrangeGrob(myplot3, main = textGrob("C", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
myplot4 <- arrangeGrob(myplot4, main = textGrob("D", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
grid.arrange(myplot1, myplot2, myplot3, myplot4)
and I got the following plot, which was fine:
but under the new R version 3.2.2 the image looks like this:
arrangeGrob opens for every textGrob a new image and I got eight images on one page instead of four. How can I fixed it that the plot looks like in the old version of R and gridExtra?
From Kev's comment:
There has been a rewrite of gridExtra, that is not (fully) backward
compatible - may be the issue. Have a look at the new wiki
cran.r-project.org/web/packages/gridExtra/vignettes/… . Try changing
main to top – user20650

Label individual panels in a multi-panel ggplot2

I'm interested in trying to create simple corner labels for a multipanel figure I am preparing in ggplot. This is similar to this previously asked question, but the answers only explained how to include a label at the top of the plot, not produce a corner label in the format required by many journals. I hope to replicate something similar to the plotrix function corner.label() in ggplot2.
Here is an example using plottrix of what I would like to recreate in ggplot2.
require(plotrix)
foo1<-rnorm(50,25,5)
foo2<-rpois(50,25)
foo3<-rbinom(50,25,0.5)
foo4<-rnbinom(50,25,0.5)
par(mfrow=c(2,2))
hist(foo1)
corner.label(label='a',figcorner=T)
hist(foo2)
corner.label(label='b',figcorner=T)
hist(foo3)
corner.label(label='c',figcorner=T)
hist(foo4)
corner.label(label='d',figcorner=T)
This produces the following:
Thanks for any help in advance!
Two recent changes have made this a lot easier:
The latest release of ggplot2 has added the tag caption which can be used to label subplots.
The package patchwork makes it really easy to plot multiple ggplot objects. https://github.com/thomasp85/patchwork
This means that no altering of grobs is required. Adapting the reproducible example provided by Kev:
library(ggplot2)
# install.package("patchwork")
library(patchwork)
a <- 1:20
b <- sample(a, 20)
c <- sample(b, 20)
d <- sample(c, 20)
mydata <- data.frame(a, b, c, d)
myplot1 <- ggplot(mydata, aes(x=a, y=b)) + geom_point() + labs(tag = "A")
myplot2 <- ggplot(mydata, aes(x=b, y=c)) + geom_point() + labs(tag = "B")
myplot3 <- ggplot(mydata, aes(x=c, y=d)) + geom_point() + labs(tag = "C")
myplot4 <- ggplot(mydata, aes(x=d, y=a)) + geom_point() + labs(tag = "D")
myplot1 + myplot2 + myplot3 + myplot4
Extension: Changing Style:
If you want to change the labelling style, you can either set this individually for each plot or set a theme default. I would recommend the second approach. Add the following line before you build your plots to make the font bold and blue
ggplot2::theme_update(plot.tag = element_text(face = "bold", colour = "blue"))
For more information on customising the theme of ggplot2, see here.
I had the same problem and came up with the following solution, which is a bit different:
loading r packages
library(ggplot2)
library(grid)
library(gridExtra)
example data
a <- 1:20
b <- sample(a, 20)
c <- sample(b, 20)
d <- sample(c, 20)
create a data frame
mydata <- data.frame(a, b, c, d)
create example plots
myplot1 <- ggplot(mydata, aes(x=a, y=b)) + geom_point()
myplot2 <- ggplot(mydata, aes(x=b, y=c)) + geom_point()
myplot3 <- ggplot(mydata, aes(x=c, y=d)) + geom_point()
myplot4 <- ggplot(mydata, aes(x=d, y=a)) + geom_point()
set corner labels
myplot1 <- arrangeGrob(myplot1, top = textGrob("A", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
myplot2 <- arrangeGrob(myplot2, top = textGrob("B", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
myplot3 <- arrangeGrob(myplot3, top = textGrob("C", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
myplot4 <- arrangeGrob(myplot4, top = textGrob("D", x = unit(0, "npc")
, y = unit(1, "npc"), just=c("left","top"),
gp=gpar(col="black", fontsize=18, fontfamily="Times Roman")))
plotting all plots on one page
grid.arrange(myplot1, myplot2, myplot3, myplot4, ncol = 2)
An example:
d <- data.frame(x = runif(16),
y = runif(16),
grp = rep(letters[1:4],each = 4))
ggplot(d,aes(x = x,y = y)) +
facet_wrap(~grp) +
geom_point() +
theme(strip.text = element_text(hjust = -0.05),
strip.background = element_blank())
Here's a solution using a custom labeller function. This doesn't invovle any manipulations to the data. Currently it only works with 1-dimensional facets (facet_wrap). I'm still working on how to increment along a 2-D grid...
Define the labeller function
make_labelstring <- function(mypanels) {
mylabels <- sapply(mypanels,
function(x) {LETTERS[which(mypanels == x)]})
return(mylabels)
}
label_panels <- ggplot2::as_labeller(make_labelstring)
Pass label_panels as the labeller to facet_wrap
library(ggplot2)
data("diamonds")
# create a faceted plot
ggplot(data = diamonds, aes(x = depth, y = price)) +
geom_point() +
facet_wrap(~cut, labeller = label_panels) +
theme(strip.text = element_text(hjust = -0),
strip.background = element_blank())

Resources