4

I hope I am missing something painfully obvious here.

I wish to update (e.g., fix title, labs, etc.) on a ggplot object produced from gratia::draw(). Not really sure why I am unable to update the object.

Is there a simple solution?

# devtools::install_github('gavinsimpson/gratia')
library('mgcv')
library('gratia')
dat <- gamSim(1, n = 400, dist = "normal", scale = 2, verbose = FALSE)
mod <- gam(y ~ s(x0),  data = dat, method = "REML")
draw(mod)

p = draw(mod)

# P is a ggobject.
class(p)
#> [1] "gg"     "ggplot"

So, why can't I update p?

p + ggtitle("My title")

Created on 2019-02-26 by the reprex package (v0.2.1)

Marco Sandri
  • 23,289
  • 7
  • 54
  • 58
Jessica Burnett
  • 395
  • 1
  • 13

2 Answers2

6

The object returned by draw.gam is the output of cowplot::plot_grid (not a pure ggplot2 graphical object).
I made a small change into draw.gam function of gratia.
. Now the p object can be manipulated:

# The modified draw.gam function
mydraw.gam <- function (object, parametric = TRUE, select = NULL, scales = c("free", 
    "fixed"), align = "hv", axis = "lrtb", n = 100, unconditional = FALSE, 
    overall_uncertainty = TRUE, dist = 0.1, ...) 
{
    scales <- match.arg(scales)
    S <- smooths(object)
    select <- gratia:::check_user_select_smooths(smooths = S, select = select)
    d <- gratia:::smooth_dim(object)
    take <- d <= 2L
    select <- select[take]
    S <- S[take]
    d <- d[take]
    is_re <- vapply(object[["smooth"]], gratia:::is_re_smooth, logical(1L))
    is_by <- vapply(object[["smooth"]], gratia:::is_by_smooth, logical(1L))
    if (any(is_by)) {
        S <- vapply(strsplit(S, ":"), `[[`, character(1L), 1L)
    }
    npara <- 0
    nsmooth <- length(S)
    if (isTRUE(parametric)) {
        terms <- parametric_terms(object)
        npara <- length(terms)
        p <- vector("list", length = npara)
    }
    g <- l <- vector("list", length = nsmooth)
    for (i in unique(S)) {
        eS <- evaluate_smooth(object, smooth = i, n = n, unconditional = unconditional, 
            overall_uncertainty = overall_uncertainty, dist = dist)
        l[S == i] <- split(eS, eS[["smooth"]])
    }
    l <- l[select]
    d <- d[select]
    g <- g[select]
    if (length(g) == 0L) {
        message("Unable to draw any of the model terms.")
        return(invisible(g))
    }
    for (i in seq_along(l)) {
        g[[i]] <- draw(l[[i]])
    }
    if (isTRUE(parametric)) {
        for (i in seq_along(terms)) {
            p[[i]] <- evaluate_parametric_term(object, term = terms[i])
            g[[i + length(g)]] <- draw(p[[i]])
        }
    }
    if (isTRUE(identical(scales, "fixed"))) {
        wrapper <- function(x) {
            range(x[["est"]] + (2 * x[["se"]]), x[["est"]] - 
                (2 * x[["se"]]))
        }
        ylims <- range(unlist(lapply(l, wrapper)))
        if (isTRUE(parametric)) {
            ylims <- range(ylims, unlist(lapply(p, function(x) range(x[["upper"]], 
                x[["lower"]]))))
        }
        gg <- seq_along(g)[c(d == 1L, rep(TRUE, npara))]
        for (i in gg) {
            g[[i]] <- g[[i]] + lims(y = ylims)
        }
    }
    g
}

# Example no. 1
dat <- gamSim(1, n = 400, dist = "normal", scale = 2, verbose = FALSE)
mod <- gam(y ~ s(x0),  data = dat, method = "REML")
p <- mydraw.gam(mod)
p[[1]] + ggtitle("My title")

enter image description here

# Example no. 2
mod <- gam(y ~ s(x0) + x1, data = dat, method = "REML")
p <- mydraw.gam(mod)
# Plot graphs separately
p[[1]] + ggtitle("My title")
p[[2]] + ggtitle("My title")
# Arrange the two plots on the same figure
cowplot::plot_grid(plotlist = p)
Marco Sandri
  • 23,289
  • 7
  • 54
  • 58
  • **You rock.** Forever grateful. I presume you will do PR on github? I don't suppose you can suggest an edit for plotting the [derivatives](https://github.com/gavinsimpson/gratia/blob/master/R/derivatives.R)? – Jessica Burnett Feb 26 '19 at 19:00
  • This does not work, however, when a fixed effect is added. E.g.: `mod <- gam(y ~ s(x0) +x1, data = dat, method = "REML")` – Jessica Burnett Feb 26 '19 at 19:09
  • @JessicaBurnett Hi. I edited my answer. Please, let me know. If you find helpful, please accept and upvote my answer ! Thank you. – Marco Sandri Feb 26 '19 at 20:33
0

Reposts from Gavin Simpson and Hao Ye, respectively:

  1. I think the only way to change the title(s) on the individual plots of smooths would be to use draw(evaluate_smooth(model, "smooth"), title = "My title") individually at the moment.

  2. You might be able to hack a title in a different way: draw(mod) + ggplot2::coord_cartesian(clip = "off") + ggplot2::theme(plot.margin = ggplot2::unit(c(0.05, 0, 0, 0), "npc")) + ggplot2::annotate("text", x = 0.5, y = 1, vjust = 0, label = "TITLE", size = 6)

Jessica Burnett
  • 395
  • 1
  • 13