Curious behaviour using gridExtra (ggplot) - r

I am trying to stack three plots on top of each other using the gridExtra package. I have tried the the first example that uses grid.arrange from here, which works absolutely fine.
However, when I try to use my own plots, I get axes for each plot but no data, with all the formatting stripped out. Minimum working example:
library(ggplot2)
library(gridExtra)
popu_H0 <- seq(10, 30, length=100)
popu_H0_norm <- dnorm(popu_H0, mean = 20, sd = 4)
popu_H0_df <- as.data.frame(cbind(popu_H0, popu_H0_norm))
plot_H0 <- ggplot(popu_H0_df, aes(x=popu_H0, y=popu_H0_norm))
plot_H0 +
geom_line() +
theme(
text = element_text(size=20),
axis.title.x = element_text(vjust=0.1),
axis.text.x = element_text(size = rel(1.8)),
legend.position = "none",
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.line.y = element_blank()
) +
xlab("New label") +
annotate("text", x = 20, y = 0.05, label = "Some annotation", size = 10)
grid.arrange(plot_H0, plot_H0, plot_H0, ncol = 1, nrow = 3)
ggplot produces the expected output, but grid.arrange produces this.

You forgot to replace the plot object.
library(ggplot2)
library(gridExtra)
popu_H0 <- seq(10, 30, length=100)
popu_H0_norm <- dnorm(popu_H0, mean = 20, sd = 4)
popu_H0_df <- as.data.frame(cbind(popu_H0, popu_H0_norm))
plot_H0 <- ggplot(popu_H0_df, aes(x=popu_H0, y=popu_H0_norm))
plot_H0 <- plot_H0 + # Here you need `<-` to update the plot
geom_line() +
theme(
text = element_text(size=20),
axis.title.x = element_text(vjust=0.1),
axis.text.x = element_text(size = rel(1.8)),
legend.position = "none",
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.line.y = element_blank()
) +
xlab("New label") +
annotate("text", x = 20, y = 0.05, label = "Some annotation", size = 10)
grid.arrange(plot_H0, plot_H0, plot_H0, ncol = 1, nrow = 3)

Related

ggplot2: using square brackets and superscript in axis title

I have a plot where each axis has been log10 transformed. For one of my axis titles I would like to use both a square bracket ([]) and a superscript. How can I do this?
Example Data
library(dplyr)
library(ggplot2)
set.seed(123)
df <- data.frame(matrix(ncol = 2, nrow = 20))
colnames(df)[1:2] <- c('x','y')
df$x <- rnorm(20,1000,100)
df$y <- rnorm(20,1000,100)
df <- df %>%
mutate(log_x = log10(x),
log_y = log10(y))
Here is an example of the figure I am trying to make. I need to know how to make the -2 on the x-axis superscripted.
df %>%
ggplot(aes(x = log_x, y = log_y)) +
geom_point() +
labs(x = expression(log[10]~"[Area (m^-2)]"),
y = expression(log[10]~"[ Time Variable (months)]")) +
theme_bw() +
theme(axis.text.x = element_text(size = 16, color = "black"),
axis.text.y = element_text(size = 16, color = "black"),
axis.title = element_text(size = 16, color = "black"),
panel.grid = element_blank(),
panel.background = element_blank())
#MrFlick response provides the correct answer, see below.
df %>%
ggplot(aes(x = log_x, y = log_y)) +
geom_point() +
labs(x = expression(log[10]~"[Area"~ (m^-2) ~"]"),
y = expression(log[10]~"[ Time Variable (months)]")) +
theme_bw() +
theme(axis.text.x = element_text(size = 16, color = "black"),
axis.text.y = element_text(size = 16, color = "black"),
axis.title = element_text(size = 16, color = "black"),
panel.grid = element_blank(),
panel.background = element_blank())

Annotate ggplot2 across multiple facets

