Pipe in magrittr package is not working for function load()
The envir
argument in load()
needs to be specified as either globalenv()
or parent.frame(3)
.
# in a fresh R session ...
a <- 1
b <- 1
save(list = ls(), file = file.path(tempdir(), 'tmp.RData'))
# in another fresh session ...
ls()
# character(0)
tempdir() %>% file.path("tmp.RData") %>% load(envir = globalenv())
ls()
# [1] "a" "b"
The following also works:
tempdir() %>% file.path("tmp.RData") %>% load(envir = parent.frame(3))
I'll try to explain why. When you call load()
from any environment, the function loads the new objects in the parent environment.
Now, the global environment globalenv()
is your R workspace. So, if you call load from the global environment (i.e. the workspace) everything works as you expect. Visualise this:
- Global environment
load()
However, if you call load()
from inside a function, then you've inserted an environment in between load and the global environment. Visualise this:
- Global environment
- function
load()
- function
This is exactly what happens when you put %>%
into the mix:
- Global environment
%>%
load()
There are two solutions for resolving this. Either explicitly point to globalenv()
or walk 3 steps up the chain to the global environment using parent.frame(3)
.
Note: There was an issue reported on GitHub for this. Not sure what the resolution was, or if there is one yet. The issue was just reported in September.
Many thanks to @Andrie for improving this explanation.
Pipe in magrittr package is not working for function rm()
Use the %<>%
operator for assigning the value to NULL
x %<>%
rm()
In the pipe, we are getting the value instead of the object. So, by using the %<>%
i.e. in place compound assignment operator, the value of 'x' is assigned to NULL
x
#NULL
If we need the object to be removed, pass it as character
string, feed it to the list
argument of rm
which takes a character
object and then specify the environment
x <- 10
"x" %>%
rm(list = ., envir = .GlobalEnv)
When we call 'x'
x
Error: object 'x' not found
The reason why the ...
doesn't work is that the object .
is not evaluated within the rm
x <- 10
"x" %>%
rm(envir = .GlobalEnv)
Warning message: In rm(., envir = .GlobalEnv) : object '.' not found
Another option is using do.call
x <- 10
"x" %>%
list(., envir = .GlobalEnv) %>%
do.call(rm, .)
x
Error: object 'x' not found
Why isn't the magrittr %% assignment pipe working with R's native pipe (|)
The reason that the assignment pipe, %<>%
is no longer is due operator precedence. The %<>%
occurs before the |>
, see below eacmple:
library(magrittr)
library(tidyverse)
a <- tibble(a = 1:3)
a %<>%
mutate(b = a * 2) |>
mutate(c = a * 3) |>
filter(a <= 2)
a
Returns
# A tibble: 3 × 2
a b
<int> <dbl>
1 1 2
2 2 4
3 3 6
Thus the
a %<>%
mutate(b = a * 2)
Is the only section that was saved. You can also get a feeling that this may be the case as you get the intended table printed instead which should never be the case with a tibble assignment.
Error: could not find function %%
You need to load a package (like magrittr
or dplyr
) that defines the function first, then it should work.
install.packages("magrittr") # package installations are only needed the first time you use it
install.packages("dplyr") # alternative installation of the %>%
library(magrittr) # needs to be run every time you start R and want to use %>%
library(dplyr) # alternatively, this also loads %>%
The pipe operator %>%
was introduced to "decrease development time and to improve readability and maintainability of code."
But everybody has to decide for himself if it really fits his workflow and makes things easier.
For more information on magrittr
, click here.
Not using the pipe %>%
, this code would return the same as your code:
words <- colnames(as.matrix(dtm))
words <- words[nchar(words) < 20]
words
EDIT:
(I am extending my answer due to a very useful comment that was made by @Molx)
Despite being from
magrittr
, the pipe operator is more commonly used
with the packagedplyr
(which requires and loadsmagrittr
), so
whenever you see someone using%>%
make sure you shouldn't loaddplyr
instead.
R: use magrittr pipe operator in self written package
It should have worked correctly if you had magrittr
listed in Depends
. However, this is not advised. Instead, you leave magrittr
in Imports
and add the following line to NAMESPACE
:
importFrom(magrittr,"%>%")
I suggest reading Writing R extensions. Your question is covered in paragraphs 1.1.3 and 1.5.1.
Error in magrittr pipe when using ``magrittr::`%%` ``
The pipe arguments (%>%, %$%, etc...) are all actually the same pipe()
function in magrittr. One of the first things that function does is to split the call into its constituent parts using an internal, non-exported function split_chain
.
split_chain()
takes the first element of the call (the function used, in this case, one of the pipe operators) and runs it through another internal, non-exported function called is_pipe()
which looks like:
function(pipe)
{
identical(pipe, quote(`%>%`)) ||
identical(pipe, quote(`%T>%`)) ||
identical(pipe, quote(`%<>%`)) ||
identical(pipe, quote(`%$%`))
}
if this doesn't come back as true, the function exits returning a list that is missing the pipe type and the right-handed side of the argument which causes problems. When scoping, a la magrittr::'%>%'
the first part of the call includes the explicit scoping and so it fails these hard coded checks.
R: transition from magrittr to native pipe and translation of a function
complete_data_native_wrong()
:
complete_data_native_wrong <- function(data){
res <- data |> (\(x) filter(x, complete.cases(x)))()
return(res)
}
Data masking is the reason that this lovely function doesn't work as expected.
"So, what actually happens?", you ask.
dplyr::filter()
checks for a column named x
, it indeed finds it, then passes the contents of that column to complete.cases()
. The same happens when you use y
instead of x
.
complete.cases()
ends up acting on a "vector" instead of a data.frame
, hence the results.
"But... How do I ensure dplyr::filter()
doesn't act that way?", you enquire.
That's where the bang-bang operator !!
comes in. And we can now have complete_data_native_right()
:
complete_data_native_right <- function(data){
res <- data |> (\(x) filter(x, complete.cases(!!x)))()
# res <- data |> (\(y) filter(y, complete.cases(!!y)))()
return(res)
}
move_row_native_attempt()
:
For this one you can use the shorthand function notation without any hiccups:
move_row_native_attempt <- function(df, ini_pos, fin_pos){
row_pick <- slice(df, ini_pos)
if (fin_pos=="last"){
res <- df |>
slice(-ini_pos) |>
(\(x) add_row(x, row_pick, .before = nrow(x)))()
} else{
res <- df |>
slice(-ini_pos) |>
add_row(row_pick, .before = fin_pos)
}
return(res)
}
Why is a command not working in a pipe operator in R, but outside the pipe it works perfectly fine?
Problem: not all functions are pipe-friendly
{magrittr} pipes work best with functions written to be "pipe-friendly." These generally take a dataframe as a first argument, and may use data masking to let you refer to columns within that dataframe without prefixing them. e.g., many {dplyr} verbs are pipe-friendly.
which.min
isn't pipe-friendly. Your code,
ir_OEX_data %>% group_by(quotedate) %>% which.min(abs(moneyness_call - 1))
is actually equivalent to
which.min(
group_by(ir_OEX_data, quotedate),
abs(moneyness_call - 1)
)
but which.min
expects only one argument, so throws an error.
Solution 1: the exposition pipe (%$%)
There are a few ways to deal with this. One is the {magrittr} exposition pipe, %$%
, which makes your column names available to the next function without passing the data:
library(magrittr)
library(dplyr)
ir_OEX_data %>%
group_by(quotedate) %$%
which.min(abs(moneyness_call - 1))
Solution 2: use inside a pipe-friendly function
If you wanted to add the result of which.min
to your dataset, you'd just need to use it inside summarize
or mutate
:
ir_OEX_data %>%
group_by(quotedate) %>%
summarize(call_which_min = which.min(abs(moneyness_call - 1)))
Solution 3: write a pipe-friendly wrapper
You can also put a non-friendly function in a pipe-friendly wrapper. This would probably be overkill here, but can be useful in more complex cases.
which_min_pipe <- function(.data, x) {
.data %>% summarize(out = which.min({{ x }})) %>% pull(out)
}
ir_OEX_data %>%
group_by(quotedate) %>%
which_min_pipe(abs(moneyness_call - 1))
Related Topics
How to Define a Function in Dplyr
Get Country (And Continent) from Longitude and Latitude Point in R
Separate String After Last Underscore
Creating a Stacked Bar Chart Centered on Zero Using Ggplot
Converting a Long-Formated Dataframe to Wide Format Tidyverse
R: How to Filter a Timestamp by Hour and Minute
Converting an Xts Object to a Data.Frame
How to Debug Methods from Reference Classes
Get Data Out of a Tcltk Function
Using Dplyr to Group_By and Conditionally Mutate a Dataframe by Group
R: Xmleventparse with Large, Varying-Node Xml Input and Conversion to Data Frame
How to Use Different Font Sizes in Ggplot Facet Wrap Labels
Using Inst/Extdata with Vignette During Package Checking R 2.14.0
Combining Multiple Identically-Named Columns in R
Identify a Value Changes' Date and Summarize The Data with Sum() and Diff() in R