whence_trace() takes a pipeline that ends in a single value, and runs it
one step at a time. It records the number of rows after each step. The
result tells you how many rows each step removed, and gives code that
makes the value again.
Usage
whence_trace(expr, env = parent.frame())Value
A whence_trace object. Use whence_value(), whence_code(),
whence_rows(), as.data.frame() and print() with it.
The object is a list. These fields are stable, and you can read them:
value: the value, aswhence_value()gives it.code: the reproduce code, aswhence_code()gives it.traced:TRUEwhen the pipeline was split into steps.stages: a data frame with one row for each step, asas.data.frame()gives it.reason: why the chain stopped short, as one sentence, orNULLwhen every step was traced.
Do not rely on the other fields. They can change in any version.
Details
The pipeline is split by its verbs. A call to a known verb, such as
filter() or summarise(), is a step, and its first argument is the data
that comes from upstream. This works the same for the native pipe |>,
for the magrittr pipe %>% and for nested calls. The chain stops at the
first call that is not a known verb, such as a join. That call and all
that is upstream of it become the source.
Each step is evaluated in env, as the full expression would be. A step
thus sees the same variables, and in 'shiny' it reads the same inputs and
reactive values.
The steps run once, in order. This is the same work as running the expression in one piece.
Limits
A database-backed pipeline (a
tbl_lazyfrom 'dbplyr') is an error. Its steps run as SQL only atcollect(), so there are no row counts to show.Joins are not traced. A join ends the chain.
The verbs of 'data.table', 'arrow' and 'duckplyr' are not known.
The native-pipe placeholder
_is not supported. A pipeline that uses it is not split, and the value is still given.
Known verbs
These calls are steps: filter(), mutate(), transmute(), select(),
rename(), arrange(), slice(), slice_head(), slice_tail(),
slice_min(), slice_max(), slice_sample(), group_by(), ungroup(),
summarise(), summarize(), count(), tally(), distinct(),
drop_na(), pivot_longer(), pivot_wider(), pull(), head() and
tail(), with or without a namespace such as dplyr::. Any other call
ends the chain, and the trace says where in its reason.
Examples
library(dplyr, warn.conflicts = FALSE)
trace <- whence_trace(
mtcars |>
filter(cyl == 4) |>
filter(mpg > 25) |>
summarise(mean_hp = mean(hp))
)
trace
#> <whence_trace> 75.5
#>
#> Where the rows went
#> 0 mtcars 32
#> 1 -> cyl == 4 11 -21 rows (66%)
#> 2 -> mpg > 25 6 -5 rows (45%)
#> 3 -> aggregated to 1 row 1
#>
#> Reproduce
#> mtcars |>
#> filter(cyl == 4) |>
#> filter(mpg > 25) |>
#> summarise(mean_hp = mean(hp))
as.data.frame(trace)
#> step label n delta percent kind verb groups shown
#> 1 0 mtcars 32 NA NA source <NA> NA TRUE
#> 2 1 cyl == 4 11 -21 -65.62500 filter filter NA TRUE
#> 3 2 mpg > 25 6 -5 -45.45455 filter filter NA TRUE
#> 4 3 aggregated to 1 row 1 NA NA summarise summarise NA TRUE
