---
title: "Frequently asked questions"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Frequently asked questions}
  %\VignetteEncoding{UTF-8}
  %\VignetteEngine{knitr::rmarkdown}
editor_options: 
  chunk_output_type: console
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
set.seed(2021)
library(ggtrace)
```

## Is ggtrace() safe?

`ggtrace()` is essentially just a wrapper around `base::trace()` designed to make it easy and safe to programmatically trace/untrace functions and methods.

So the short answer is that `ggtrace()` is at least as safe as `trace()`. But how safe _is_ `trace()`?

The beauty of `trace()` is that the modified function being traced _masks_ over the original function without _overwriting_ it. This allows for **non-destructive modifications to the execution behavior**.

In this simple example, we add a trace to `replace()` which multiples the value of `x` by 10 as the function enters the last step.

```{r}
body(replace)

replace(1:5, 3, 30)

as.list(body(replace))

trace(replace, tracer = quote(x <- x * 10), at = 3)
```

The traced function looks strange and runs with a different behavior

```{r}
class(replace)

body(replace)

replace(1:5, 3, 30)
```

But again, this is non-destructive. The original function body is safely stored away in the `"original"` attribute of the traced function

```{r}
attr(replace, "original")
```

The original function can be recovered by removing the trace with a call to `untrace()`

```{r}
untrace(replace)

body(replace)

replace(1:5, 3, 30)
```

Beyond this, `{ggtrace}` also offers some extra built-in safety measures:

- Cleans up after itself by untracing on exit (the default behavior with `once = TRUE`)
- Always untraces before tracing, which prevents nested traces from being created
- Provides ample messages about whethere there is an existing trace (which you can also check with `is_traced()`)
- Exits as early as possible if the method expression is ill-formed with more informative error messages that you can actually act on
- Prevents traces from being created on functions that aren't bound to a variable in some way (i.e., prevents you from creating traces that you can't trigger)

However, some expression you pass to `ggtrace()` for delayed evaluation are not without consequences. You need to be careful about running functions that have _side effects_ and making _assignments to environments_ (ex: `self$method <- ...` will modify in place). But this isn't a problem of `{ggtrace}` - they follow from the general rules of reference semantics in R.


## What can you `ggtrace()`?

### Functions

{base} functions

```{r}
sample(letters, 5)
ggtrace(sample, 1, quote(x <- LETTERS), verbose = FALSE)
sample(letters, 5)
sample(letters, 5)
```

Imported functions

```{r}
ggtrace(ggplot2::mean_se, 1, quote(cat("Running...\n")), verbose = FALSE)
ggplot2::mean_se(mtcars$mpg)
```

Custom functions

```{r}
please_return_number <- function() {
  result <- runif(1)
  result
}
please_return_number()

ggtrace(please_return_number, -1, quote(result <- "no"), verbose = FALSE)
please_return_number()
```


### ggproto methods

```{r}
library(ggplot2)
boxplot_plot <- ggplot(mpg, aes(drv, hwy)) +
  geom_boxplot()

boxplot_plot
```

Default tracing behavior with untracing on exit

```{r, fig.show='hide'}
ggtrace(StatBoxplot$compute_group, -1, verbose = FALSE)

# Plot not printed to save space
boxplot_plot

last_ggtrace()
```

Persistent trace with `once = FALSE` and explicit untracing with `gguntrace()`

```{r fig.show='hide'}
global_ggtrace_state()
global_ggtrace_state(TRUE)
clear_global_ggtrace()

ggtrace(StatBoxplot$compute_group, -1, once = FALSE, verbose = FALSE)

# Plot not printed to save space
boxplot_plot

gguntrace(StatBoxplot$compute_group)

global_ggtrace()

global_ggtrace_state(FALSE)
```


### S3/S4 generics

The exported generic function `ggplot_build()` from `{ggplot2}` is itself not very meaningful, but the unexported method for the `<ggplot>` class `ggplot_build.ggplot()` contains the actual data transformation pipeline.

```{r}
body(ggplot_build)

