1#' Get detailed information on nodes 2#' 3#' Obtain a data frame with detailed information on nodes and their 4#' interrelationships within the graph. 5#' 6#' @param graph A graph object of class `dgr_graph`. 7#' 8#' @return A data frame containing information specific to each node within the 9#' graph. 10#' 11#' @examples 12#' # Create a simple graph 13#' graph <- 14#' create_graph() %>% 15#' add_gnm_graph( 16#' n = 5, m = 10, 17#' set_seed = 23) 18#' 19#' # Get information on the graph's nodes 20#' graph %>% get_node_info() 21#' 22#' @export 23get_node_info <- function(graph) { 24 25 # Get the name of the function 26 fcn_name <- get_calling_fcn() 27 28 # Validation: Graph object is valid 29 if (graph_object_valid(graph) == FALSE) { 30 31 emit_error( 32 fcn_name = fcn_name, 33 reasons = "The graph object is not valid") 34 } 35 36 # If graph is empty, return NULL 37 if (is_graph_empty(graph)) { 38 return(NULL) 39 } 40 41 # Get vectors of nodes in edges and 42 # node `type` values 43 edge_from <- graph$edges_df$from 44 edge_to <- graph$edges_df$to 45 type <- graph$nodes_df$type 46 47 # Get vector of all node IDs and all labels 48 all_nodes <- graph$nodes_df$id 49 labels <- graph$nodes_df$label 50 51 # For graphs with no edges, create a 52 # `node_properties` data frame that doesn't 53 # need to consider any edge information 54 if (nrow(graph$edges_df) == 0) { 55 56 node_properties <- 57 as.data.frame( 58 mat.or.vec( 59 nr = length(all_nodes), 60 nc = 7), 61 stringsAsFactors = FALSE) 62 63 colnames(node_properties) <- 64 c("id", "type", "label", "deg", 65 "indeg", "outdeg", "loops") 66 67 node_properties[, 1] <- graph$nodes_df[, 1] 68 node_properties[, 2] <- graph$nodes_df[, 2] 69 node_properties[, 3] <- graph$nodes_df[, 3] 70 71 # Ensure that the `id` column is an integer 72 node_properties <- 73 dplyr::mutate(node_properties, id = as.integer(id)) 74 75 # Arrange the table by `id` ascending 76 node_properties <- 77 dplyr::arrange(node_properties, id) 78 79 } else if (!is.null(graph$edges_df)) { 80 81 # Get vector of the top-level nodes 82 top_nodes <- 83 unique( 84 edge_from[which(!(edge_from %in% 85 edge_to))]) 86 87 # Get vector of the bottom-level nodes 88 bottom_nodes <- 89 unique( 90 edge_to[which(!(edge_to %in% 91 edge_from))]) 92 93 # Get vector of all nodes neither at the top nor 94 # the bottom level 95 between_nodes <- 96 all_nodes[which(!(all_nodes %in% 97 c(top_nodes, 98 bottom_nodes)))] 99 100 # Place the nodes in order 101 ordered_nodes <- 102 c(top_nodes, between_nodes, bottom_nodes) 103 104 # Create data frame of node properties 105 for (i in seq(ordered_nodes)) { 106 if (i == 1) { 107 node_properties <- 108 as.data.frame( 109 mat.or.vec(nr = 0, 110 nc = 7), 111 stringsAsFactors = FALSE) 112 113 colnames(node_properties) <- 114 c("id", "type", "label", "deg", 115 "indeg", "outdeg", "loops") 116 } 117 118 # Get degree for each node 119 degree <- 120 sum(c(graph$edges_df$from, 121 graph$edges_df$to) %in% 122 ordered_nodes[i]) 123 124 # Get indegree for each node 125 if (ordered_nodes[i] %in% 126 top_nodes | degree == 0) { 127 indegree <- 0 128 } 129 130 if (!(ordered_nodes[i] %in% 131 top_nodes) & degree != 0) { 132 for (j in 1:sum(edge_to %in% 133 ordered_nodes[i])) { 134 if (j == 1) { 135 indegree <- vector(mode = "character") 136 } 137 indegree <- 138 c(indegree, 139 edge_from[which(edge_to %in% 140 ordered_nodes[i])[j]]) 141 } 142 indegree <- length(indegree) 143 } 144 145 # Get outdegree for each node 146 if (ordered_nodes[i] %in% 147 bottom_nodes | degree == 0) { 148 outdegree <- 0 149 } 150 151 if (!(ordered_nodes[i] %in% bottom_nodes) & 152 degree != 0) { 153 for (j in 1:sum(edge_from %in% 154 ordered_nodes[i])) { 155 if (j == 1) { 156 outdegree <- vector(mode = "character") 157 } 158 outdegree <- 159 c(outdegree, 160 edge_from[which(edge_from %in% 161 ordered_nodes[i])[j]]) 162 } 163 outdegree <- length(outdegree) 164 } 165 166 # Get number of loops for each node 167 loops <- 168 sum(graph$edges_df$from == graph$edges_df$to & 169 graph$edges_df$to == ordered_nodes[i]) 170 171 # Collect information into `node_properties` 172 node_properties[i, 1] <- 173 ordered_nodes[i] 174 175 node_properties[i, 2] <- 176 ifelse(exists("type"), 177 type[which(all_nodes %in% 178 ordered_nodes[i])], 179 rep(NA, length(ordered_nodes))) 180 181 node_properties[i, 3] <- 182 ifelse(!is.null( 183 labels[which(all_nodes %in% 184 ordered_nodes[i])]), 185 labels[which(all_nodes %in% 186 ordered_nodes[i])], 187 NA) 188 189 node_properties[i, 4] <- degree 190 node_properties[i, 5] <- indegree 191 node_properties[i, 6] <- outdegree 192 node_properties[i, 7] <- loops 193 } 194 195 # Ensure that the `id` column is an integer 196 node_properties <- 197 dplyr::mutate( 198 node_properties, id = as.integer(id)) 199 200 # Arrange the table by `id` ascending 201 node_properties <- 202 dplyr::arrange( 203 node_properties, id) 204 } 205 206 node_properties 207} 208