Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override magrittr pipe operator?

Tags:

r

dplyr

magrittr

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.

like image 923
tonytonov Avatar asked Jan 22 '26 03:01

tonytonov


2 Answers

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.

like image 58
AEF Avatar answered Jan 23 '26 20:01

AEF


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.

like image 23
MrFlick Avatar answered Jan 23 '26 19:01

MrFlick