attr(utils::methods("ggplot_build"), "info")
```

You can trace the `ggplot_build()` method defined for `<ggplot>` in the same way as functions

```{r}
ggtrace(ggplot2:::ggplot_build.ggplot, -1, verbose = FALSE)

boxplot_plot
```

```{r}
last_ggtrace()[[1]]$data[[1]]

identical(last_ggtrace()[[1]]$data[[1]], layer_data(boxplot_plot, 1))
```


### R6 methods

Adopted from [Advanced R Ch. 14.2](https://adv-r.hadley.nz/r6.html)

```{r}
library(R6)
Accumulator <- R6Class("Accumulator", list(
  sum = 0,
  add = function(x = 1) {
    self$sum <- self$sum + x 
    invisible(self)
  })
)
x <- Accumulator$new()
x$add(1)
x$sum
```

```{r}
ggtrace(
  method = x$add,
  trace_steps = c(1, -1),
  trace_exprs = list(
    before = quote(self$sum),
    after = quote(self$sum)
  ),
  once = FALSE,
  verbose = FALSE
)
x$add(10)
last_ggtrace()
x$add(100)
last_ggtrace()
gguntrace(x$add)
x$add(1000)
x$sum
```

## What can't you `ggtrace()`?

- Non-functions (ex: constants, object properties). But you can still inspect the values for these with `ggbody()` 
- Functions not defined in an environment (ex: you can't define a function to trace on-the-spot inside `ggtrace()`)
- Limited support for closures (the LHS of the `$` must itself be an environment where the function can be searched for)


## How can I save a modified ggplot?

When you trace the internals of ggplot, that doesn't directly modify the _instructions_ for plotting. Instead, it changes how certain components behave when they are _executed_.

This means that you will not get a different ggplot with the following code if `original_plot` is being traced with modifications, since `original_plot` is not being executed here.

```{r}
original_plot <- ggplot(mtcars, aes(hp, mpg)) + geom_point()

ggtrace(ggplot2:::ggplot_build.ggplot, -1, quote(data[[1]]$colour <- "red"), verbose = FALSE)

modified_plot <- original_plot
```

It looks like it worked when you first print it...

```{r}
modified_plot
```

But the variable `modified_pot` doesn't hold modified _code_ for generating the plot. Instead, it just happened to trigger the trace on ggplot_build.ggplot(). So the next time it runs, it's ran with the normal behavior of `original_plot`.

```{r}
modified_plot
```

To capture the actual figure generated by a ggplot, you can use `ggplotGrob()`, which returns the **Gr**aphical **ob**ject representation of the plot:

```{r}
ggtrace(ggplot2:::ggplot_build.ggplot, -1, quote(data[[1]]$colour <- "red"), verbose = FALSE)

modified_plot <- ggplotGrob(original_plot)

modified_plot
```

What you get is an object of class `<gtable>`, which you can draw to your device like any other grob:

```{r}
class(modified_plot)

library(grid)
grid.newpage()
grid.draw(modified_plot)
```

You can also use ggsave() to render a `<gtable>` to an image:

```{r, eval = FALSE}
# Not ran 
ggsave(filename = "modified_plot.png", plot = modified_plot, ...)
```

Still, `modified_plot` is only the graphical representation of the plot and not itself a ggplot object so you can't keep adding layers to it. So grobs are more limiting in that sense.

But it's not totally limiting like a raster image of a figure. For example, `{patchwork}` has `patchwork::wrap_ggplot_grob()` which allows a `<gtable>` to be properly aligned to other ggplots.

```{r}
library(patchwork)
original_plot_titled <- original_plot + ggtitle("original plot")

# Panels get aligned since `modified_plot` contains info about that
original_plot_titled + wrap_ggplot_grob(modified_plot)
```
