0

I have created a function in R having several arguments. I'd like to be able to call these arguments globally, to be used outside of the function.

How can this easily be done? I'm thinking perhaps match.fun() and match.arg() would be what is needed here. Am I correct in this?

My function is as follows:

HAC.sim <- function(K, N, Hstar, p, probs, perms = 10000){

specs <- 1:N

### Set up a container to hold the identity of each individual from each permutation

pop <- array(dim = c(c(perms, N), K))

### Create an ID for each haplotype

haps <- as.character(1:Hstar)

### Assign probabilities of occurrence to each haplotype, ensure they sum to 1
### This is where we assume we "know" the distribution of haplotypes
### Here, I have assumed they all occur with equal frequency, but you can change this to            assume some dominant ones and some rare ones, whatever you want

# probs <- rep(1/Hstar, Hstar) 
probs <- c(0.45, 0.45, rep(0.10/8, 8))

### Generate permutations, we assume each permutation has N individuals, and we sample  those individuals' haplotypes from our probabilities

# If K > 1, haplotypes are partitioned into equally-sized subpopulations/demes
# Can change number of haplotypes in each subpopulation and re-run simulation 
# For each additional, K, add new Ki and new pop[j ,, i] in loop

for(j in 1:perms){
    for(i in 1:K){ 
        if(i == 1){
            pop[j, specs, i] <- sample(haps, size = N, replace = TRUE, prob = probs)
        }
            else{
                pop[j ,, 1] <- sample(haps[K1], size = N, replace = TRUE, prob = probs[K1])
                pop[j ,, 2] <- sample(haps[K2], size = N, replace = TRUE, prob = probs[K2]) 
        }
    }
}

### Make a matrix to hold the 1:N individuals from each permutation

HAC.mat <- array(dim = c(c(perms, N), K))

for(k in specs){
    for(j in 1:perms){
        for(i in 1:K){ 
            ind.index <- sample(specs, size = k, replace = FALSE) ## which individuals will we sample
            hap.plot <- pop[sample(1:nrow(pop), size = 1, replace = TRUE), ind.index, sample(1:K, size          = 1, replace = TRUE)] ## pull those individuals from a permutation
            HAC.mat[j, k, i] <- length(unique(hap.plot))  ## how many haplotypes did we get for a given sampling intensity (k) from each ### permutation (j)
        }
    }
}

### Calculate the mean and CI for number of haplotypes at each sampling intensity (j)

means <- apply(HAC.mat, MARGIN = 2, mean)
lower <- apply(HAC.mat, MARGIN = 2, function(x) quantile(x, 0.025))
upper <- apply(HAC.mat, MARGIN = 2, function(x) quantile(x, 0.975))

d <- data.frame(specs, means, lower, upper)

### Plot the curve and frequency barplot

par(mfrow = c(1, 2))

for(i in 1:K){
    if(i == 1){
        plot(specs, means, type = "n", xlab = "Specimens sampled", ylab = "Unique haplotypes",  ylim = c(1, Hstar))
        polygon(x = c(specs, rev(specs)), y = c(lower, rev(upper)), col = "gray")
        lines(specs, means, lwd = 2)
        HAC.bar <- barplot(N*probs, xlab = "Unique haplotypes", ylab = "Specimens sampled", names.arg = 1:Hstar)
    }
    else{
        plot(specs, means, type = "n", xlab = "Specimens sampled", ylab = "Unique haplotypes", ylim = c(1, max(HAC.mat)))
        polygon(x = c(specs, rev(specs)), y = c(lower, rev(upper)), col = "gray")
        lines(specs, means, lwd = 2)
        HAC.bar <- barplot(N*probs[get(paste0("K", i))], xlab = "Unique haplotypes", ylab = "Specimens sampled", names.arg = get(paste0("K",i)))
    }
}

## Measures of Closeness ##

cat("\n Mean number of haplotypes sampled: " , max(means))
cat("\n Mean number of haplotypes not sampled: " , Hstar - max(means))
cat("\n Proportion of haplotypes sampled: " , max(means)/Hstar)
cat("\n Proportion of haplotypes not sampled: " , (Hstar - max(means))/Hstar)

cat("\n")

cat("\n Mean estimate of N*: ", (p*N*Hstar)/max(means))

}

HAC.sim(K = 1, N = 100, Hstar = 10, p = 0.95, probs = probs, perms = 10000)

I would like the argument 'p' to be available to pass to another function. Should I just use the ellipsis (...) in my function to specify additional arguments?

compbiostats
  • 909
  • 7
  • 22
  • What do you mean by "call these arguments globally"? It's unclear to me what you are doing. Perhaps you can make a more complete [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). Not sure what "no avail" means in this case. – MrFlick Oct 03 '17 at 18:10
  • I just need to easily pass my function's argument to outside of the function environment. I have tried function.name <<- function(...), but apparently this only works for local variables and not entire functions. – compbiostats Oct 03 '17 at 18:28
  • That sounds like exactly what functions are supposed to do. Functions typically encapsulate logic to keep it from the global environment. It would be much easier to help if you gave an example of what you hoped would work. I don't understand where you are trying to run this assignment. Are you writing a function that creates another function? – MrFlick Oct 03 '17 at 18:30
  • @MrFlick I have updated my question with my user-defined function, along with details on what I want to accomplish. – compbiostats Oct 03 '17 at 18:37
  • What function do you want to pass `p` to? And why exactly can't you do it currently? Are you getting an error or something? You called the `HAC.sim()` function with a particular value for `p`; why not just make that a variable that you also pass to another function.? – MrFlick Oct 03 '17 at 18:40
  • @MrFlick I'd like to pass 'p' to a second user-defined function that I have created. – compbiostats Oct 03 '17 at 18:46
  • And what's preventing you from doing that? There's nothing in this code that makes that clear. If you want to pass `p` to that function, then pass `p` to that function. If you want to pass the same value to two function, save that value to a variable, and use that variable when calling both functions. – MrFlick Oct 03 '17 at 18:48
  • @ I think I will just define p as a variable in my function... – compbiostats Oct 03 '17 at 18:54

1 Answers1

0

If I understand correctly what you are asking, this demonstrates how to assign to the global environment values from a function's arguments.

> ls()
character(0)
> fn <- function(a, b, c) { 
   global_a <<- a
   global_b <<- b
   global_c <<- c
  a*b*c
}
> ls()
[1] "fn"
> fn(2, 3, 4)
[1] 24
> ls()
[1] "fn"       "global_a" "global_b" "global_c"
> global_a
[1] 2

However, I would strongly encourage you to find an alternative way around what you are trying to solve, because this kind of approach can lead to lots of headaches down the road.

You could pass the arguments as an attribute to your results if you are interested in only some of the parameters for instance:

fn_attr <- function(a, b, c) {
    res <- a * b * c
    attr(res, "args") <- list(a = a, c = c)
    res
}

> foo <- fn_attr(2, 3, 4)
> attr(foo, "args")$a

or get all the arguments values:

fn_attr_all <- function(a, b, c) {
    args_vals <- as.list(environment())
    res <- a * b * c
    attr(res, "args") <- args_vals
    res
}
fmic_
  • 2,281
  • 16
  • 23