Skip to contents

Extending base::trace() with ggtrace()

The low-level function ggtrace() is designed for interacting with functions and ggproto methods in the ggplot2 ecosystem, from the “outside”.

Formally put, ggtrace() allows the user to inject arbitrary expressions (called traces) to functions and methods that are evaluated over the execution of a ggplot. When “triggered” by the evaluation of the ggplot, these traces may modify the resulting graphical output, or they may simply log their values to the “tracedump” for further inspection by the user. Check out the FAQ vignette for more details.

Briefly, there are three key arguments to ggtrace():

  • method: what function/method to trace
  • trace_steps: where in the body to inject expressions
  • trace_exprs what expressions to inject

A simple example:

dummy_fn <- function(x = 1, y = 2) {
  z <- x + y
  return(z)
}
dummy_fn()
#> [1] 3

The following code injects the code z <- z * 10 right as dummy_fn enters the third “step” in the body, right before the line return(z) is ran.

body(dummy_fn)[[3]]
#> return(z)
ggtrace(
  method = dummy_fn,
  trace_steps = 3L, # Before `return(z)` is ran
  trace_exprs = quote(z <- z * 10)
)
#> `dummy_fn` now being traced.

Note that the value of trace_exprs must be of type “language” (a quoted expression), the idea being that we are injecting code to be evaluate inside the function when it is called. Often, providing the code wrapped in quote() suffices. For more complex injections see the Expressions chapter of Advanced R

After this ggtrace() call, the next time dummy_fn is called it is run with this injected code.

# Returns 30 instead of 3
dummy_fn()
#> Triggering trace on `dummy_fn`
#> Untracing `dummy_fn` on exit.
#> [1] 30

Essentially, dummy_fn ran with this following modified code just now:

dummy_fn_traced <- function(x = 1, y = 2) {
  z <- x + y
  z <- z * 10 #< injected code!
  return(z)
}
dummy_fn_traced()
#> [1] 30

By default, traces created by ggtrace functions delete themselves after being triggered. You can also check whether a function is currently being traced with is_traced().

is_traced(dummy_fn)
#> [1] FALSE

ggtrace automatically logs the output of triggered trace to what we call tracedumps. For example, last_ggtrace() stores the output of the last trace created by ggtrace():

# The value of `(z <- z * 10)` when it was ran
last_ggtrace() # Note that this is a list of length `trace_steps`
#> [[1]]
#> [1] 30

See the references section Extending base::trace() for more functionalities offered by ggtrace().