I need to wrap several plots in a grid, often an uneven number, so there'll often be an "empty spot".
I need to use arrangeGrob() -- not grid.arrange() -- because I want to save the plot for later, not plot() it right away.
This works fine, but oddly, arrangeGrob() leaves some weird background in the empty spots.
Like so:
library(ggplot2)
p1 <- ggplot(mtcars, aes(x=factor(cyl), y=mpg)) + geom_boxplot()
p2 <- ggplot(mtcars, aes(x=factor(cyl), y=wt)) + geom_boxplot()
p3 <- ggplot(mtcars, aes(x =factor(cyl), y=disp)) + geom_boxplot()
library(gridExtra)
y <- arrangeGrob(p1, p2, p3, ncol = 2)
plot(y)
yields a plot with some weird gray stuff in the bottom right corner:
Compare this to grid.arrange():
grid.arrange(p1, p2, p3, ncol = 2)
yields a pretty plot with no grey weirdness:
Where does this gray stuff in the bottom right corner come from? And how do I get rid of it?
Notice that I cannot avoid the empty spots by changing ncol; I sometimes have an uneven number of plots, so there'll always be empty spots.
I'm ok with empty spots, I just like them to be clean.
(In isolation, that last sentence sounds pretty OCD-ish.
UPDATE
The package author (?) answered below: I should have used grid.draw(y).
A similar problem remains (maybe the same root cause?): if you plot some object before, the "empty spot" remains occupied by that past plot.
Weird.
Like so:
plot(p1)
grid.draw(y)
yields:
arrangeGrob() now returns a gtable, which you should draw with grid.draw(), not plot().
grid.draw(y)
yields
To get rid of artefacts from past plots (as per above update) use grid.newpage().
Remove the nrow argument. Like so:
library(ggplot2)
p1 <- ggplot(mtcars, aes(x=factor(cyl), y=mpg)) + geom_boxplot()
p2 <- ggplot(mtcars, aes(x=factor(cyl), y=wt)) + geom_boxplot()
library(gridExtra)
y <- arrangeGrob(p1, p2, ncol = 2)
plot(y)
Related
I would like to create a facet plot with ggplot and show the x-axis with ticks on all facets. Then I want to use ggplotly to convert the result to a plotly graph. However when I use scales='free_x' to add the extra x-axes to the facets, the zoom linkage is lost. i.e. when I zoom on one of the facets it doesn't zoom on the others automatically. Is there a way to add that functionality back in?
This is a reprex showing the problem:
library(ggplot2)
library(ggthemes)
library(plotly)
p <- ggplot(mtcars, aes(mpg, hp)) + geom_point() + facet_wrap(~carb, ncol = 1, scales='free_x') +
theme_tufte() + theme(axis.line=element_line()) +
scale_x_continuous(limits=c(10,35)) + scale_y_continuous(limits=c(0,400))
ggplotly(p)
Notice here when I zoom in on the top plot, the other plots remain unchanged:
I have three plots to show and I'd like to place them in a matrix of plots. The first in the top-left corner, the second in the top-right one and the third in the bottom-left one.
These plots share the same legend and I'd like to show it in the bottom-right corner as in the figure:
I'm using the ggarrange() function of the egg package to display the plots like this.
Thanks for the help.
One option to achieve your desired result would be to switch to the patchwork package:
Using mtcars as example data:
library(ggplot2)
library(patchwork)
p <- ggplot(mtcars, aes(factor(cyl), mpg, fill = factor(am))) +
geom_boxplot()
list(p, p, p) |>
wrap_plots(nrow = 2) +
guide_area() +
plot_layout(guides = "collect")
Is there a way to spread facetted plots apart in ggplot2? As you can see in the picture (the bottom section of my plot), the x-axes are overlapping a bit at the ends of each plot, obscuring the years. I'd like to move them apart. No matter how much I increase the width when exporting, the values still overlap.
My code, if relevant:
ggplot(filter(TotalsRegion, Source!="Total"), aes(x=Date, y=SourceSum, col=Source)) +
geom_line(size=1) +
facet_grid(.~Region)
Since you did not provide a reproducible example, we'll have to make one for you.
library(ggplot2)
library(grid)
data(mpg)
mpg$displ <- mpg$displ + 2000
p <- ggplot(mpg, aes(displ, cty))
p <- p + geom_point()
p <- p + facet_grid(. ~ cyl)
p
p <- p + theme(panel.margin.x=unit(20, "pt"))
p
This does not suffer from the overlap (can't do all the work for you) but hopefully it's clear what the panel margin settings do.
To display multiple plots I use multiplot (http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/), now I have two plots who share the same x-axis range and are plotted above each other:
multiplot(plot1, plot2)
I removed the x-axis labels and title using:
xlab(NULL) + theme(axis.text.x=element_blank(),axis.ticks.x=element_blank())
But there is still a white margin between the two plots. How can I make this margin smaller or remove it?
To reduce space between the plots, remove the bottom margin of the top plot and remove the top margin of the bottom plot. The code below sets these margins to 0, which still results in a tiny bit of white space between the plots. You can make these margins slightly negative (maybe -0.1 or so) to completely remove the white space. Rather than the multiplot function, we use grid.arrange from the gridExtra package to lay out the plots. :
library(grid)
library(gridExtra)
## Create two sample plots with the same x axis using built-in mtcars data frame
# Top plot: Remove bottom margin, x-labels, and x title
p1 = ggplot(mtcars, aes(wt, mpg)) + geom_point() +
xlab(NULL) +
theme(axis.text.x=element_blank(),axis.ticks.x=element_blank(),
plot.margin=unit(c(1,1,0,1), "lines"))
# Bottom plot: Remove top margin
p2 = ggplot(mtcars, aes(wt, carb)) + geom_point() +
theme(plot.margin=unit(c(0,1,1,1), "lines"))
# Lay out plots in one column
grid.arrange(p1, p2, ncol=1)
Two problems with the above layout: (1) the y axes are not justified properly, and (2) the height of the lower plot's plot area is less than that of upper plot's plot area. The code below addresses these issues:
# Left justify plots
# Source: http://stackoverflow.com/a/13295880/496488
gA <- ggplotGrob(p1)
gB <- ggplotGrob(p2)
maxWidth = grid::unit.pmax(gA$widths[2:5], gB$widths[2:5])
gA$widths[2:5] <- as.list(maxWidth)
gB$widths[2:5] <- as.list(maxWidth)
# Lay out justified plots. Use heights argument to equalize heights of each plot area
grid.arrange(gA, gB, heights=c(0.47,0.53), ncol=1)
You can exactly equalize the heights of each plot area using the same trick as we used to left-justify the plots (rather than doing it by eye using the heights argument to grid.arrange), but then the plot margins get added back. I'm not sure of how to deal with that, but here's the code for reference:
maxHeight = grid::unit.pmax(gA$heights[2:5], gB$heights[2:5])
gA$heights[2:5] <- as.list(maxHeight)
gB$heights[2:5] <- as.list(maxHeight)
The last update of ggplot2 gives much more control over the plot. See for example:
ggplot(mtcars, aes(disp, mpg)) +
geom_point() +
facet_wrap(~vs)
You can further adjust the labels, number of rows, and how scales will be displayed, for instance: nrow = 2; scales = "free".
It is easier than you might think to re-arrange the data so that you can take advantage of the nice alignment features that already exist in ggplot2. See below for an example replicating eipi10's answer, but without having to use ggplotGrob.
What you have to do is just select the columns you want to plot, along with the ID columns (in this case, the car model and the x-axis value column). Then melt, and it's ready to plot using the standard facet procedure.
Note that the "switch" option in the facet_grid call is a new feature that you can access by updating to the most recent CRAN version. I used that to replace the regular y-axis title, which was omitted using theme.
The nice part about this approach is that the plots will always be perfectly aligned.
library("ggplot2")
library("dplyr")
library("reshape2")
df <- mtcars %>%
add_rownames(var = "Model") %>%
select(Model, wt, mpg, carb) %>%
melt(id.vars = c("Model","wt"))
ggplot(df)+
aes(x=wt, y=value)+
geom_point()+
theme(strip.background=element_blank())+
facet_grid(variable ~ ., scales="free_y", switch="y")
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