0

I am currently working with the 'igraph' package on R.

I have created two functions that create a statistical table of graph object that work pretty well if used directly on a single graph object (here is an example of what they look like) :

Sfn <- function(x) # Give a table of statistics for nodes

{

Name <- deparse(substitute(x))
Nodes <- V(x)$name
Dtotal <- degree(x, mode="all")
Eigenvector <- eigen_centrality(x)

statistics_table <- data.frame(Nodes,
                               Dtotal,
                               Eigenvector)

colnames(statistics_table) <- c("Nodes","Total Degrees",
                                "Eigenvector centrality")    
write.table(statistics_table, 
            file = paste0("Table_of_",Name,"_nodes.csv"),
            sep=",",
            row.names = F)

print("Success.")

}

As I am using several graph objects, I would like not to have to write one line per command, such as :

Sfn(g)
Sfn(g2)
Sfn(g3)
# etc...
Sfn(n)

I would thus like to create a vector of lists in which I could collect all my graph objects. I created something like that :

G <- c(
     list(CC1),list(CC2),list(CC3),
     list(CC4),list(CC5),list(CC6),
     list(CC7),list(CC8),list(CC9),
     list(CC10),list(CC11),list(CC12))

Yet, this solution is not optimal. First, it is too long to write if I have, for example, 100 graph objects. Secondly, if I write my script with an for() loop, the name of the variable sent to my function will be the name of the parameter of for(), thus, ruining the variable Name of my function Sfn. In other words, the script for(i in G) {Sfn(G)} does not work, because the variable Name will be equal to i :

# In my function Sfn, Name <- deparse(substitute(i)), 
for(i in G) {print(deparse(substitute(i)))} 
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"
[1] "i"

Also, the solution there : (Change variable name in for loop using R) does not work because I have, in my graph objects, very different randomly attributed graph names (such as "CC1","g2","CT3","CC1T3", etc).

Do you have any idea on how I could possibly:

1 - achieve a better way of creating a vector of graph objects ?

2 - make the name of the parameter sent to my variable the same as the actual name of the variable ?

PGCD
  • 1

1 Answers1

0

Using deparse(substitute()) makes it hard to do what you want. If you really want to do this without changing your Sfn function, you'll need to construct a call to it as a string and parse that. For example:

names <- c("CC1", "g2")
Sfn <- function(x) deparse(substitute(x))   # just return the name
result <- list()
for (n in names) {
  result[[n]] <- eval(parse(text = paste("Sfn(", n, ")")))
}
result
#> $CC1
#> [1] "CC1"
#> 
#> $g2
#> [1] "g2"

Created on 2021-09-12 by the reprex package (v2.0.0)

This could be much simpler if you passed the name you want as a string to Sfn, instead of trying to get it using deparse(substitute()), e.g.

names <- c("CC1", "g2")
Sfn <- function(x, name) name
result <- list()
for (n in names)
  result[[n]] <- Sfn(n, n)
result
#> $CC1
#> [1] "CC1"
#> 
#> $g2
#> [1] "g2"

Created on 2021-09-12 by the reprex package (v2.0.0)

Edited to add: Not only is the second solution cleaner, it's safer too. If you don't have complete control of the names vector, there's a huge security risk: someone could set the "name" to some executable code (see https://xkcd.com/327/) and it would be executed.

user2554330
  • 37,248
  • 4
  • 43
  • 90
  • Thank you very much for your answer ! I am not familiar with your formulation however I will try to understand it. I will keep you in touch, but seeing as it seems to work by my side (I have not fully tested it yet), I think it will be of great help. – PGCD Sep 15 '21 at 17:39