Writing a function with text arguments - r

I have a matrix (colormatrix) that in the first column (called NCS.code) has a identifier, and in a second column (called colour.assignment) that has color names.
I would like to create a function (changecolor) that can change the color name (so the value of colour.assignment), based on the identifier name. I wrote the following, but it does not work.
changecolor<-function(id,color){
locdat<-match(id, colormatrix$NCS.code)
#finds the location where id matches the identifier
colormatrix_lab$colour.assignment[locdat]<-color}
#changes the color name at location locdat into the name that was given as input
changecolor("S0300-N","white")
#test if the code works -- which is not the case.
Thanks for all the help.

When you want to modify global variables from within function calls, you can not use <- because it will not evaluate in the global scope. To do what you want - try using:
<<- when modifying global data structures from within function calls.

Related

How do I write a dplyr pipe-friendly function where a new column name is provided from a function argument?

I'm hoping to produce a pipe-friendly function where a user specifies the "name of choice" for a new column produced by the function as one of the function arguments.
In the function below, I'd like name_for_elective to be something that the user can set at will, and afterwards, the user could expect that there will be a new column in their data with the name that they provided here.
I've looked at https://dplyr.tidyverse.org/reference/dplyr_data_masking.html, the mutate() function documentation, searched here, and tried working with https://dplyr.tidyverse.org/reference/rename.html, but to no avail.
elective_open<-function(.data,name_for_elective,course,tiebreaker){
name_for_elective<-rlang::ensym(name_for_elective)
course<-rlang::ensym(course)
tiebreaker<-rlang::ensym(tiebreaker)
.data%>%
mutate(!!name_for_elective =ifelse(!!tiebreaker==max(!!tiebreaker),1,0))%>%mutate(!!name_for_elective=ifelse(!!name_for_elective==0,!!course[!!name_for_elective==1],""))%>%
filter(!(!!course %in% !!name_for_elective))
}
I've included this example function because there are several references to the desired new column name, and I'm unsure if the context in which the reference is made changes syntax.
As you can see, I was hoping !!name_for_elective would let me name our new column, but no. I've played with {{}}, not using rlang::ensym, and still haven't got this figured out.
Any solution would be greatly appreciated.
This: Use dynamic variable names in `dplyr` may be helpful, but I can't seem to figure out how to extend this to work in the case where multiple references are made to the name argument.
Example data, per a good suggestion by #MrFlick, takes the form below:
dat<-tibble(ID=c("AA","BB","AA","BB","AA","BB"),Class=c("A_Class","B_Class","C_Class","D_Class","E_Class","F_Class"),
randomNo=c(.75,.43,.97,.41,.27,.38))
The user could then run something like:
dat2<-dat%>%
elective_open(MyChosenName,Class,randomNo)
A desired result, if using the function a single time, would be:
desired_result_1<-tibble(ID=c("AA","BB","AA","BB"),
Class=c("A_Class","D_Class","E_Class","F_Class"),
randomNo=c(.75,.41,.27,.38),
MyChosenName=c("C_Class","B_Class"))
The goal would be to allow this function to be used again if so desired, with a different name specified.
In the case where a user runs:
dat3<-dat%>%
elective_open(MyChosenName,Class,randomNo)%>%
mutate(Just_Another_One=1)%>%
elective_open(SecondName,Class,randomNo)
The output would be:
desired_result_2<-tibble(ID=c("AA","BB"),
Class=c("E_Class","F_Class"),
randomNo=c(.27,.38),
MyChosenName=c("C_Class","B_Class"),
Just_Another_One=c(1,1),
SecondName=c("A_Class","D_Class"))
In reality, there may be any number of records with the same ID, and any number of Class-es.
In this case you can just stick to using the embrace {{}} option for your variables. If you want to dynamically create column names, you're going to still need to use :=. The difference here is that you can use the glue-style syntax with the embrace operator to get the name of the symbol. This works with the data provided.
elective_open <- function(.data, name_for_elective, course, tiebreaker){
.data%>%
mutate("{{name_for_elective}}" := ifelse({{tiebreaker}}==max({{tiebreaker}}),1,0)) %>%
mutate("{{name_for_elective}}" := ifelse({{name_for_elective}}==0,{{course}}[{{name_for_elective}}==1],"")) %>%
filter(!({{course}} %in% {{name_for_elective}}))
}

