Nothing
#' Add a node to an existing graph object
#'
#' @description
#'
#' With a graph object of class `dgr_graph`, add a new node to the graph. One
#' can optionally provide node attributes for the created node. There is also
#' the option to create edges to and from existing nodes in the graph. Because
#' new edges can also be created through this function, there is the possibility
#' to set edge attributes for any new graph edges.
#'
#' @inheritParams node_edge_aes_data
#' @inheritParams render_graph
#' @param type An optional character object that acts as a group identifier for
#' the node to be added.
#' @param label An optional character object that describes the node.
#' @param from An optional vector containing node IDs from which edges will be
#' directed to the new node.
#' @param to An optional vector containing node IDs to which edges will be
#' directed from the new node.
#'
#' @return A graph object of class `dgr_graph`.
#'
#' @examples
#' # Create an empty graph and add 2 nodes by using
#' # the `add_node()` function twice
#' graph <-
#' create_graph() %>%
#' add_node() %>%
#' add_node()
#'
#' # Get a count of all nodes
#' # in the graph
#' graph %>% count_nodes()
#'
#' # The nodes added were given
#' # ID values `1` and `2`; obtain
#' # the graph's node IDs
#' graph %>% get_node_ids()
#'
#' # Add a node with a `type`
#' # value defined
#' graph <-
#' graph %>%
#' add_node(type = "person")
#'
#' # View the graph's internal
#' # node data frame (ndf)
#' graph %>% get_node_df()
#'
#' @family node creation and removal
#'
#' @export
add_node <- function(
graph,
type = NULL,
label = NULL,
from = NULL,
to = NULL,
node_aes = NULL,
edge_aes = NULL,
node_data = NULL,
edge_data = NULL
) {
# Get the time of function start
time_function_start <- Sys.time()
# Validation: Graph object is valid
check_graph_valid(graph)
# Get the node ID for the node to be added
node <- graph$last_node + 1L
# Get the number of edges in the graph
edges_in_graph <- nrow(graph$edges_df)
# Get the number of edges ever created for
# this graph
edges_created <- graph$last_edge
# If `type` or `label` is NULL, convert to NA
type <- type %||% NA_character_
label <- label %||% NA_character_
# Collect node aesthetic attributes
if (!is.null(node_aes)) {
node_aes_tbl <- dplyr::as_tibble(node_aes)
if (nrow(node_aes_tbl) == 1) {
node_aes$index__ <- 1
node_aes_tbl <-
dplyr::as_tibble(node_aes) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(node_aes_tbl)) {
node_aes_tbl$id <- NULL
}
}
# Collect node data attributes
if (!is.null(node_data)) {
node_data_tbl <- dplyr::as_tibble(node_data)
if (nrow(node_data_tbl) == 1) {
node_data$index__ <- 1
node_data_tbl <-
dplyr::as_tibble(node_data) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(node_data_tbl)) {
node_data_tbl$id <- NULL
}
}
# Modify graph if neither `to` nor `from`
# values provided
if (is.null(from) && is.null(to)) {
new_node <-
create_node_df(
n = 1,
label = as.character(label),
type = as.character(type))
new_node[1, 1] <- node
# Add node aesthetics if available
if (exists("node_aes_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_aes_tbl)
}
# Add node data if available
if (exists("node_data_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_data_tbl)
}
combined_nodes <-
combine_ndfs(graph$nodes_df, new_node)
edges_in_graph_2 <- nrow(graph$edges_df)
graph$nodes_df <- combined_nodes
graph$last_node <- graph$last_node + 1
# Get the name of the function
fcn_name <- get_calling_fcn()
# Update the `graph_log` df with an action
graph$graph_log <-
add_action_to_log(
graph_log = graph$graph_log,
version_id = nrow(graph$graph_log) + 1L,
function_used = fcn_name,
time_modified = time_function_start,
duration = graph_function_duration(time_function_start),
nodes = nrow(graph$nodes_df),
edges = nrow(graph$edges_df),
d_n = 1)
# Write graph backup if the option is set
if (graph$graph_info$write_backups) {
save_graph_as_rds(graph = graph)
}
return(graph)
}
# Modify graph if only `from` values provided
if (!is.null(from) && is.null(to)) {
from_nodes_available <-
all(from %in% get_node_ids(graph))
if (!from_nodes_available) {
cli::cli_abort(c(
"The nodes from which edges should be applied to the new node are not available."
))
}
# from_nodes_available
new_node <-
create_node_df(
n = 1,
label = as.character(label),
type = as.character(type)
)
new_node[1, 1] <- node
# Add node aesthetics if available
if (exists("node_aes_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_aes_tbl)
}
# Add node data if available
if (exists("node_data_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_data_tbl)
}
# Combine the new nodes with those in the graph
combined_nodes <-
combine_ndfs(graph$nodes_df, new_node)
# Collect edge aesthetic attributes
if (!is.null(edge_aes)) {
edge_aes_tbl <- dplyr::as_tibble(edge_aes)
if (nrow(edge_aes_tbl) < length(from)) {
edge_aes$index__ <- seq_along(from)
edge_aes_tbl <-
dplyr::as_tibble(edge_aes) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(edge_aes_tbl)) {
edge_aes_tbl$id <- NULL
}
}
# Collect edge data attributes
if (!is.null(edge_data)) {
edge_data_tbl <- dplyr::as_tibble(edge_data)
if (nrow(edge_data_tbl) < length(from)) {
edge_data$index__ <- seq_along(from)
edge_data_tbl <-
dplyr::as_tibble(edge_data) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(edge_data_tbl)) {
edge_data_tbl$id <- NULL
}
}
new_edges <-
create_edge_df(
from = from,
to = rep(node, length(from))
)
new_edges$id <-
new_edges$id + edges_created
# Add edge aesthetics if available
if (exists("edge_aes_tbl")) {
new_edges <-
new_edges %>%
dplyr::bind_cols(edge_aes_tbl)
}
# Add edge data if available
if (exists("edge_data_tbl")) {
new_edges <-
new_edges %>%
dplyr::bind_cols(edge_data_tbl)
}
# Use `bind_rows()` to add the
# new edges
combined_edges <-
dplyr::bind_rows(
graph$edges_df,
new_edges
)
edges_in_graph_2 <- nrow(combined_edges)
edges_added <- edges_in_graph_2 - edges_in_graph
# Create a revised graph
graph$nodes_df <- combined_nodes
graph$edges_df <- combined_edges
graph$last_node <- graph$last_node + 1
graph$last_edge <- graph$last_edge + edges_added
# Get the name of the function
fcn_name <- get_calling_fcn()
# Update the `graph_log` df with an action
graph$graph_log <-
add_action_to_log(
graph_log = graph$graph_log,
version_id = nrow(graph$graph_log) + 1L,
function_used = fcn_name,
time_modified = time_function_start,
duration = graph_function_duration(time_function_start),
nodes = nrow(graph$nodes_df),
edges = nrow(graph$edges_df),
d_n = 1,
d_e = length(from)
)
# Write graph backup if the option is set
if (graph$graph_info$write_backups) {
save_graph_as_rds(graph = graph)
}
return(graph)
}
# Modify graph if only `to` values provided
if (is.null(from) && !is.null(to)) {
to_nodes_available <-
all(to %in% get_node_ids(graph))
if (!to_nodes_available) {
cli::cli_abort(
"The nodes to which edges should be applied from the new node are not available.")
}
# Assume to_nodes is available.
new_node <-
create_node_df(
n = 1,
label = as.character(label),
type = as.character(type))
new_node[1, 1] <- node
# Add node aesthetics if available
if (exists("node_aes_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_aes_tbl)
}
# Add node data if available
if (exists("node_data_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_data_tbl)
}
combined_nodes <-
combine_ndfs(graph$nodes_df, new_node)
# Collect edge aesthetic attributes
if (!is.null(edge_aes)) {
edge_aes_tbl <- dplyr::as_tibble(edge_aes)
if (nrow(edge_aes_tbl) < length(from)) {
edge_aes$index__ <- seq_along(from)
edge_aes_tbl <-
dplyr::as_tibble(edge_aes) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(edge_aes_tbl)) {
edge_aes_tbl$id <- NULL
}
}
# Collect edge data attributes
if (!is.null(edge_data)) {
edge_data_tbl <- dplyr::as_tibble(edge_data)
if (nrow(edge_data_tbl) < length(from)) {
edge_data$index__ <- seq_along(from)
edge_data_tbl <-
dplyr::as_tibble(edge_data) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(edge_data_tbl)) {
edge_data_tbl$id <- NULL
}
}
new_edges <-
create_edge_df(
from = rep(node, length(to)),
to = to)
new_edges$id <-
new_edges$id + edges_created
# Add edge aesthetics if available
if (exists("edge_aes_tbl")) {
new_edges <-
new_edges %>%
dplyr::bind_cols(edge_aes_tbl)
}
# Add edge data if available
if (exists("edge_data_tbl")) {
new_edges <-
new_edges %>%
dplyr::bind_cols(edge_data_tbl)
}
# Use `bind_rows()` to add the
# new edges
combined_edges <-
dplyr::bind_rows(
graph$edges_df,
new_edges)
edges_in_graph_2 <- nrow(combined_edges)
edges_added <- edges_in_graph_2 - edges_in_graph
# Create a revised graph
graph$nodes_df <- combined_nodes
graph$edges_df <- combined_edges
graph$last_node <- graph$last_node + 1
graph$last_edge <- graph$last_edge + edges_added
# Get the name of the function
fcn_name <- get_calling_fcn()
# Update the `graph_log` df with an action
graph$graph_log <-
add_action_to_log(
graph_log = graph$graph_log,
version_id = nrow(graph$graph_log) + 1L,
function_used = fcn_name,
time_modified = time_function_start,
duration = graph_function_duration(time_function_start),
nodes = nrow(graph$nodes_df),
edges = nrow(graph$edges_df),
d_n = 1,
d_e = length(to))
# Write graph backup if the option is set
if (graph$graph_info$write_backups) {
save_graph_as_rds(graph = graph)
}
return(graph)
}
# Modify graph if both `to` and `from` values provided
if (!is.null(from) && !is.null(to)) {
from_nodes_available <-
all(from %in% get_node_ids(graph))
to_nodes_available <-
all(to %in% get_node_ids(graph))
if (!from_nodes_available) {
cli::cli_abort(
"The nodes from which edges should be applied to the new node are not available.")
}
if (!to_nodes_available) {
cli::cli_abort(
"The nodes to which edges should be applied from the new node are not available."
)
}
# If both to_nodes and from_nodes are available, continue.
new_node <-
create_node_df(
n = 1,
label = as.character(label),
type = as.character(type))
new_node[1, 1] <- node
# Add node aesthetics if available
if (exists("node_aes_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_aes_tbl)
}
# Add node data if available
if (exists("node_data_tbl")) {
new_node <-
new_node %>%
dplyr::bind_cols(node_data_tbl)
}
# Combine the new nodes with those in the graph
combined_nodes <-
combine_ndfs(graph$nodes_df, new_node)
new_edges <-
combine_edfs(
create_edge_df(
from = rep(node, length(to)),
to = to),
create_edge_df(
from = from,
to = rep(node, length(from))))
new_edges$id <-
new_edges$id + edges_created
# Collect edge aesthetic attributes
if (!is.null(edge_aes)) {
edge_aes_tbl <- dplyr::as_tibble(edge_aes)
if (nrow(edge_aes_tbl) < (length(from) + length(to))) {
edge_aes$index__ <- seq_len(length(from) + length(to))
edge_aes_tbl <-
dplyr::as_tibble(edge_aes) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(edge_aes_tbl)) {
edge_aes_tbl$id <- NULL
}
}
# Collect edge data attributes
if (!is.null(edge_data)) {
edge_data_tbl <- dplyr::as_tibble(edge_data)
if (nrow(edge_data_tbl) < (length(from) + length(to))) {
edge_data$index__ <- seq_len(length(from) + length(to))
edge_data_tbl <-
dplyr::as_tibble(edge_data) %>%
dplyr::select(-"index__")
}
if ("id" %in% colnames(edge_data_tbl)) {
edge_data_tbl$id <- NULL
}
}
# Add edge aesthetics if available
if (exists("edge_aes_tbl")) {
new_edges <-
new_edges %>%
dplyr::bind_cols(edge_aes_tbl)
}
# Add edge data if available
if (exists("edge_data_tbl")) {
new_edges <-
new_edges %>%
dplyr::bind_cols(edge_data_tbl)
}
# Use `bind_rows()` to add the
# new edges
combined_edges <-
dplyr::bind_rows(
graph$edges_df,
new_edges)
edges_in_graph_2 <- nrow(combined_edges)
edges_added <- edges_in_graph_2 - edges_in_graph
# Create a revised graph and return that graph
graph$nodes_df <- combined_nodes
graph$edges_df <- combined_edges
graph$last_node <- graph$last_node + 1
graph$last_edge <- graph$last_edge + edges_added
# Get the name of the function
fcn_name <- get_calling_fcn()
# Update the `graph_log` df with an action
graph$graph_log <-
add_action_to_log(
graph_log = graph$graph_log,
version_id = nrow(graph$graph_log) + 1L,
function_used = fcn_name,
time_modified = time_function_start,
duration = graph_function_duration(time_function_start),
nodes = nrow(graph$nodes_df),
edges = nrow(graph$edges_df),
d_n = 1,
d_e = length(from) + length(to))
# Perform graph actions, if any are available
if (nrow(graph$graph_actions) > 0) {
graph <-
trigger_graph_actions(graph)
}
# Write graph backup if the option is set
if (graph$graph_info$write_backups) {
save_graph_as_rds(graph = graph)
}
return(graph)
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.