How to avoid axis line disappearing when using ggarrange? - r

I'd like to arrange two facet plots using ggarrange (in order to get x axes aligned).
library(egg)
library(ggplot2)
p1 <- ggplot(warpbreaks) +
geom_bar(aes(x = wool)) +
facet_wrap(~tension, ncol = 2, scales = "free_x") +
theme_bw() +
theme(axis.line = element_line(colour = "black", size = .1),
panel.border = element_blank(),
strip.background = element_blank())
p2 <- ggplot(warpbreaks) +
geom_bar(aes(x = tension)) +
facet_wrap(~wool) +
theme_bw() +
theme(axis.line = element_line(colour = "black", size = .1),
panel.border = element_blank(),
strip.background = element_blank())
ggarrange(p1, p2, ncol = 2)
Works great, but unfortunately the vertical axis lines disappeared. This does not happen when using grid.arrange, but at least for my real data there the x axes are not aligned, hence my wish to use ggarrange. Is there a way to keep the axis lines?

tl;dr: setting panel.background = element_blank() should restore the axes.
I think it's a combination of a clipping issue in ggplot2 (the y axis line can be clipped by the plot panel, cutting its width in half), and egg::gtable_frame placing the axis below the plot panel.
library(egg)
library(ggplot2)
p1 <- ggplot(warpbreaks) +
geom_bar(aes(x = wool)) +
facet_wrap(~tension, ncol = 2, scales = "free_x") +
theme_bw() +
theme(axis.line = element_line(colour = alpha("red", 0.5), size = 5),
panel.border = element_blank(),
panel.background = element_rect(fill = alpha("white", 0.5),
linetype = 2, colour = "black"),
strip.background = element_blank())
p1
g1 <- ggplotGrob(p1)
gg <- gtable_frame(g1)
grid.newpage()
grid.draw(gg)

Related

Arrange faceted plots in a grid - how to completely remove facet labels to avoid overlapping

I am a bit stuck with the following: I want to arrange multiple (gg)plots into a grid with cowplot::plot_grid. Below is an example with two ggplots (g_bottom and g_top), both faceted. The bottom one has the facet labels deleted as they are redundant. However, there seems to remain the contour of the background or so, acting as cutting with a white line the top plot (see image below).
How could I fix this?
What have I tried so far:
Instead of strip.background = element_blank() I also tried strip.background = element_rect(fill = NA, color = NA) in theme, but with no success.
If I set rect = element_blank(), it somehow works, but I lose the entire plot border. I was then hopping that rect = element_rect(fill = "transparent", colour = NA) would do it, but still no success. I also just tried colour = NULL or colour = "transparent" also with no success.
library(ggplot2)
library(cowplot)
g <- ggplot(mpg, aes(class)) +
geom_bar() +
facet_grid(. ~ year) +
theme_bw()
g_bottom <- g +
theme(
strip.text = element_blank(),
strip.background = element_blank(),
# strip.background = element_rect(fill = NA, color = NA) # didn't work either
# Was hoping that this will do the trick, bot no success:
rect = element_rect(fill = "transparent", color = NA)
)
g_top <- g +
labs(x = element_blank()) +
theme(
axis.text.x = element_blank(),
axis.ticks.x = element_blank()
)
plot_grid(g_top, NULL, g_bottom,
# used NULL to be able to tweak spacing between plots with rel_heights
align = "hv",
nrow = 3,
rel_heights = c(1, -0.2, 1))
I could go around the problem by not faceting and creating each of the 4 plots individually, but maybe there is a more straightforward solution with some theme argument which I'm too blinded to see any-further...
Eventually, using rect = element_blank() in theme when making g_bottom and then adding panel.border = element_rect(colour = "black") seems to do the trick. I still fail to understand why the initial trials didn't work as expected.
library(ggplot2)
library(cowplot)
g <- ggplot(mpg, aes(class)) +
geom_bar() +
facet_grid(. ~ year) +
theme_bw()
g_bottom <- g +
theme(
strip.text = element_blank(),
rect = element_blank(),
panel.border = element_rect(colour = "black")
)
g_top <- g +
labs(x = element_blank()) +
theme(
axis.text.x = element_blank(),
axis.ticks.x = element_blank()
)
plot_grid(g_top, NULL, g_bottom + theme(panel.border = element_rect(colour = "black")),
align = "hv",
nrow = 3,
rel_heights = c(1, -0.2, 1))