How do I use get() in R to access a variable with another variable?

I have a loop which is running over a vector containing names of a few tens of dataframes that are in my environment. On each iteration, I want to access the dataframe using the name, and access a specific column within it. As I understand it, the best way to access a variable with a string is using get().
But when I try and do this (with name being a variable containing the string "first.name"):
get(column.name, name)
I get the error:
Error in as.environment(pos) : no item called "first.name" on the search list
It does work if I try to run:
get(column.name, first.name)
So, assuming that get() is the right function for this, what am I doing wrong?
Reproduceable example:
my.df <- as.data.frame(x = seq(1:10), y = rnorm(10))
name <- "my.df"
get("x",name)
We may need to use
get(name)[[column.name]]

Preserve a promise in R

I want to, essentially, pass a value untouched through a function. So in the following example (in Rstudio):
example_function <- function(datain){
as.environment("package:utils")$View(datain)
}
I want the inner function to act as if I'm passing it the original object, in particular so the name which appears in the View window will have the name of the original object (X, say) rather than datain which is what currently occurs.
With deparse(substitute(datain)) you can get the original name of the argument passed.
Then, to accomplish what you asked for, you can simply do
example_function <- function(datain){
as.environment("package:utils")$View(datain, deparse(substitute(datain)))
}
Now the View window will be titled appropriately as you wanted.
However note that "I want the inner function to act as if I'm passing it the original object" request of yours is not possible in R. R does not support pass-by-reference. There are some workarounds, but if you only needed if for naming the View, the above fix should be fine.
You can also use get for this.
example_function <- function(datain){
as.environment("package:utils")$View(get(datain),datain)
}
in this case you don't pass the variable but rather the name of the variable as a string.
example_function("X")

getNodeSet by attribute values

I'm parsing xml with R's getNodeSet function by attribute value with the following code:
getNodeSet(doc, "/body//*[#attribution='HM'][#*='checkmark'][#*='underline']")
The code above returns node content that includes all three of the above values (effectively, 'HM' And 'checkmark' And 'underline').
I'd like the function to return nodes in which the first value remains constant, but for which additional values are EITHER/OR (effectively, 'HM' AND 'checkmark' OR 'underline').
Grateful for any help.
The solution is to combine the type attribute values to be OR'd within a single set of square brackets, and supply 'or' without quotes:
getNodeSet(doc, "/body//*[#attribution='HM'][#*='underline' or #*='checkmark']")

Referencing a function parameter in R

I'm working on a function and need to know how to reference the incoming parameters.
For example, in python or lots of other languages, you can reference the input parameters something like this:
sys.argv[1:].
How can I reference the name of a parameter in R?
The specific problem I'm trying to solve is I want to capture the string value of the incoming parameter, so I can paste it as a concentration with a list of column_names I want to iterate through.
Here's the head of the function call, just so you can see the incoming parameter:
function(df_in)
So here's an example of the code I am writing and I want the string value of the dataframe_in, not the object that it references.
col_name <-paste(df_in,varnames[i],sep="$")
if df_in contained "my_df" and the current column_name is my_col, I'm trying to have col_name in the example above set to my_df$my_col.
I was thinking of using the get() function but quite sure how to apply it in this situation.
Thanks
Try something along these lines:
fn1 <- function(df_in){ in_nam <- deparse(substitute(df_in) )
col_names <-paste(in_nam, names(df_in), sep="$")
cat(col_names) }
> dfrm <- data.frame(a=1:10, b=letters[1:10])
> fn1(dfrm)
#dfrm$a dfrm$b
You didn't say what varnames was supposed to be so I'm guessing you want the column names from the object. BTW, don't expect to be able to reference the column values with those character values. They are no longer language objects.

Resources