Vinicius Perin
Vinicius Perin

Reputation: 13

stack graphs with different temporal resolution in r

I am trying to stack three graphs using ggplot2 and grid arrange. All three graphs should have have the same x axis (but not sharing), the problem is that all of them are in a different temporal resolution and I am having a hard time to align the axis of the three different plots.

This is what I have:

stacked graphs

And I want something similar to this:

target format.

Dataset Soil temperature

                average
3/1/2018 11:00  9.353692972
3/1/2018 12:00  10.75947564
3/1/2018 13:00  11.56223312
3/1/2018 14:00  11.59511989
3/1/2018 15:00  11.07712308
3/1/2018 16:00  9.762939639
3/1/2018 17:00  7.650089417
3/1/2018 18:00  6.021789611
3/1/2018 19:00  4.844122056
3/1/2018 20:00  3.946675139
3/1/2018 21:00  3.265207733
3/1/2018 22:00  2.751823167
3/1/2018 23:00  2.307551222
3/2/2018 0:00   1.977323322
3/2/2018 1:00   1.714310775
3/2/2018 2:00   1.505199708
3/2/2018 3:00   1.402693267
3/2/2018 4:00   1.384921586
3/2/2018 5:00   1.350009046
....

Dataset ppt

3/1/2018    0
3/2/2018    0
3/3/2018    0
3/4/2018    0
3/5/2018    0
3/6/2018    0
3/7/2018    0
3/8/2018    0
3/9/2018    0
3/10/2018   0
3/11/2018   0
3/12/2018   0
3/13/2018   0
3/14/2018   0

Dataset flux

DPF     U       N
7.08    0.00    0.00
14      0.01    0.02
22      0.16    0.25
29.21   0.00    0.00
33.88   0.05    0.00
42.08   0.00    0.00

code

# define sheets
hourly <- read_excel("ashland2_graphs.xlsx", sheet = 'Hourly')
daily <- read_excel("ashland2_graphs.xlsx", sheet = 'Climate')
nh3flux <-read_excel('ashland2_graphs.xlsx', sheet = 'flux')


# define soil temp
soiltemp <- as.numeric(as.character(hourly$average))

# soil temperature graph
# define x axis
x = c(1:length(soiltemp))

fig1 <- ggplot()+
  geom_line(aes(x=x,y = soiltemp), stat = 'identity') +
  scale_x_continuous(breaks = seq(1, length(soiltemp), by = 240), 
                     label = c('0', '10', '20', '30', '40'))

# precipitation graph
ppt <- as.numeric(as.character(daily$ppt))

# precip x axis
x2 = c(1:length(ppt))

fig2 <- ggplot(climate) +
  geom_bar(aes(x = x2, y = ppt), stat = 'identity', color = "grey") +
  scale_y_continuous(expand = c(0, 0))

print(fig2)

# Losses
urea <- as.numeric(as.character(nh3flux$`NH3 Flux g/m2 day-1 - urea`))
nbpt <- as.numeric(as.character(nh3flux$`NH3 Flux g/m2 day-1 - nbpt`))
x3 <- nh3flux$`Days post fertilization`

fig3 <- ggplot(nh3flux) +
  geom_point(mapping = aes(x = x3, y = urea)) +
  geom_line(mapping = aes(x = x3, y = urea)) +
  geom_point(mapping = aes(x = x3, y = nbpt)) +
  geom_line(mapping = aes(x = x3, y = nbpt), linetype = 'dashed') +
  scale_x_continuous(breaks=seq(0, 45, 10), limits = c(0, 45))

print(fig3)

# stack graphs
grid.arrange(fig3, fig2, fig1, ncol = 1)

Upvotes: 1

Views: 200

Answers (1)

Mikko Marttila
Mikko Marttila

Reputation: 11898

Setup

For the sake of easy reproducibility, I'll use the mtcars dataset to demonstrate how to tackle this. First let's create our three plots:

library(ggplot2)

set.seed(123)
dfs <- split(mtcars, sample(3, nrow(mtcars), replace = TRUE))

# Three plots, with the same x variable but different y and geoms
p1 <- ggplot(dfs[[1]], aes(wt, mpg)) + geom_point()
p2 <- ggplot(dfs[[2]], aes(wt)) + geom_histogram()
p3 <- ggplot(dfs[[3]], aes(wt, cyl)) + geom_smooth()

plots <- list(p1, p2, p3) # easier to work with them all in a list

And here are the plots stacked, exhibiting the same problems that you have:

cowplot::plot_grid(plotlist = plots, ncol = 1)
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'

(I'm not using grid.arrange(), because it lacks some features that we need for a solution.)

Identifying issues

We can identify two problems that need to be taken care of:

  1. The x-axis limits need to be equal across the plots.
  2. The plot areas need to be aligned. (Varying y-axis label lengths cause the plot areas to vary in size.)

Solutions

The first problem can be addressed by creating a single coordinate object defining the x-axis limits that we want. With the plots in a list, it's easy to apply this coordinate system to each of them with lapply():

common_coord <- coord_cartesian(xlim = c(1.5, 5.5))
common_x_plots <- lapply(plots, `+`, common_coord)

For your data, setting the limits to c(0, 45) sould do quite nicely.

The second problem is trickier, and I don't think gridExtra::grid.arrange() can solve it without quite a bit of extra work. That's why I would recommend using plot_grid() from the cowplot package instead: it has an align option that we can use to line up the plot areas by adding some extra space between the axis title and axis labels where needed.

Result

With both problems adressed, here's the result:

cowplot::plot_grid(plotlist = common_x_plots, ncol = 1, align = "v")
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'

Following this approach, you should be able to achieve what you're looking for with your real data, too.

Created on 2018-08-24 by the reprex package (v0.2.0.9000).

Upvotes: 2

Related Questions