--- a +++ b/R/get_interaction_from_database.R @@ -0,0 +1,195 @@ +#' Get interaction from database +#' +#' Returns an interaction graph from a vector of nodes (or a list of vectors) +#' and an interaction database (data.frame or igraph) +#' +#' @param X vector of nodes or list of vectors +#' @param db data.frame (with two columns: from, to) or igraph +#' @param type character added to node metadata +#' @param user.ego logical, if user.ego == TRUE looks for first degree neighbors +#' in db and add 'mode' metadata ('core'/'extended') +#' +#' @return a subset graph of db from X list of nodes +#' +#' @examples +#' X <- letters[1:4] +#' db <- as.data.frame(list(from = sample(letters[1:10], replace = TRUE), +#' to = sample(letters[1:10], replace = TRUE))) +#' +#' sub <- get_interaction_from_database(X, +#' db) +#' +#' db.graph <- igraph::graph_from_data_frame(db, +#' directed=FALSE) +#' sub <- get_interaction_from_database(X, +#' db) +#' +#' @importFrom purrr is_empty map reduce +#' @importFrom igraph induced_subgraph set_vertex_attr adjacent_vertices +#' @export +get_interaction_from_database <- function(X, + db = NULL, + type = "db", + user.ego = FALSE) { + + # check X + if (is(X, "list")) { + X <- lapply(X, function(x) check_vector_char(x)) + if (is.null(names(X))) { + names(X) <- seq_along(X) + } + } else { + X <- check_vector_char(X) + } + + # check db + db <- check_db(db, var.name = "'db' ") + + # check type + type <- check_vector_char(type, X.length = 1, default = "db") + + # check user.ego + user.ego <- return_true_false(user.ego, default = FALSE) + + + if (is.null(X)) { + message("X is NULL, returning an empty graph") + db.subgraph <- igraph::make_empty_graph(directed = FALSE) + class(db.subgraph) <- c("interaction.igraph", "igraph") + return(db.subgraph) + } else if (is(X, "list")) { + # filter db from X + db.subgraph.list <- list() + if (is(db, "igraph")) { + ### + db.subgraph.list <- lapply(X, function(i){ + .interaction_from_igraph(X = i, + db = db, + ego = user.ego, + type = type) + }) + + } else { + # db is a data.frame + db.subgraph.list <- lapply(X, function(i){ + .interaction_from_dataframe(X = i, + db = db, + ego = user.ego, + type = type) + }) + } + class(db.subgraph.list) <- "list.igraph" + return(db.subgraph.list) + } else { + # X is a single vector + if (is(db, "igraph")) { + db.subgraph <- .interaction_from_igraph(X = X, + db = db, + ego = user.ego, + type = type) + } else { + # db is a data.frame + db.subgraph <- .interaction_from_dataframe(X = X, + db = db, + ego = user.ego, + type = type) + } + return(db.subgraph) + } +} + +.interaction_from_igraph <- function(X, + db, + ego, + type) { + node.names <- intersect(X, igraph::V(db)$name) + if (purrr::is_empty(node.names)) { + message("no shared elements between X and db, return empty graph") + db.subgraph <- igraph::make_empty_graph(directed = FALSE) + } else if (isTRUE(ego)) { + ego.neighbors <- igraph::adjacent_vertices(graph = db, + v = node.names, + mode = "all") + ego.neighbors <- unique( + purrr::reduce( + purrr::map(ego.neighbors, ~names(.x)), + union + ) + ) + ego.neighbors <- setdiff(ego.neighbors, node.names) + + db.subgraph <- igraph::induced_subgraph(graph = db, + vids = c(node.names, + ego.neighbors)) + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "mode", + index = node.names, + value = "core") + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "mode", + index = ego.neighbors, + value = "extended") + } else { + # ego = FALSE + db.subgraph <- igraph::induced_subgraph(graph = db, + vids = c(node.names)) + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "mode", + index = node.names, + value = "core") + } + # return graph + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "type", + value = type) + class(db.subgraph) <- c("interaction.igraph", "igraph") + return(db.subgraph) +} + +.interaction_from_dataframe <- function(X, + db, + ego, + type) { + db <- as.data.frame(db) %>% + dplyr::select(c("from", "to")) # checked colnames + db.all.nodes <- unique(c(db$from, db$to)) + node.names <- intersect(X, db.all.nodes) + if (purrr::is_empty(node.names)) { + message("no shared elements between X and db, return empty graph") + db.subgraph <- igraph::make_empty_graph(directed = FALSE) + } else if (isTRUE(ego)) { + ego.db <- db %>% + dplyr::filter(.$from %in% node.names | .$to %in% node.names) + # ego.neighbors <- setdiff(db.all.nodes, node.names) + ego.neighbors <- setdiff( + unique(c(ego.db$from, ego.db$to)), + node.names + ) + + db.subgraph <- igraph::graph_from_data_frame(ego.db, directed = FALSE) + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "mode", + index = node.names, + value = "core") + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "mode", + index = ego.neighbors, + value = "extended") + } else { + # ego = FALSE + ego.db <- db %>% + dplyr::filter(.$from %in% node.names & .$to %in% node.names) + + db.subgraph <- igraph::graph_from_data_frame(ego.db, directed = FALSE) + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "mode", + value = "core") + } + + # return graph + db.subgraph <- igraph::set_vertex_attr(graph = db.subgraph, + name = "type", + value = type) + class(db.subgraph) <- c("interaction.igraph", "igraph") + return(db.subgraph) +}