I have recently started using the facet_nested function from the ggh4x package and I really like the look of the nested axis. I would like to annotate the plot to show stats that I have run. I have created a dummy dataset to illustrate my problem.
library(tidyverse)
library(markdown)
library(ggtext)
library(ggh4x)
df <- data.frame(pretreatment = c("10NA", "10NA","10NA", "NT", "NT", "NT"),
timepoint = c("0 h", "6 h","6 h", "0 h", "6 h", "6 h"),
treatment = c("baseline", "10NA", "NT","baseline", "10NA", "NT"),
mean_copy_no = c(1000, 1500, 1200, 600, 700, 400),
sample_id = c(1, 2, 3, 4, 5, 6))
df %>%
ggplot(aes(x=sample_id, y = mean_copy_no, fill = treatment)) +
geom_col(colour = "black") +
facet_nested(.~ pretreatment + timepoint + treatment, scales = "free", nest_line = TRUE, switch = "x") +
ylim(0,2000) +
theme_bw() +
theme(strip.text.x = element_text(size = unit(10, "pt")),
legend.position = "none",
axis.title.y = element_markdown(size = unit(13, "pt")),
axis.text.y = element_text(size = 11),
axis.text.x = element_blank(),
axis.title.x = element_blank(),
axis.ticks.x = element_blank(),
strip.text = element_markdown(size = unit(12, "pt")),
strip.background = element_blank(),
panel.spacing.x = unit(0.05,"line"),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
panel.border = element_blank())
This generates the following plot.
Now my problem is that each of the bars is located within its own facet and not all on one x axis (if you run the code without the theme, it shows it more clearly).
I have drawn how I would like the plot to look.
I would like to add lines and stars to indicate significant differences.
I can easilly add the stars, however I am struggling to add the lines and I understand that this may not even be possible because I am using facets to generate the plot. I just wanted to post the question and see if someone has any suggestion on how to do it in R. Or if there is a way to achieve the nested look without using facets.
*Edited for clarity.
One option is to use cowplot after making the ggplot object, where we can add the lines and text.
library(ggplot2)
library(cowplot)
results <- df %>%
ggplot(aes(x=sample_id, y = mean_copy_no, fill = treatment)) +
geom_col(colour = "black") +
facet_nested(.~ pretreatment + timepoint + treatment, scales = "free", nest_line = TRUE, switch = "x") +
ylim(0,2000) +
theme_bw() +
theme(strip.text.x = element_text(size = unit(10, "pt")),
legend.position = "none",
axis.title.y = element_markdown(size = unit(13, "pt")),
axis.text.y = element_text(size = 11),
axis.text.x = element_blank(),
axis.title.x = element_blank(),
axis.ticks.x = element_blank(),
strip.text = element_markdown(size = unit(12, "pt")),
strip.background = element_blank(),
panel.spacing.x = unit(0.05,"line"),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
panel.border = element_blank())
ggdraw(results) +
draw_line(
x = c(0.07, 0.36),
y = c(0.84, 0.84),
color = "black", size = 1
) +
annotate("text", x = 0.215, y = 0.85, label = "*", size = 15) +
draw_line(
x = c(0.7, 0.98),
y = c(0.55, 0.55),
color = "black", size = 1
) +
annotate("text", x = 0.84, y = 0.56, label = "**", size = 15)
Output

How to increase space among different boxes created for the facet labels using `facet_nested`?

