ggsave() doesn't seem to work with the grid package (see below). How do I save this combination of plot p1 and plot p2. The following code only save the last plot p2 that ggplot() sees.
library(tidyverse)
p1 <- ggplot(mpg, aes(fl)) + geom_bar()
p2 <- ggplot(mpg, aes(cty, hwy)) + geom_col()
grid.newpage()
grid.draw(rbind(ggplotGrob(p1), ggplotGrob(p2), size = "last"))
ggsave("mpg.png")
Consider using gridExtra. As explained in this vignette, gridExtra, building off of gtable (a higher-level layout scheme), provides more facility in arranging multiple grobs on a page, while grid package provides low-level functions to create graphical objects (grobs).
library(ggplot2)
library(gridExtra)
p1 <- ggplot(mpg, aes(fl)) + geom_bar()
p2 <- ggplot(mpg, aes(cty, hwy)) + geom_col()
p <- grid.arrange(p1, p2)
ggsave(plot=p, filename="myPlot.png")
I think you can do something like this.
#plotFile
g1=file.path(HomeDir,plotFile)
f1=grid.arrange(p1,p2, ncol=2, top=textGrob("Multiple Plots", gp=gpar(fontsize=12, font = 2))) #arranges plots within grid
g <- arrangeGrob(f1) #generates g
#save
ggsave(g1, g,width = 29.7, height = 21, units = 'cm') #saves g
You have to assign the new combination first then use ggsave() to print it.
# here I name it to_print
to_print <- rbind(ggplotGrob(p1), ggplotGrob(p2), size = "last")
ggsave(filename = "mpg.png", plot = to_print)
hope this helps!
I've got a few different categories that I want to plot. These are different categories, each with their own set of labels, but which makes sense to group together in the document. The following gives some simple stacked bar chart examples:
df <- data.frame(x=c("a", "b", "c"),
y=c("happy", "sad", "ambivalent about life"))
ggplot(df, aes(x=factor(0), fill=x)) + geom_bar()
ggplot(df, aes(x=factor(0), fill=y)) + geom_bar()
The problem is that with different labels, the legends have different widths, which means the plots have different widths, leading to things looking a bit goofy if I make a table or \subfigure elements. How can I fix this?
Is there a way to explicitly set the width (absolute or relative) of either the plot or the legend?
Edit: Very easy with egg package
# install.packages("egg")
library(egg)
p1 <- ggplot(data.frame(x=c("a","b","c"),
y=c("happy","sad","ambivalent about life")),
aes(x=factor(0),fill=x)) +
geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),
y=c("happy","sad","ambivalent about life")),
aes(x=factor(0),fill=y)) +
geom_bar()
ggarrange(p1,p2, ncol = 1)
Original Udated to ggplot2 2.2.1
Here's a solution that uses functions from the gtable package, and focuses on the widths of the legend boxes. (A more general solution can be found here.)
library(ggplot2)
library(gtable)
library(grid)
library(gridExtra)
# Your plots
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()
# Get the gtables
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# Set the widths
gA$widths <- gB$widths
# Arrange the two charts.
# The legend boxes are centered
grid.newpage()
grid.arrange(gA, gB, nrow = 2)
If in addition, the legend boxes need to be left justified, and borrowing some code from here written by #Julius
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()
# Get the widths
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")
# Set the widths
gA$widths <- gB$widths
# Add an empty column of "abs(diff(widths)) mm" width on the right of
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))
# Arrange the two charts
grid.newpage()
grid.arrange(gA, gB, nrow = 2)
Alternative solutions There are rbind and cbind functions in the gtable package for combining grobs into one grob. For the charts here, the widths should be set using size = "max", but the CRAN version of gtable throws an error.
One option: It should be obvious that the legend in the second plot is wider. Therefore, use the size = "last" option.
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# Combine the plots
g = rbind(gA, gB, size = "last")
# Draw it
grid.newpage()
grid.draw(g)
Left-aligned legends:
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")
# Add an empty column of "abs(diff(widths)) mm" width on the right of
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))
# Combine the plots
g = rbind(gA, gB, size = "last")
# Draw it
grid.newpage()
grid.draw(g)
A second option is to use rbind from Baptiste's gridExtra package
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# Combine the plots
g = gridExtra::rbind.gtable(gA, gB, size = "max")
# Draw it
grid.newpage()
grid.draw(g)
Left-aligned legends:
# Get the grobs
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
# The parts that differs in width
leg1 <- convertX(sum(with(gA$grobs[[15]], grobs[[1]]$widths)), "mm")
leg2 <- convertX(sum(with(gB$grobs[[15]], grobs[[1]]$widths)), "mm")
# Add an empty column of "abs(diff(widths)) mm" width on the right of
# legend box for gA (the smaller legend box)
gA$grobs[[15]] <- gtable_add_cols(gA$grobs[[15]], unit(abs(diff(c(leg1, leg2))), "mm"))
# Combine the plots
g = gridExtra::rbind.gtable(gA, gB, size = "max")
# Draw it
grid.newpage()
grid.draw(g)
The cowplot package also has the align_plots function for this purpose (output not shown),
both2 <- align_plots(p1, p2, align="hv", axis="tblr")
p1x <- ggdraw(both2[[1]])
p2x <- ggdraw(both2[[2]])
save_plot("cow1.png", p1x)
save_plot("cow2.png", p2x)
and also plot_grid which saves the plots to the same file.
library(cowplot)
both <- plot_grid(p1, p2, ncol=1, labels = c("A", "B"), align = "v")
save_plot("cow.png", both)
As #hadley suggests, rbind.gtable should be able to handle this,
grid.draw(rbind(ggplotGrob(p1), ggplotGrob(p2), size="last"))
however, the layout widths should ideally be size="max", which doesn't cope well with some types of grid units.
Just by chance, I noticed that Arun's solution he had suggested in his comments hasn't been picked up. I feel his simple and efficient approach is really worth to be illustrated.
Arun suggested to move the legend to the top or bottom:
ggplot(df, aes(x=factor(0), fill=x)) + geom_bar() + theme(legend.position = "bottom")
ggplot(df, aes(x=factor(0), fill=y)) + geom_bar() + theme(legend.position = "bottom")
Now, the plots have the same width as requested. In addition, the plot area is equally sized in both cases.
If there are more factors or even longer labels, it might become necessary to play around with the legend, e.g., to display the legend in two ore more rows. theme() and guide_legend() have several parameters to control the position and appearance of legends in ggplot2.
I created a little function based on the answer of #Sandy.
same.size.ggplot <- function(vector.string.graph, # a vector of strings which correspond to Robject ggplot graphs
reference.string.graph, # a string of a Robject ggplot graphs where height and/or height will be taken for reference
width = T, # if you wanna adapat only the width
height = F # if you wanna adapat only the height
) {
# example: same.size.ggplot(p0rep(c("a", "b"), thre), "a30")
which(vector.string.graph %in% reference.string.graph)
newref <- ggplotGrob(get(reference.string.graph))
ref.width <- newref$widths
ref.height <- newref$heights
assign(reference.string.graph, newref, env = parent.frame(1))
for(i in seq_along(vector.string.graph)) {
if(vector.string.graph[i] != reference.string.graph) {
new <- ggplotGrob(get(vector.string.graph[i]))
if( width ) {
new$widths <- ref.width
}
if( height ) {
new$heights <- ref.height
}
assign(vector.string.graph[i], new, env = parent.frame(1))
}
}
}
p1 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=x)) + geom_bar()
p2 <- ggplot(data.frame(x=c("a","b","c"),y=c("happy","sad","ambivalent about life")),aes(x=factor(0),fill=y)) + geom_bar()
p3 <- ggplot(data.frame(x=c("a","b","c"),y=c("Crazy happy","sad","Just follow the flow")),aes(x=factor(0),fill=y)) + geom_bar()
grid.arrange(p1, p2, p3, ncol = 1)
same.size.ggplot(c("p1", "p2", "p3"), "p2") # same as same.size.ggplot(c("p2", "p3"), "p1")
grid.arrange(p1, p2, p3, ncol = 1)
Before
After
You could also use the patchwork-package for that:
require(ggplot2)
require(patchwork)
# data
df = data.frame(x = c("a", "b", "c"),
y = c("happy", "sad", "ambivalent about life"))
p1 = ggplot(df, aes(x=factor(0), fill=x)) + geom_bar()
p2 = ggplot(df, aes(x=factor(0), fill=y)) + geom_bar()
# Patchwork 1: Does it automatically
p1 / p2
# Patchwork 2: Create a list
l = patchwork::align_patches(p1, p2)
I have two dataframes which I will like to map. The dfs have the same xy coordinates and I need a single colorbar with a visible discrete color scale for both dfs like the one shown here. I would like the colors in the colorkey to match the self-defined breaks. a more general solution that can be applied outside this example is much appreciated
The RdYIBu color palette from the RcolorBrewer package is what I am after.
My code so far:
library(rasterVis)
ras1 <- raster(nrow=10,ncol=10)
set.seed(1)
ras1[] <- rchisq(df=10,n=10*10)
ras2=ras1*(-1)/2
s <- stack(ras1,ras2)
Uniques <- cellStats(s,stat=unique)
Uniques.max <- max(Uniques)
Uniques.min <- min(Uniques)
my.at <- round(seq(ceiling(Uniques.max), floor(Uniques.min), length.out= 10),0)
myColorkey <- list(at=my.at, labels=list(at=my.at))
levelplot(s, at=my.at, colorkey=myColorkey,par.settings=RdBuTheme())
How can I set the values in the colorkey to match values on the map as shown on the sample map above? Note that the number of colors in the colorkey should be the same number shown on the map.
Many thanks for your help. Your suggestions will help me to develop many such maps.
Thanks.
The following should get you going. With the ggplot2 documentation and the many online examples,you should be able to tweak the aesthetics to get it to look exactly as you want without any troubles.Cheers.
#Order breaks from lowest to highest
my_at <- sort(my_at)
#Get desired core colours from brewer
cols0 <- brewer.pal(n=length(my_at), name="RdYlBu")
#Derive desired break/legend colours from gradient of selected brewer palette
cols1 <- colorRampPalette(cols0, space="rgb")(length(my_at))
#Convert raster to dataframe
df <- as.data.frame(s, xy=T)
names(df) <- c("x", "y", "Epoch1", "Epoch2")
#Melt n-band raster to long format
dfm <- melt(df, id.vars=c("x", "y"), variable.name="epoch", value.name="value")
#Construct continuous raster plot without legend
#Note usage of argument `values` in `scale_fill_gradientn` -
#-since your legend breaks are not equi-spaced!!!
#Also note usage of coord_equal()
a <- ggplot(data=dfm, aes(x=x, y=y)) + geom_raster(aes(fill=value)) + coord_equal()+
facet_wrap(facets=~epoch, ncol=1) + theme_bw() +
scale_x_continuous(expand=c(0,0))+
scale_y_continuous(expand=c(0,0))+
scale_fill_gradientn(colours=cols1,
values=rescale(my_at),
limits=range(dfm$value),
breaks=my_at) +
theme(legend.position="none", panel.grid=element_blank())
#Make dummy plot discrete legend whose colour breaks go along `cols1`
df_leg <- data.frame(x=1:length(my_at), y=length(my_at):1, value=my_at)
gg_leg <- ggplot(data=df_leg, aes(x=x, y=y)) + geom_raster(aes(fill=factor(value))) +
scale_fill_manual(breaks=my_at, values=cols1,
guide=guide_legend(title="",
label.position="bottom")) +
theme(legend.position="bottom")
#Extract discrete legend from dummy plot
tmp <- ggplot_gtable(ggplot_build(gg_leg))
leg <- which(sapply(tmp$grobs, function(x) x$name)=="guide-box")
legend <- tmp$grobs[[leg]]
#Combine continuous plot of your rasters with the discrete legend
grid.arrange(a, legend, ncol=1, heights=c(4, 0.8))
I need to put Greek letters into facet labels using facet_wrap() in ggplot2. I found a Link describing the same for facet_grid(). I applied this for my data, using the following code:
levels(parameters) <- c(expression(alpha), expression(beta))
p + facet_grid(.~parameters, labeller = label_parsed)
This works great and does exactly what I want. However, I need to use facet_wrap() instead (to get separate y-axes for both paramters, and also to plot even more parameters in different columns and rows). I tried the following:
p + facet_wrap(.~parameters, labeller = label_parsed) , or
p + facet_wrap(.~parameters)
but this didn't work because there is no "labeller" function in facet_wrap. How could this be done using grid?
This example should get you started:
library("ggplot2")
library("grid")
d <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() +
facet_wrap(~Species)
grob <- ggplotGrob(d)
strip_elem <- grid.ls(getGrob(grob, "strip.text.x", grep=TRUE, global=TRUE))$name
grob <- grid::editGrob(grob, strip_elem[1], label=expression(alpha[1]))
grob <- grid::editGrob(grob, strip_elem[2], label=expression(beta^2))
grob <- grid::editGrob(grob, strip_elem[3], label=expression(hat(gamma)))
grid.draw(grob)
Update: this works with ggplot2 version 0.9.3 (although using grid is a fragile way to modify ggplot2 graphics)
grob[["grobs"]][["strip_t.1"]][["children"]][[2]][["label"]] <- expression(alpha[1])
grob[["grobs"]][["strip_t.2"]][["children"]][[2]][["label"]] <- expression(beta^2)
grob[["grobs"]][["strip_t.3"]][["children"]][[2]][["label"]] <- expression(hat(gamma))
grid.draw(grob)
I tried it using the code below, and it works for me.
library("ggplot2")
library("grid")
## 1. Plot d and print d
d <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) + geom_point() + facet_wrap(~Species)
d
## 2. Put Greek letters into facet labels using grid.edit function
grid.force()
grid.ls() #You should find the exact names for facet labels in the printed output!
grid.edit("GRID.text.77",label=expression(alpha[1])) #"GRID.text.77" = name for the first facet label
grid.edit("GRID.text.80",label=expression(beta^2)) #"GRID.text.80" = name for the second facet label
grid.edit("GRID.text.83",label=expression(hat(gamma))) #"GRID.text.83" = name for the third facet label