How to put plots without any space using plot_grid?

I'm doing an arrangement of 2x2 plots. The plots share the same axis, so I want to put them together, e.g.
This code:
library(ggplot2)
library(cowplot)
Value <- seq(0,1000, by = 1000/10)
Index <- 0:10
DF <- data.frame(Index, Value)
plot <- ggplot(DF, aes(x = Index, y = Value)) +
geom_line(linetype = 2) +
theme(aspect.ratio = 0.5)
plot_grid(plot, plot, plot, plot, align = "hv", ncol = 2)
produces
But I'd like something like:
How can I achieve a similar result?
I think this is a case for the ggarrange() function from the egg package. Doing this with plot_grid() would require endless fiddling and isn't worth it.
(The technical reason is that plot_grid() keeps the total area for each plot in the grid constant, but if some plots have an x axis and others don’t then they take up different areas. One could try to circumvent this by using the rel_heights argument but there’s no good way to calculate the correct values for rel_heights, so it would be trial and error. By contrast, ggarrange() separately looks at the plot panel and the surrounding elements and makes sure the plot panels have the same size.)
Here is the code using ggarrange():
Value <- seq(0,1000, by = 1000/10)
Index <- 0:10
DF <- data.frame(Index, Value)
pbase <- ggplot(DF, aes(x = Index, y = Value)) +
geom_line(linetype = 2) +
theme_bw()
ptopleft <- pbase +
scale_x_continuous(position = "top") +
theme(plot.margin = margin(5.5, 0, 0, 5.5),
axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank())
ptopright <- pbase +
scale_y_continuous(position = "right") +
scale_x_continuous(position = "top") +
theme(plot.margin = margin(5.5, 5.5, 0, 0),
axis.title.x = element_blank(),
axis.text.x = element_blank(),
axis.ticks.x = element_blank())
pbottomleft <- pbase +
theme(plot.margin = margin(0, 0, 5.5, 5.5))
pbottomright <- pbase +
scale_y_continuous(position = "right") +
theme(plot.margin = margin(0, 5.5, 5.5, 0))
library(egg)
ggarrange(ptopleft, ptopright,
pbottomleft, pbottomright,
ncol = 2)
Two comments:
To remove every last bit of space below the plot panel on the top plots, we need to move the x axis to the top, even though we're not showing it. This is a strange limitation of the theming mechanism. We can't fully get rid of just one axis.
I'm not a big fan of shared axis titles, as in your example. I think each axis should have a title. If you want shared axis titles, why not use the faceting mechanism?
You can set subtle plot.margin each plot, then grid.arrange and add labs.
library(ggplot2)
library(grid)
library(gridExtra)
Value <- seq(0,1000, by = 1000/10)
Index <- 0:10
DF <- data.frame(Index, Value)
plot1 <- ggplot(DF, aes(x = Index, y = Value)) +
geom_line(linetype = 2) +
theme_minimal() +
theme(aspect.ratio = 0.5,
panel.border = element_rect(fill = NA),
axis.text.x = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank(),
plot.margin = unit(c(5.5, 5.8, -50, 5.5), "pt"))
plot2 <- ggplot(DF, aes(x = Index, y = Value)) +
geom_line(linetype = 2) +
theme_minimal() +
theme(aspect.ratio = 0.5,
panel.border = element_rect(fill = NA),
axis.text.x = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank(),
plot.margin = unit(c(5.5, 5.5, -50, 5.5), "pt")) +
scale_y_continuous(position = "right")
plot3 <- ggplot(DF, aes(x = Index, y = Value)) +
geom_line(linetype = 2) +
theme_minimal() +
theme(aspect.ratio = 0.5,
panel.border = element_rect(fill = NA),
axis.title = element_blank(),
axis.ticks = element_blank(),
plot.margin = unit(c(-50, 5.8, -50, 5.5), "pt"))
plot4 <- ggplot(DF, aes(x = Index, y = Value)) +
geom_line(linetype = 2) +
theme_minimal() +
theme(aspect.ratio = 0.5,
panel.border = element_rect(fill = NA),
axis.title = element_blank(),
axis.ticks = element_blank(),
plot.margin = unit(c(-50, 5.5, -50, 5.5), "pt")) +
scale_y_continuous(position = "right")
grid.arrange(grobs = list(plot1, plot2, plot3, plot4), ncol = 2, bottom = 'Index', left = 'Value', right = 'Value')
final plot