I have a plot like this below:
library(ggplot2)
library(ggh4x) # remotes::install_github("teunbrand/ggh4x")
df1 <- data.frame(x = rep(1:12, times=4, each=1),
y = rep((1:12)^2, times=4, each=1),
Variable1 = rep(c("A","B"), times=1, each=24),
Variable2 = rep(c("C","D"), times=4, each=12))
g<-ggplot(df1, aes(x=x, y=y)) +
geom_point(size=1.5) +
theme(strip.background = element_rect(colour = "black", fill = "white",
size = 1.5, linetype = "solid"),
axis.title.x =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
axis.title.y =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
axis.text.x = element_text(angle = 0, hjust = 0.5,size = 14),
axis.text.y = element_text(angle = 0, hjust = 0.5,size = 14),
strip.text.x = element_text(size = 14),
strip.text.y = element_text(size = 13),
axis.line = element_line(),
panel.grid.major= element_blank(),
panel.grid.minor = element_blank(),
legend.text=element_text(size=15),
legend.title = element_text(size=15,face="bold"),
legend.key=element_blank(),
legend.position = "right",
panel.border = element_blank(),
strip.placement = "outside",
strip.switch.pad.grid = unit('0.25', "cm")) +
facet_nested( .~Variable1 + Variable2)
g
How could I increase the space among different boxes for the different facet labels? So for example, I want to increase the space between A and C/D. In this post is explained how to change the distance between the plot edge and the facet labels (using strip.switch.pad.grid in theme), but it doesn't work for separating facet boxes among them.
Does anyone know how to do it?
ggplot2 and ggh4x don't have options to place the facet strips apart. However, that doesn't mean it can't be done: it just means that the solution is a bit uglier than you'd like. Because you'd have to dive into the gtable/grid structures underneath ggplot.
For completeness; this gives identical output to your code.
library(ggplot2)
library(ggh4x)
library(grid)
df1 <- data.frame(x = rep(1:12, times=4, each=1),
y = rep((1:12)^2, times=4, each=1),
Variable1 = rep(c("A","B"), times=1, each=24),
Variable2 = rep(c("C","D"), times=4, each=12))
g<-ggplot(df1, aes(x=x, y=y)) +
geom_point(size=1.5) +
theme(strip.background = element_rect(colour = "black", fill = "white",
size = 1.5, linetype = "solid"),
axis.title.x =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
axis.title.y =element_text(margin = margin(t = 2, r = 20, b = 0, l = 0),size = 16),
axis.text.x = element_text(angle = 0, hjust = 0.5,size = 14),
axis.text.y = element_text(angle = 0, hjust = 0.5,size = 14),
strip.text.x = element_text(size = 14),
strip.text.y = element_text(size = 13),
axis.line = element_line(),
panel.grid.major= element_blank(),
panel.grid.minor = element_blank(),
legend.text=element_text(size=15),
legend.title = element_text(size=15,face="bold"),
legend.key=element_blank(),
legend.position = "right",
panel.border = element_blank(),
strip.placement = "outside",
strip.switch.pad.grid = unit('0.25', "cm")) +
facet_nested( .~Variable1 + Variable2)
Then here is the extra steps that you'd have to take for your plot, or any plot where the strip layout is horizontal without vertical strips. This should work for regular facet_grid() too.
# How much to push the boxes apart
space <- unit(0.5, "cm")
# Convert to gtable
gt <- ggplotGrob(g)
# Find strip in gtable
is_strip <- which(grepl("strip", gt$layout$name))
strip_row <- unique(gt$layout$t[is_strip])
# Change cell height
gt$heights[strip_row] <- gt$heights[strip_row] + space
# Add space to strips themselves
gt$grobs[is_strip] <- lapply(gt$grobs[is_strip], function(strip) {
gtable::gtable_add_row_space(strip, space)
})
# Render
grid.newpage(); grid.draw(gt)
Created on 2020-05-26 by the reprex package (v0.3.0)
Note that this example is on R4.0.0. The grid::unit() arithmetic behaviour might be slightly different in previous R versions.
As an aside, if you just want to add padding to the text, it is easier to just wrap newlines around the text:
df1$Variable1 <- factor(df1$Variable1)
levels(df1$Variable1) <- paste0("\n", levels(df1$Variable1), "\n")
EDIT: It might just be easiest to use ggtext textbox elements:
library(ggtext) # remotes::install_github("wilkelab/ggtext")
g + theme(
strip.background = element_blank(),
strip.text = element_textbox_simple(
padding = margin(5, 0, 5, 0),
margin = margin(5, 0, 5, 0),
size = 13,
halign = 0.5,
fill = "white",
box.color = "black",
linewidth = 1.5,
linetype = "solid",
)
)
g

Change histogram bar percentage label in R ggplot

