I run each of the below plots within the loop with no problem, but for some reason, when I try to combine them in grid.arrange the axes get scaled automatically. I can't figure out how to not automatically scale. I literally just want to combine the ggplots together (as if I used par(mfrow = c(2,3)) with base R).
I think the fact that the X axis is really a re-formatted datetime (as.posixct) is throwing it off. Ideally, I would like the X axis to display just the hour.
library(ggplot2)
library(bp)
df <- data(hypnos_data)
ids <- unique(df$ID)
id_tab <- cbind(ids, c(1:5))
index <- c(8:23, 0:7)
plot_list <- list()
for(i in ids){
subs <- df[which(df$ID == i & df$VISIT == 1),]
subs$DATE.TIME <- as.POSIXct(subs$DATE.TIME)
subs$hour_rec <- lubridate::hour(subs$DATE.TIME)
subs$hour_rec <- factor(subs$hour_rec, levels = as.character(index), ordered = T)
row.names(subs) <- NULL
tmp <- subs %>% dplyr::filter(WAKE == 0)
min(tmp$hour_rec)
p <- ggplot2::ggplot(subs, ggplot2::aes(x = DATE.TIME, y = SYST)) +
geom_rect(aes(xmin = min(tmp$DATE.TIME), xmax = max(tmp$DATE.TIME), ymin = -Inf, ymax = Inf),
fill = "navajowhite2", alpha = 0.03) +
ggplot2::geom_point(aes(y = SYST), col = 'blue') +
ggplot2::geom_smooth(aes(y = SYST), method = "loess", col = 'blue') +
ggplot2::geom_point(aes(y = DIAST), col = 'red') +
ggplot2::geom_smooth(aes(y = DIAST), method = "loess", col = 'red') +
scale_x_datetime(date_label = "%H:%M", date_breaks = "1 hour") +
theme(axis.text.x = element_text(angle=45)) +
ggtitle( paste("BP Profile for Subject: ", i, sep = "") )
plot_list[[match(i, id_tab)]] <- p
print(p)
#grid::grid.newpage()
}
The above code should produce 5 plots similar to this (which are correct):
individual plot output
gridExtra::grid.arrange(grobs = plot_list, ncol = 2 )
However, trying to combine them using grid.arrange yields the following:
grid.arrange plot output
The issue is not in the grid.arrange
It is due to the reference variable in ggplot2
. Some of the axis data is reference values instead of stored values inside the plot. This result in the change in axis when the subs
& tmp
change for each for-loop
interation. Here is a way to walk around it using eval(substitute(...))
library(ggplot2)
library(bp)
library(doParallel)
#> Loading required package: foreach
#> Loading required package: iterators
#> Loading required package: parallel
data(hypnos_data)
df <- hypnos_data
ids <- unique(df$ID)
id_tab <- cbind(ids, c(1:5))
index <- c(8:23, 0:7)
plot_list <- list()
plot_list <- foreach(i = ids) %do% {
eval(substitute({
subs <- df[which(df$ID == i & df$VISIT == 1),]
subs$DATE.TIME <- as.POSIXct(subs$DATE.TIME)
subs$hour_rec <- lubridate::hour(subs$DATE.TIME)
subs$hour_rec <- factor(subs$hour_rec, levels = as.character(index), ordered = T)
row.names(subs) <- NULL
tmp <- subs %>% dplyr::filter(WAKE == 0)
min(tmp$hour_rec)
p <- ggplot2::ggplot(subs, ggplot2::aes(x = DATE.TIME, y = SYST)) +
geom_rect(aes(xmin = min(tmp$DATE.TIME), xmax = max(tmp$DATE.TIME), ymin = -Inf, ymax = Inf),
fill = "navajowhite2", alpha = 0.03) +
ggplot2::geom_point(aes(y = SYST), col = 'blue') +
ggplot2::geom_smooth(aes(y = SYST), method = "loess", col = 'blue') +
ggplot2::geom_point(aes(y = DIAST), col = 'red') +
ggplot2::geom_smooth(aes(y = DIAST), method = "loess", col = 'red') +
scale_x_datetime(date_label = "%H:%M", date_breaks = "1 hour") +
theme(axis.text.x = element_text(angle=45)) +
ggtitle( paste("BP Profile for Subject: ", i, sep = "") )
}, list(subs = as.name(paste0("subs_", i)), tmp = as.name(paste0("tmp_", i)))))
p
}
gridExtra::grid.arrange(grobs = plot_list)
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
#> `geom_smooth()` using formula 'y ~ x'
Created on 2021-03-31 by the reprex package (v1.0.0)