Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In writing an R package, using the flowCore::transform function, can I both use a variable name as text and get the actual value?

I am trying to pass on an argument to a function, which is a string but must be evaluated both for it's name (symbol?) and it's value (see example below). So far I am able to use base::get to get the actual value, but the assignment in flowCore::'transform,flowSet-method' fails. I am aware that many questions on SO are on evaluating strings as variable names and, as you will see below I tried a whole lot of them. I assume there must be an rlang based answer, but I cannot find any solution, any pointers would be appreciated.

A reproducible example:

# load required packages -------------------------------------------------------
library(flowAI)   # Bioconductor
library(flowCore) # Bioconductor
library(rlang)
# load example data ------------------------------------------------------------
data(Bcells) # from flowAI
# reprex -----------------------------------------------------------------------
timeCh <- "Time" # this could be variable

x <- flowCore::transform(Bcells,`Time`=(`Time`-min(`Time`)))           # this works
y <- flowCore::transform(Bcells,`Time`=(get(timeCh)-min(get(timeCh)))) # still good
z <- flowCore::transform(Bcells,timeCh=(get(timeCh)-min(get(timeCh)))) # not good

While in the code above the transform for z will run just fine, in fact a new column is added to the flowSet called "timeCh". This is not the desired effect, because I want to use the transform to specifically change the existing column Time. Hence, I have been trying a few strategies to evaluate the string stored in timeCh as an object name (?) into transform, but to no avail:

timeSym <- sym("Time")
timequo <- quo(timeCh)

t1 <- flowCore::transform(Bcells,!!timeSym=(get(timeCh)-min(get(timeCh)))) 
# Error: unexpected '=' in "t1 <- flowCore::transform(Bcells,!!timeSym="
t2 <- flowCore::transform(Bcells,{{timeSym}}=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t2 <- flowCore::transform(Bcells,{{timeSym}}="
t3 <-  flowCore::transform(Bcells,eval(parse(text=timeCh))=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t3 <-  flowCore::transform(Bcells,eval(parse(text=timeCh))="
t4 <-  flowCore::transform(Bcells,assign(timeCh,(get(timeCh)-min(get(timeCh)))))
# Error in get(timeCh) : object 'Time' not found
t5 <-  flowCore::transform(Bcells,assign(timeCh,(get(timeCh)-min(get(timeCh))),inherits = TRUE))
# Error in get(timeCh) : object 'Time' not found
t6 <-  flowCore::transform(Bcells,with(Bcells,assign(timeCh,(get(timeCh)-min(get(timeCh))),inherits = TRUE)))
# Error in get(timeCh) : object 'Time' not found
t7 <-  flowCore::transform(Bcells,as.name(timeCh)=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t7 <-  flowCore::transform(Bcells,as.name(timeCh)="
t8 <-  flowCore::transform(Bcells,UQ(timequo)=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t8 <-  flowCore::transform(Bcells,UQ(timequo)="
t9 <-  flowCore::transform(Bcells,(eval(quote(timeCh)))=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t9 <-  flowCore::transform(Bcells,(eval(quote(timeCh)))="

It seems to me an issue with scoping, but I am really stumped on how to get around it.

like image 738
FM Kerckhof Avatar asked Mar 13 '20 10:03

FM Kerckhof


1 Answers

One possible way using rlang expression arithmetic:

# Compose the expression `Time = Time - min(Time)`
tfarg <- rlang::exprs( !!timeSym := !!timeSym - min(!!timeSym) )

# Compose the expression `flowCore::transform(Bcells, Time = Time - min(Time))`
xpr  <- rlang::expr( flowCore::transform(Bcells, !!!tfarg) )
xpr2 <- rlang::call2( flowCore::transform, Bcells, !!!tfarg )   # Alternative

# Evaluate the second expression
t1 <- eval(xpr)      # or t1 <- eval(xpr2)

# Compare to desired output
identical( summary(t1), summary(x) )  # TRUE

In the above, we first create the expression Time = Time - min(Time) using quasiquotation. Think of it as replacing !!timeSym with the symbol stored inside timeSym (i.e., Time), while using := to make it work on the left-hand side of the assignment.

We then create the second expression flowCore::transform(Bcells, Time = Time - min(Time)) by pasting the first expression inside a flowCore::transform() function call. Lastly, we evaluate it and compare the result to your desired output.

Side note: it appears that the minimum Time value is zero, so your transform() effectively does nothing.

like image 177
Artem Sokolov Avatar answered Sep 26 '22 23:09

Artem Sokolov