0

I did check this problem but couldn't find an exact solution. Furthermore, applying the solution threw another error.

I did write the following function for agents' matchmaking.

    library(tidyverse)
    library(cowplot)
    library(gridExtra)
    library(grid)
    library(Rmisc)


    matchmaking_two_value <- function(eta_lt,eta_rt,rho_lt,rho_rt,theta,time,
                                  target = c("eta_lt","eta_rt","rho_lt","rho_rt")){
  
    storage_v2 <- matrix(NA_real_, nrow = time, ncol = 4)
    graphs <- list()
    storage_v2 <- as.data.frame(storage_v2)
    colnames(storage_v2) <- c("eta_lt","eta_rt","rho_lt","rho_rt")
  
    for (i in 1:time) {
    storage_v2[i,1] <- eta_lt
    storage_v2[i,2] <- eta_rt
    storage_v2[i,3] <- rho_lt
    storage_v2[i,4] <- rho_rt
    
    
    eta_lt_next <- (2*eta_rt*rho_lt) - (2*eta_lt*rho_rt) + (2*theta*eta_lt*eta_rt) - (2*(1-theta)*eta_rt*eta_lt) + eta_lt^2
    eta_rt_next <- 1 - eta_lt_next - rho_lt - rho_rt
    
    if(eta_lt_next <= 0) {
      eta_lt <- 0
      eta_rt <- 1 - (eta_lt + rho_lt + rho_rt)
    } else{
      eta_lt <- eta_lt_next
      eta_rt <- eta_rt_next
    }
 
 
    
 
     }
         plot <- storage_v2%>%ggplot(mapping = aes(x = 1:time)) + 
         geom_line(aes(y = eta_lt, color = "Eta_L")) + 
         geom_line(aes(y = eta_rt, color = "Eta_R")) + 
         geom_line(aes(y = rho_lt, color = "Rho_L")) + 
         geom_line(aes(y = rho_rt, color = "Rho_R")) + 
         
         ggtitle("Population", subtitle = paste("Theta: ", theta)) + 
         ylab("Proportions") + xlab("Time") + 
         scale_color_manual(name = "Agent Types", 
                            breaks = c("Eta_L","Eta_R","Rho_L","Rho_R"), 
                            values = c("Eta_L" = "khaki4","Eta_R" = "salmon3", 
                                       "Rho_L" = "darkslateblue", "Rho_R" = "tomato4")) + 
         theme_minimal()
  
  
    print(storage_v2)
    print(plot)

}

This function gives the results if I give the input. Although I want to use this function for creating multiple plots. Such as following

for(i in seq(0,0.9,0.1)){
matchmaking_two_value(eta_lt = i, eta_rt = 0.9-i, rho_lt= 0.05, rho_rt = 0.05, theta = 0.5, time = 10)
}

My problem is I can't store the function's results under the list. Any solution would be appreciated

jpsmith
  • 11,023
  • 5
  • 15
  • 36
Onur Bal
  • 5
  • 1
  • 1
    Could you please better articulate you question in a clear, straightforward statement and provide sample data? This will likely get you good help faster. In the lower code, you aren't saving anything - have you tried list_data[[i]] <- matchmaking_two_value(...)`? – jpsmith May 26 '22 at 16:56
  • 1
    One reason you might not be able to save the function's results is that it doesn't return anything. Also, when all you do in the loop is *assign* a function's return value to an object and then only access the object outside the loop, you are likely to encounter *lazy evaluation* problems. Typically this is characterised by every element of ther array or list being assigned the same value - the value returned by the final evaluation of the loop. Far better to use a member of the `apply` family, all of which *force* evaluation. – Limey May 26 '22 at 17:00
  • @jpsmith Yes! Thank you for your instant reply. I did try to save it, as you mentioned. But it is just storing the last value, which is logical. I am trying to get these plots and plot them under one graphs with grid.extra. – Onur Bal May 26 '22 at 17:31
  • @Limey I am sorry. I don't think I am advanced enough to understand what you mean. Which function can I use from the apply family to get the results of the graphs in the for loop as a list? – Onur Bal May 26 '22 at 17:33
  • See, for example, [here](https://stackoverflow.com/questions/67413684/adding-layers-to-ggplots-works-but-adding-in-a-loop-does-not). – Limey May 26 '22 at 17:40
  • @Limey thank you so much, the answer solved my problem. I have no clue how it works currently, but will learn about it. Thanks for contributing! – Onur Bal May 26 '22 at 17:48

1 Answers1

1

You need a function that actually returns a value. If you just print() results in the function, those side effects cannot be collected and used later. So change your function from

matchmaking_two_value <- function(...){
  ...
  print(storage_v2)
  print(plot)
}

to

matchmaking_two_value <- function(...){
  ...
  list(data=storage_v2, plot=plot)`
}

Then when you are return a list, you can collect those values in a list quickly with something like lapply()

result <- lapply(seq(0,0.9,0.1), function(i) {
  matchmaking_two_value(eta_lt = i, eta_rt = 0.9-i, rho_lt= 0.05, rho_rt = 0.05, theta = 0.5, time = 10)
})

Then you can extract the plots and data with commands like

result[[1]]$plot
result[[1]]$data
result[[10]]$plot
result[[10]]$data

To get a list of all the plots to send to grid.extra you can do

allplots <- lapply(result, function(x) x$plot)
gridExtra::grid.arrange(grobs=allplots)
MrFlick
  • 195,160
  • 17
  • 277
  • 295