Can you get the axis of the marginal densities to line up with the axis of the scatter plot

Hi I have the plot below and the marginal density plots are slightly off. They do not line up to the x and y axis of the scatter plot so interpretation can be a bit misleading.
I can sort of play with these lines of code to try and get the margins to align for rthe marginal plots but it is very manual and frustrating.
theme0(plot.margin = unit(c(1,0,0,2.2),"lines"))
theme0(plot.margin = unit(c(0,1,1.2,0),"lines"))
Is there a way to automatically find the right margins to pass to theme0(plot.margin = unit(c(0,1,1.2,0),"lines") so that no manual work needs to be done to line up the margins? Thank you.
library(ggplot2)
library(gridExtra)
set.seed(42)
DF <- data.frame(x=rnorm(100,mean=c(1,5)),y=rlnorm(100,meanlog=c(8,6)),group=1:2)
DF
## Scatter plot
p1 <- ggplot(DF,aes(x=x,y=y)) + geom_point() +
scale_x_continuous(expand=c(0.02,0)) +
scale_y_continuous(expand=c(0.02,0)) +
theme_bw() +
theme(legend.position="none",plot.margin=unit(c(0,0,0,0),"points")) # ggplot(DF,aes(x=x,y=y,colour=factor(group))) color the gorup
theme0 <- function(...) theme( legend.position = "none",
panel.background = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.margin = unit(0,"null"),
axis.ticks = element_blank(),
axis.text.x = element_blank(),
axis.text.y = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.ticks.length = unit(0,"null"),
axis.ticks.margin = unit(0,"null"),
panel.border=element_rect(color=NA),...)
### DENSITY OF X
p2 <- ggplot(DF,aes(x=x, fill="blue")) +
geom_density(alpha=0.5) +
scale_x_continuous(breaks=NULL,expand=c(0.02,0)) +
scale_y_continuous(breaks=NULL,expand=c(0.02,0)) +
theme_bw() +
theme0(plot.margin = unit(c(1,0,0,2.2),"lines")) # to color group ggplot(DF,aes(x=x,colour=factor(group),fill=factor(group)))
### DENSITY OF Y
p3 <- ggplot(DF,aes(x=y, fill = "red")) +
geom_density(alpha=0.5) +
coord_flip() +
scale_x_continuous(labels = NULL,breaks=NULL,expand=c(0.02,0)) +
scale_y_continuous(labels = NULL,breaks=NULL,expand=c(0.02,0)) +
theme_bw() +
theme0(plot.margin = unit(c(0,1,1.2,0),"lines")) # color group ggplot(DF,aes(x=y,colour=factor(group),fill=factor(group)))
grid.arrange(arrangeGrob(p2,ncol=2,widths=c(3,1)),
arrangeGrob(p1,p3,ncol=2,widths=c(3,1)),
heights=c(1,3))

drawing a box around a raster key

I'm plotting a species prediction map in ggplot using a spatial pixels data frame. I have the plot pretty much how I want it, the only problem is that my raster scale goes from white to red and so it's hard to see where it begins in the legend see the plot. I want to draw a box to outline to the legend key- just the bar going from white to red not the rest of it. I've being searching for over an hour but I can't find any way to do this, only ways to give the legend a background or draw a box around the legend text and bar, which I don't want to do. Does anyone know if this is possible to do in ggplot or do I need to change my colour gradient?
Thanks!
My plotting code:
ggplot() +
geom_raster(data=habs_pop_clip1, aes(x = easting.x, y = northing.x, fill = pred)) +
scale_fill_gradient("Probability of occurrence", low="white", high="red",limits = c(0,1)) +
coord_fixed(ratio=1, xlim=c(545000, 654000), ylim=c(278000,347000))+
geom_polygon(data=Norfolk1, aes(x=long, y=lat, Group=group), color="grey",fill=NA)+
theme(text = element_text(family = "serif")) +
geom_segment(aes(x = 550000, y = 278500, xend = 560000, yend = 278500), lineend = "round") +
annotate("text", x = 555000, xend = 555000, y = 282000, yend = 282000, label = "10 km", family = "serif", size = 4) +
ggtitle(colnames(bat_occ[i+7])) +
theme(plot.margin=unit(c(0.5, 0.5, 0.5, 0.5), "cm")) +
theme_bw() +
theme(axis.line = element_line(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
axis.line=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
axis.text =element_blank())
I don't know if there's a built-in parameter. If not, you could add a rectangle manually,
df <- reshape2::melt(outer(1:4, 1:4), varnames = c("X1", "X2"))
p <- ggplot(df, aes(X1, X2)) + geom_tile(aes(fill = value))+ scale_fill_continuous(guide = "colorbar")
g <- ggplotGrob(p)
g$grobs[[8]][[1]][[1]] <- gtable::gtable_add_grob(g$grobs[[8]][[1]][[1]],
rectGrob(gp=gpar(fill=NA, lwd=5)), 4, 2)
grid.newpage()
grid.draw(g)

ggplot2 & facet_wrap - eliminate vertical distance between facets

I'm working with some data that I want to display as a nxn grid of plots. Edit: To be more clear, there's 21 categories in my data. I want to facet by category, and have those 21 plots in a 5 x 5 square grid (where the orphan is by itself on the fifth row). Thus facet_wrap instead of facet_grid.
I've got the following code written up for doing it (using the good old iris data set for my reproducible example):
library(ggplot2)
library(grid)
cust_theme <- theme_bw() + theme(legend.position="none",
axis.title = element_blank(), axis.ticks = element_blank(),
axis.text = element_blank(), strip.text = element_blank(),
strip.background = element_blank(), panel.margin = unit(0, "lines"),
panel.border = element_rect(size = 0.25, color = "black"),
panel.grid = element_blank())
iris.plot <- ggplot(data = iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
geom_point() + cust_theme + facet_wrap( ~ Species, ncol = 2) +
labs(title = "Irises by species")
This gives me ALMOST what I want, but not quite:
I've still got a tiny strip of space between the top row of plots and the bottom row. I'd like to get rid of that entirely, but panel.margin is obviously not doing it. Is there a way to do this?
This might be a little late, but panel.marginis now deprecated. Inside theme use panel.spacing. To eliminate the spacing between the facets then load the grid package and use panel.spacing = unit(0, "lines")
Change the panel.margin argument to panel.margin = unit(c(-0.5,0-0.5,0), "lines"). For some reason the top and bottom margins need to be negative to line up perfectly. Here is the result:
You can also edit the grobs directly:
library(ggplot2)
library(grid)
g <- ggplot(data = iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
geom_point() +
facet_wrap( ~ Species, ncol = 2) +
labs(title = "Irises by species") +
theme_bw() +
theme(panel.margin = unit(0, "lines")) +
theme(plot.margin = unit(c(0,0,0,0), "lines")) +
theme(strip.background = element_blank()) +
theme(plot.background = element_blank()) +
theme(strip.text = element_blank()) +
theme(axis.ticks.margin = unit(0, "lines"))
g <- ggplotGrob(p)
g$heights[[7]] = unit(0, "lines")
grid.newpage()
grid.draw(g)

Resources