How to view the process step by step of a function in R?

Viewed 131

Df:

df <- tibble(
  a = c("z", "x", "y"),
  b = c("m", "n", "o"),
  c = c("p", "q", "r")
)

-I would like to see the result of names(.) (to inspect) in:

df %>% 
  set_names(c(names(.)[1], unlist(.[2, 2:3])))

-I know it is c("a", "b", "c"), or the result in unlist(.[2, 2:3]). This is an example, I want to apply the idea in any operation in R. Is there something out there? I want to have a deep sense of what some function is doing.

2 Answers

Not sure if this is what you had in mind, but lobstr::ast() shows the abstract syntax tree that R creates to determine how the various inputs and functions in a call are related.

https://medium.com/analytics-vidhya/become-a-better-r-programmer-with-the-awesome-lobstr-package-af97fcd22602

lobstr::ast(df %>% 
              set_names(c(names(.)[1], unlist(.[2, 2:3]))))


█─`%>%` 
├─df 
└─█─set_names 
  └─█─c 
    ├─█─`[` 
    │ ├─█─names 
    │ │ └─. 
    │ └─1 
    └─█─unlist 
      └─█─`[` 
        ├─. 
        ├─2 
        └─█─`:` 
          ├─2 
          └─3 

Perhaps you're looking for the boomer package by @Moody_Mudskipper:

boomerlogo.png

Installation

Install with remotes::install_github("moodymudskipper/boomer")

Examples (from github):

library(boomer)
boom(1 + !1 * 2)
#> 1 * 2
#> [1] 2
#> !1 * 2
#> [1] FALSE
#> 1 + !1 * 2
#> [1] 1

boom(subset(head(mtcars, 2), qsec > 17))
#> head(mtcars, 2)
#>               mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4      21   6  160 110  3.9 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4
#> qsec > 17
#> [1] FALSE  TRUE
#> subset(head(mtcars, 2), qsec > 17)
#>               mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4

# You can use boom() with {magrittr} pipes, just pipe to boom() at the end of a pipe chain.
library(magrittr)
mtcars %>%
  head(2) %>%
  subset(qsec > 17) %>%
  boom()
#> head(., 2)
#>               mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4      21   6  160 110  3.9 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4
#> qsec > 17
#> [1] FALSE  TRUE
#> subset(., qsec > 17)
#>               mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4
#> mtcars %>% head(2) %>% subset(qsec > 17)
#>               mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4

#If a call fails, {boomer} will print intermediate outputs up to the occurrence of the error, it can help with debugging:
"tomato" %>%
  substr(1, 3) %>%
  toupper() %>%
  sqrt() %>%
  boom()
#> substr(., 1, 3)
#> [1] "tom"
#> toupper(.)
#> [1] "TOM"
#> Error in .Primitive("sqrt")(.): non-numeric argument to mathematical function

Boomer prints the output of intermediate steps as they are executed, and thus doesn’t say anything about what isn’t executed, it is in contrast with functions like lobstr::ast() which return the parse tree.

Apparently boomer doesn't 'play nice' with the set_names function; here is a similar example:

df %>% 
  names(.)[1] %>% 
  boom()
#>names(.)
#>[1] "a" "b" "c"
#>.[names(.), 1]
#> A tibble: 3 x 1
#>      a
#>  <dbl>
#>1    NA
#>2    NA
#>3    NA
#>df %>% names(.)[1]
#> A tibble: 3 x 1
#>      a
#>  <dbl>
#>1    NA
#>2    NA
#>3    NA
Related