Reputation: 25638
Say I have a data set and I'd like to apply several filters to it using piping syntax, like so:
library(magrittr)
library(dplyr)
mtcars %<>%
filter(cyl == 4) %>%
select(cyl, mpg)
nrow(mtcars)
#[1] 11
I check the current status of the data set with nrow
after each such step, so I thought I could override the piping %<>%
operator along the lines of
`%<?>%` <- function(lhs, rhs) {
x <- magrittr::`%<>%`(lhs, rhs)
if (is.data.frame(x) & pipeVerbose) print(nrow(x))
}
#Using this will generate errors like
#Error in pipes[[i]] : subscript out of bounds
And now by switching pipeVerbose
flag on or off I would control the tracking procedure for the whole flow. Apparently it's not that simple because of the internal evaluation mechanism, as prompted here. The question is, is it possible to achieve the desired behavior with minimal effort, i.e. without patching the magittr
internals?
I have to admit the whole idea is slightly unsettling, but my actual scenario is a bit more complicated and I'd like to hide some debug/development details for demonstration purposes via a simple on/off switch.
Upvotes: 3
Views: 407
Reputation: 47340
Note that you can have you on/off switch this way, not much more visible than having %<?>%
instead of %<>%
:
p <- function(x){if(pipeVerbose) print(nrow(x))}
pipeVerbose <- FALSE
mtcars %<>%
filter(cyl == 4) %>%
select(cyl, mpg) %T>% p
rm(mtcars)
pipeVerbose <- TRUE
mtcars %<>%
filter(cyl == 4) %>%
select(cyl, mpg) %T>% p
Upvotes: 1
Reputation: 206536
Since chains take advantage of lazy evaluation, a better translation would have been something like this:
`%<?>%` <- function(lhs, rhs) {
call <- match.call()
call[[1]] <- quote(`%<>%`)
x <- eval.parent(call)
if (is.data.frame(x) & pipeVerbose) print(nrow(x))
}
We basically re-write the function call and evaluate it.
Upvotes: 2
Reputation: 5670
You could make use of a TaskCallback
which executes whenever a toplevel task is completed. In the callback check if the expression contains the %<>%
operator and if yes print the result:
printAssignmentPipe <- function(exp, res, success, printed){
if (any(grepl("%<>%", exp, fixed = T))) {
print(res)
}
TRUE
}
addTaskCallback(printAssignmentPipe)
You can easily extend the callback to also check the value of pipeVerbose
or you simply call addTaskCallback
and removeTaskCallback
to activate/deactivate.
Upvotes: 3