I have made a histogram in R using the following code:
(I have tried generating a reprex. Try the code reprex here
progressiveNumber = c(1:50)
c = c(-0.22037439, -0.21536365, -0.34203720, 0.04501624, -0.13141665, -1.28155157, -0.08394700, -0.08484768, -0.12577287, 0.30402612, -0.40578251,
0.00000000, -0.16849942, -0.04212114, 0.12577287, 0.57366312, -0.84766743, -1.03909659, -0.21536365, -0.46263648, -0.48181028, -0.38887381,
-0.38571106, -0.38571106, -0.26220026, 0.73227348, -0.38887381, -0.96590662, -0.29931065, 0.04272655, 0.04182587, -0.38571106, -0.13141665,
-0.34614726, -0.49063020, -0.08484768, 0.05249378, 0.08484768, -0.74591104, 0.46263648, -0.42081062, 0.00000000, 0.08394700, -0.38571106,
-0.34203720, -0.04212114, -0.79517364, 0.25429442, -0.30402612, -0.08365173)
library(tidyverse)
# DEFINING BREAKS AND CUT A VECTOR INTO BINS
# set up cut-off values
breaks <- c(-1.2816,-0.3881,-0.2154, 0.0000, 0.3 ,0.7323)
# specify interval/bin labels
tags <- c("[-1.2 / -0.3]","[-0.3 / -0.2]", "[-0.2 / 0]", "[0 / 0.3]","[0.3 / 0.7]")
# bucketing values into bins
group_tags <- cut(c,
breaks=breaks,
include.lowest=TRUE,
right=FALSE,
labels=tags)
# inspect bins
summary(group_tags)
# c_groups <- factor(group_tags,levels = labels, ordered = TRUE) # this line doesn't work for some reason
#tiff("percentageBinsC.tiff", units="in", width=5, height=5, res=300,)
p2 = ggplot(data = as_tibble(group_tags), mapping = aes(x=value)) +
geom_bar(fill="deepskyblue1",color="white",alpha=0.7, ) +
stat_count(geom="text", aes(label=sprintf("%.2f",..count../length(group_tags))), vjust=-0.5) +
labs(y = 'Count', x='C') +
theme(text = element_text(size=20), axis.line.x = element_line(color = "black", size = 1),
axis.line.y = element_line(color = "black", size = 1), axis.text.x = element_text(angle = 35, hjust = 1, vjust = 1),
panel.background = element_blank(), panel.border = element_blank(),
panel.grid.minor = element_blank(),panel.grid.major = element_blank())
p2
#dev.off()
Result
I would like to change the label on the bars (not the x-axis label but the ones that are right on top of each bar) from, e.g., 0.26 to 26%, 22% and so on.
How can I do that?
You can use percent_format from scales, first we define a function to do the conversion, and the rounding up you did with sprintf:
convert2perc = scales::percent_format(accuracy = 2)
You can test it:
convert2perc(0.107)
[1] "10%"
Then use it in the plotting:
p2 = ggplot(data = as_tibble(group_tags), mapping = aes(x=value)) +
geom_bar(fill="deepskyblue1",color="white",alpha=0.7, ) +
stat_count(geom="text", aes(label=convert2perc(..count../length(group_tags))), vjust=-0.5) +
labs(y = 'Count', x='C') +
theme(text = element_text(size=20), axis.line.x = element_line(color = "black", size = 1),
axis.line.y = element_line(color = "black", size = 1), axis.text.x = element_text(angle = 35, hjust = 1, vjust = 1),
panel.background = element_blank(), panel.border = element_blank(),
panel.grid.minor = element_blank(),panel.grid.major = element_blank())

stat_fit_glance and generalized additive models (GAM) error

I am trying to add the p-value and R2 from mgcv::gam results to ggplot with facets. The sample dataframe and code are below. Is there a way to successfully paste the p-value and R2 on the ggplots?
DF <- data.frame(Site = rep(LETTERS[20:24], each = 4),
Region = rep(LETTERS[14:18], each = 4),
time = rep(LETTERS[1:10], each = 10),
group = rep(LETTERS[1:4], each = 10),
value1 = runif(n = 1000, min = 10, max = 15),
value2 = runif(n = 1000, min = 100, max = 150))
DF$time <- as.numeric(DF$time)
GAMFORMULA <- y ~ s(x,bs="cr",k=3)
plot1 <- ggplot(data=DF,
aes(x=time, y=value2)) +
geom_point(col="gray", alpha=0.8,
name="") +
geom_line(col="gray", alpha=0.8,
name="",aes(group=group)) +
geom_smooth(se=T, col="darkorange", alpha=0.8,
name="", fill="orange",
method="gam",formula=GAMFORMULA) +
theme_bw() +
theme(strip.text.x = element_text(size=10),
strip.text.y = element_text(size=10, face="bold", angle=0),
strip.background = element_rect(colour="black", fill="gray90"),
axis.text.x = element_text(size=10), # remove x-axis text
axis.text.y = element_text(size=10), # remove y-axis text
axis.ticks = element_blank(), # remove axis ticks
axis.title.x = element_text(size=18), # remove x-axis labels
axis.title.y = element_text(size=25), # remove y-axis labels
panel.background = element_blank(),
panel.grid.major = element_blank(), #remove major-grid labels
panel.grid.minor = element_blank(), #remove minor-grid labels
plot.background = element_blank()) +
labs(y="Value", x="Time", title = "") +
stat_fit_glance(method = "gam",
method.args = list(formula = GAMFORMULA),
aes(label = sprintf('R^2~"="~%.3f~~italic(p)~"="~%.2f',
stat(..r.squared..),stat(..p.value..))),
parse = TRUE)
plot1 + facet_wrap(Site~group, scales="free_y", ncol=3)
Error in sprintf("R^2~\"=\"~%.3f~~italic(p)~\"=\"~%.2f", r.squared, p.value) :
object 'r.squared' not found
My answer explains why stat_fit_glance() cannot be used to add r.sq to a plot, but I am afraid is does not provide an alternative approach.
stat_fit_glance() is a wrapper on broom:glance() that fits the model and passes the model fit object to broom:glance(). In the case of gam(), broom:glance() does not return an estimate for R2 and consequently also stat_fit_glance() is unable to return it.
To see what computed values are available one can use geom_debug() from package 'gginnards'.
library(ggpmisc)
library(gginnards)
library(mgcv)
DF <- data.frame(Site = rep(LETTERS[20:24], each = 4),
Region = rep(LETTERS[14:18], each = 4),
time = rep(LETTERS[1:10], each = 10),
group = rep(LETTERS[1:4], each = 10),
value1 = runif(n = 1000, min = 10, max = 15),
value2 = runif(n = 1000, min = 100, max = 150))
DF$time <- as.numeric(DF$time)
GAMFORMULA <- y ~ s(x,bs="cr",k=3)
plot1 <- ggplot(data=DF,
aes(x=time, y=value2)) +
geom_point(col="gray", alpha=0.8,
name="") +
geom_line(col="gray", alpha=0.8,
name="",aes(group=group)) +
geom_smooth(se=T, col="darkorange", alpha=0.8,
name="", fill="orange",
method="gam",formula=GAMFORMULA) +
theme_bw() +
theme(strip.text.x = element_text(size=10),
strip.text.y = element_text(size=10, face="bold", angle=0),
strip.background = element_rect(colour="black", fill="gray90"),
axis.text.x = element_text(size=10), # remove x-axis text
axis.text.y = element_text(size=10), # remove y-axis text
axis.ticks = element_blank(), # remove axis ticks
axis.title.x = element_text(size=18), # remove x-axis labels
axis.title.y = element_text(size=25), # remove y-axis labels
panel.background = element_blank(),
panel.grid.major = element_blank(), #remove major-grid labels
panel.grid.minor = element_blank(), #remove minor-grid labels
plot.background = element_blank()) +
labs(y="Value", x="Time", title = "") +
stat_fit_glance(method = "gam",
method.args = list(formula = GAMFORMULA),
# aes(label = sprintf('R^2~"="~%.3f~~italic(p)~"="~%.2f',
# stat(..r.squared..),stat(..p.value..))),
# parse = TRUE)
geom = "debug")
plot1 + facet_wrap(Site~group, scales="free_y", ncol=3)
Shown above are the values returned by stat_fit_glance() for the first two panels in the plot.
Note: There does not seem to be agreement on whether R-square is meaningful for GAM. However the summary() method for gam does return an adjusted R-square estimate as member r.sq.

Resources