Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

across(all_of()) doesn't see variables outside it's own environment #5498

Closed
vovoch opened this issue Aug 26, 2020 · 5 comments · Fixed by #5508
Closed

across(all_of()) doesn't see variables outside it's own environment #5498

vovoch opened this issue Aug 26, 2020 · 5 comments · Fixed by #5508
Assignees
Labels
reprex needs a minimal reproducible example

Comments

@vovoch
Copy link

vovoch commented Aug 26, 2020

I faced the strange behavior in mutate(across(all_of())) combination of functions. Objects defined previously cannot be used inside of this construction. Two examples:

reduce(mget(ls(pattern = "^mcmc_stat_")), full_join, by = "ParameterMCMC") %>%
    select(ParameterMCMC, Median, LCL95, HCL95, Mean, SD) %>%
    nest(data = !all_of("ParameterMCMC")) %>%
    mutate(retaining_cols = map(ParameterMCMC, ~global_settings$mcmc_param_presets %>%
                                  filter(INPUT == .x) %>% pull(COLUMNS) %>% unlist()),
           data = map2(retaining_cols, data, ~.y %>% mutate(across(!all_of(.x), ~NA))))

#Error: object '.x' is not found
reduce(mget(ls(pattern = "^mcmc_stat_")), full_join, by = "ParameterMCMC") %>%
    select(ParameterMCMC, Median, LCL95, HCL95, Mean, SD) %>%
    nest(data = !all_of("ParameterMCMC")) %>%
    mutate(data = map2(ParameterMCMC, data, ~{
      retaining_cols <- global_settings$mcmc_param_presets %>%
        filter(INPUT == .x) %>% pull(COLUMNS) %>% unlist()
      .y %>% mutate(across(!all_of(retaining_cols), ~NA))
    }))

#Error: object 'retaining_cols' is not found

But objects from the R_GlobalEnv can be used. For example, the "<<-" operator in the following code resolves this problem and works in the expected way:

reduce(mget(ls(pattern = "^mcmc_stat_")), full_join, by = "ParameterMCMC") %>%
    select(ParameterMCMC, Median, LCL95, HCL95, Mean, SD) %>%
    nest(data = !all_of("ParameterMCMC")) %>%
    mutate(data = map2(ParameterMCMC, data, ~{
      retaining_cols <<- global_settings$mcmc_param_presets %>%
        filter(INPUT == .x) %>% pull(COLUMNS) %>% unlist()
      .y %>% mutate(across(!all_of(retaining_cols), ~NA))
    }))
@lionel-
Copy link
Member

lionel- commented Aug 27, 2020

It would really help if you could reduce the example to a bare bones reprex with:

  • the least amount of function calls
  • the least amount of control flow (e.g. is reduce() essential to your example?)
  • the least amount of symbols and texts (but still informative names)
  • some typographic air around the essential constructs to help the reader focus on the flow of code

Also please make it reproducible with https://github.com/tidyverse/reprex

@hadley hadley added the reprex needs a minimal reproducible example label Aug 28, 2020
@hadley
Copy link
Member

hadley commented Aug 28, 2020

Can you please provide a minimal reprex (reproducible example)? The goal of a reprex is to make it as easy as possible for me to recreate your problem so that I can fix it: please help me help you!

If you've never heard of a reprex before, start by reading "What is a reprex", and follow the advice further down the page. Please make sure your reprex is created with the reprex package as it gives nicely formatted output and avoids a number of common pitfalls.

@vovoch
Copy link
Author

vovoch commented Aug 30, 2020

I have the full set of statistics for all parameters after an MCMC simulation (data_tbl).
My intention is to keep only the essential statistics for each parameter based on the special tibble (preset_tbl).
It is possible only using the global assignment (res_ok_tbl), but doesn't work without it (res_error_tbl).

library(tidyverse)

data_tbl <- tibble(
  PARAMETER = c("Rate",   "mu"),
  MEDIAN    = c("28.01%", "-0.94"),
  LCL95     = c("8.15%",  "-2.42"),
  HCL95     = c("62.97%", "0.53"),
  MEAN      = c("29.93%", "-0.95"),
  SD        = c("14.02%", "0.74")
)

preset_tbl <- tribble(
  ~PARAMETER, ~STAT_COLUMNS,
  "Rate",    c("MEDIAN", "LCL95", "HCL95"),
  "mu",      c("MEAN", "SD")
)

join_tbl <- left_join(data_tbl, preset_tbl, by = "PARAMETER")

res_error_tbl <- join_tbl %>%
  nest(data = !all_of(c("PARAMETER", "STAT_COLUMNS"))) %>%
  mutate(data = map2(data, STAT_COLUMNS, ~{
    .x %>% mutate(across(!all_of(.y), ~NA_character_))
  })) %>% unnest(cols = data) %>% select(-STAT_COLUMNS)
#> Error: Problem with `mutate()` input `data`.
#> x Problem with `mutate()` input `..1`.
#> x object '.y' not found
#> i Input `..1` is `across(!all_of(.y), ~NA_character_)`.
#> i Input `data` is `map2(...)`.

res_ok_tbl <- join_tbl %>%
  nest(data = !all_of(c("PARAMETER", "STAT_COLUMNS"))) %>%
  mutate(data = map2(data, STAT_COLUMNS, ~{
    y_global <<- .y
    .x %>% mutate(across(!all_of(y_global), ~NA_character_))
  })) %>% unnest(cols = data) %>% select(-STAT_COLUMNS)

# Input and desirable output of the target code

join_tbl
#> # A tibble: 2 x 7
#>   PARAMETER MEDIAN LCL95 HCL95  MEAN   SD     STAT_COLUMNS
#>   <chr>     <chr>  <chr> <chr>  <chr>  <chr>  <list>      
#> 1 Rate      28.01% 8.15% 62.97% 29.93% 14.02% <chr [3]>   
#> 2 mu        -0.94  -2.42 0.53   -0.95  0.74   <chr [2]>

res_ok_tbl
#> # A tibble: 2 x 6
#>   PARAMETER MEDIAN LCL95 HCL95  MEAN  SD   
#>   <chr>     <chr>  <chr> <chr>  <chr> <chr>
#> 1 Rate      28.01% 8.15% 62.97% <NA>  <NA> 
#> 2 mu        <NA>   <NA>  <NA>   -0.95 0.74

Created on 2020-08-30 by the reprex package (v0.3.0)

@lionel-
Copy link
Member

lionel- commented Aug 31, 2020

Thank you for the reproducible example. Here is a minimal version:

library(tidyverse)

df <- tibble(
  vars = list("foo"),
  data = list(data.frame(foo = 1))
)

map2(df$data, df$vars, ~ mutate(.x, across(all_of(.y), ~ NA)))
#> [[1]]
#>   foo
#> 1  NA

df %>% mutate(data = map2(data, vars, ~ {
  .x %>% mutate(across(all_of(.y), ~ NA))
}))
#> Error: Problem with `mutate()` input `data`.
#> ✖ Problem with `mutate()` input `..1`.
#> ✖ object '.y' not found
#> ℹ Input `..1` is `across(all_of(.y), ~NA)`.
#> ℹ Input `data` is `map2(...)`.

@lionel-
Copy link
Member

lionel- commented Aug 31, 2020

From #5475

@lionel- lionel- self-assigned this Aug 31, 2020
lionel- added a commit to lionel-/dplyr that referenced this issue Aug 31, 2020
lionel- added a commit to lionel-/dplyr that referenced this issue Aug 31, 2020
lionel- added a commit to lionel-/dplyr that referenced this issue Aug 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
reprex needs a minimal reproducible example
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants