Modification

What's a graph library without the ability to modify the graph? The functions presented herein are all about changing the graph in specific ways. Whether it's adding a node here, an edge there, or deleting a whole swath of nodes, this sort of functionality is important.

Adding a Node or Edge to a Graph

The add_node() and add_edge() functions provide a facility for adding a single node or edge to an existing graph. Although you may prepare node data frames (NDFs) or edge data frames (EDFs) and incorporate those into a new graph object with the create_graph() function, there may be new nodes or edges to add after creation of the graph object (say, as new data becomes available). After calling either of these functions, the new node or edge becomes part of the graph's internal NDF or EDF, respectively.

The add_node() function allows one to add a single node to a graph. Specify the graph to which the node should be added and the node ID for the node argument, and a node will be added. While the other arguments are optional, using just graph and node will result in the addition of an unconnected node. This might be desirable (say, if the graph is empty), but the more likely case is that edges to other nodes will be required upon addition of a new node. The from and to arguments (both optional) are where you would specify connections from existing nodes to the new node (with to), and connections to existing nodes from the new node (with from). A vector of node IDs can be supplied to either argument. The label and type arguments allow for direct setting of these node attributes during the addition of a node. Finally, a named vector of node attributes and their values can be included in the add_node() call.

The add_edge() function is meant for adding an edge between two extant graph nodes. Because the nodes must exist in the graph, this function cannot be invoked for an empty graph. (It can, however, be used for a graph with a single node since an edge can be created as a loop from and to the same node.) The basic means to add an edge to a graph with this function is to specify from and to nodes for the edge to be added. One can optionally add an edge rel string as a value for the rel argument.

###
# Add single nodes and edges
# with the `add_node()` and
# `add_edge()` functions
###

library(DiagrammeR)
library(magrittr)

# Create an empty graph
graph <- create_graph()

# Add two nodes, they will be
# given ID values that are
# monotonically increasing from `1`
graph <- add_node(graph)
graph <- add_node(graph)

# Get the node ID values
get_nodes(graph)
#> [1] "1" "2"

# Show the graph's internal NDF
get_node_df(graph)
#>   nodes   type label
#> 1     1            1
#> 2     2            2

# Create the same graph with
# magrittr `%>%` pipes
graph <-
  create_graph() %>%
  add_node %>%
  add_node

# Show the graph's internal NDF
get_node_df(graph)
#>   nodes   type label
#> 1     1            1
#> 2     2            2

# Add an edge between the two nodes
graph <-
  graph %>%
  add_edge(1, 2)

# Show the graph's internal EDF
get_edge_df(graph)
#>   from to rel
#> 1    1  2    

Adding an NDF or EDF to a Graph

So long as you are careful not to introduce nodes with duplicate ID values, you can add a node data frame (NDF) to existing graph. You can also add an edge data frame (EDF) to an existing graph. This can be done upon creation of the graph using the create_graph() function, however, these it can be useful to add collections of nodes or edges as NDFs or EDFs, perhaps whenever new data is available for the graph.

###
# Add several nodes and
# edges to the graph in the
# form of NDFs and EDFs
###

library(DiagrammeR)

# Create an empty graph
graph <- create_graph()

# Create a node data frame
nodes <-
  create_nodes(
    nodes = 1:4,
    type = "a",
    color = c("red", "green",
              "grey", "blue"),
    value = c(3.5, 2.6, 9.4, 2.7))

# Add the node data frame to the
# graph object to create a graph
# with nodes
graph <-
  add_node_df(graph = graph,
              node_df = nodes)

get_node_df(graph)
#>   nodes type label color value
#> 1     1    a     1   red   3.5
#> 2     2    a     2 green   2.6
#> 3     3    a     3  grey   9.4
#> 4     4    a     4  blue   2.7

# Create another node data frame
nodes_2 <-
  create_nodes(
    nodes = 5:8,
    type = "b",
    color = c("orange", "brown",
              "aqua", "pink"),
    value = c(1.6, 6.4, 0.8, 4.2))

# Add the second node data frame
# to the graph object to add more
# nodes with attributes to the
# graph
graph <-
  add_node_df(
    graph = graph,
    node_df = nodes_2)

# Check the graph's internal
# NDF to see that the two NDFs
# were added
get_node_df(graph)
#>   nodes type label  color value
#> 1     1    a     1    red   3.5
#> 2     2    a     2  green   2.6
#> 3     3    a     3   grey   9.4
#> 4     4    a     4   blue   2.7
#> 5     5    b     5 orange   1.6
#> 6     6    b     6  brown   6.4
#> 7     7    b     7   aqua   0.8
#> 8     8    b     8   pink   4.2

# Create edges by first specifying
# `from` to `to` vectors of node
# ID values
from <-
  c(1, 3, 5, 2, 3, 5, 2, 5, 3)

to <-
  c(3, 6, 2, 7, 8, 7, 4, 4, 5)

# Create the EDF
edges <-
  create_edges(
    from = from,
    to = to,
    rel = "toward")

# Add the EDF to the graph
graph <-
  add_edge_df(
    graph,
    edge_df = edges)

# Check the graph's internal
# EDF to see that the EDF
# was indeed added
get_edge_df(graph)
#>   from to    rel
#> 1    1  3 toward
#> 2    3  6 toward
#> 3    5  2 toward
#> 4    2  7 toward
#> 5    3  8 toward
#> 6    5  7 toward
#> 7    2  4 toward
#> 8    5  4 toward
#> 9    3  5 toward

# View the graph
render_graph(graph)


Adding Several New Nodes or Edges to a Graph

There may be times when the addition of many individual nodes or edges is desired. Add a multiple of new nodes to the graph in a single function call with the add_n_nodes() function. Or, add several edges using a string representation with add_edges_w_string().

When adding nodes with add_n_nodes(), the argument n is for the number of new nodes to add to the graph, so, supply an integer that is greater than or equal to 1. Optionally, set node type values for the new nodes (this is important for creating property graphs). The set_node_type argument takes an optional string for applying a single type attribute to all the newly created nodes.

###
# Add several nodes with different
# `type` attributes to the graph
# with the `add_n_nodes()`
# functions
###

library(DiagrammeR)
library(magrittr)

# Add 20 nodes to an empty graph
create_graph(
  graph_attrs = "output = visNetwork") %>%
  add_n_nodes(20) %>%
  render_graph



# Add 20 nodes of 4 different types to
# an empty graph and then create edges
# between them
create_graph(
  graph_attrs = "output = visNetwork") %>%
  add_n_nodes(5, "A") %>%
  add_n_nodes(5, "B") %>%
  add_n_nodes(5, "C") %>%
  add_n_nodes(5, "D") %>%
  add_edge_df(create_edges(1:19, 2:20)) %>%
  render_graph


The add_edges_w_string() function provides an easy way to declare edges between nodes, provided that the node IDs are known in advance. The edges argument is supplied with a string that defines edges between the nodes' IDs. If the graph is directed, then the format is [ID]->[ID] [ID]->[ID] .... If the graph is undirected then -> should be replaced by --. The rel argument provides an option to set a common edge rel value for all the edges created (again, could be important for creating property graphs).

###
# Add several nodes of different
# types and add edges between the
# nodes with `add_edges_w_string()`
###

library(DiagrammeR)
library(magrittr)

# Add 12 nodes to an empty graph and
# then create edges between all nodes
create_graph(
  graph_attrs = "output = visNetwork") %>%
  add_n_nodes(4, "A") %>%
  add_n_nodes(4, "B") %>%
  add_n_nodes(4, "C") %>%
  add_edges_w_string(
    "1->6 2->10 5->8 9->2", "X") %>%
  add_edges_w_string(
    "3->7 6->2 11->5 12->2", "Y") %>%
  add_edges_w_string(
    "4->8 9->4 7->9 10->1", "Z") %>%
  render_graph

Adding Several New Nodes to or from a Selection of Nodes

Add a number of nodes to the graph by attaching them to or from a selection of nodes with add_n_nodes_ws(). The nodes created can be assigned a common value for their type attribute.

It's occasionally convenient to select one or more nodes and then add several nodes to or from them. Any use of add_n_nodes_ws() requires a selection of one or more nodes in the graph (all functions ending with _ws indicate the use of a node or edge selection). This selection of nodes can be made with a variety of node selection functions (e.g., select_nodes(), select_nodes_by_degree(), etc.) or through a traversal function (e.g., trav_out, trav_in_node, etc.). The direction in which edges travel is specified in the direction argument. Using from will direct the edges from the selected node(s) to the new nodes. With from, edges will be made in the the opposite direction.

This function has set_node_type and set_edge_rel arguments, which allow you to optionally provide a common value for either the node type or for the edge rel type for all new nodes and edges created through this function call.

###
# Add several nodes with different
# `type` attributes to the graph
# with `add_n_nodes_ws()`
###

library(DiagrammeR)
library(magrittr)

# Create a graph with a central
# node and multiples of children nodes
create_graph(
  graph_attrs = "output = visNetwork") %>%
  add_node("A") %>%
  select_nodes %>%
  add_n_nodes_ws(3, "from", "B") %>%
  clear_selection %>%
  select_nodes("type", "B") %>%
  add_n_nodes_ws(3, "from", "C") %>%
  clear_selection %>%
  select_nodes("type", "C") %>%
  add_n_nodes_ws(3, "from", "D") %>%
  render_graph



# Create a graph with two central
# nodes with a high indegree and
# outdegree
create_graph(
  graph_attrs = "output = visNetwork") %>%
  add_n_nodes(2, "A") %>%
  add_edge(1, 2) %>%
  select_nodes_by_id(1) %>%
  add_n_nodes_ws(10, "to", "B") %>%
  clear_selection %>%
  select_nodes_by_id(2) %>%
  add_n_nodes_ws(10, "from", "C") %>%
  render_graph



# Create a graph in the same
# manner but add relationships
# and other attributes
create_graph(
  graph_attrs = "output = visNetwork") %>%
  add_n_nodes(1, "A") %>%
  select_last_node %>%
  set_node_attrs_ws("value", 5) %>%
  add_n_nodes_ws(3, "to", "B", "toward") %>%
  clear_selection %>%
  select_nodes("type", "B") %>%
  set_node_attrs_ws("value", 4) %>%
  add_n_nodes_ws(3, "from", "C", "away") %>%
  clear_selection %>%
  select_nodes("type", "C") %>%
  set_node_attrs_ws("value", 3) %>%
  add_n_nodes_ws(5, "to", "D", "toward") %>%
  select_nodes("type", "D") %>%
  set_node_attrs_ws("value", 2) %>%
  render_graph

Adding Nodes or Edges from a Table


Deleting a Node or Edge from a Table

Graphs can undergo all sorts of modifications, and this includes the removal of nodes or edges. The delete_node() and delete_edge() functions allow for the removal of single nodes or edges. Also, when deleting a node that has edges, those edge definitions will also be removed.

The function delete_node() removes a single node from the graph. The functions expects a node ID value to uniquely identify the node to be deleted. As the function can only delete a single node per call, supply only a single node ID to the node argument. All of the removed node's edges with other nodes in the graph will also be removed in this operation.

###
# Delete specific nodes
# from the graph using
# `delete_node()`
###

library(DiagrammeR)
library(magrittr)

# Create a graph with a central
# node and multiples of children nodes
graph <-
create_graph(graph_attrs =
               "output = visNetwork") %>%
  add_n_nodes(1, "A") %>%
  select_nodes %>%
  add_n_nodes_ws(3, "B") %>%
  clear_selection %>%
  select_nodes("type", "B") %>%
  add_n_nodes_ws(3, "C")

# View the graph
graph %>% render_graph



# Remove the central node (`1`) by
# specifying the node ID directly
graph_delete_node_1 <-
  graph %>% delete_node(1)

# View the modified graph
graph_delete_node_1 %>% render_graph



# Remove the first (and only) node
# with `type = A` from the graph
# (this is node `1`, as before)
graph_delete_node_2 <-
  graph %>%
  delete_node(
    get_nodes(., "type", "A")[1])

# Inspect a list of nodes to
# ensure that node `1` has been
# removed
get_nodes(graph_delete_node_2)
#> [1] "2"  "3"  "4"  "5"  "6"
#> [6] "7"  "8"  "9"  "10"
#> [10] "11"  "12"  "13"

# Also, edges were removed from
# this node removal; check that
# there are no edges from or to
# node `1`
graph_delete_node_2 %>%
  get_edges %>%
  {
    from <- .[[1]]
    to <- .[[2]]
    nodes_in_edges <- c(from, to)
  } %>% is_in(1, .)
#> [1] FALSE

The function delete_edge() removes a single edge from the graph. Specify the graph object in graph, the nodes in from and to, and the edge will removed if it exists.

###
# Delete specific edges
# from the graph using
# `delete_edge()`
###

library(DiagrammeR)
library(magrittr)

# Create a graph with a central
# node and multiples of children nodes;
# this is the same graph as in the
# previous example
graph <-
create_graph(
  graph_attrs = "output = visNetwork") %>%
  add_n_nodes(1, "A") %>%
  select_nodes %>%
  add_n_nodes_ws(3, "from", "B") %>%
  clear_selection %>%
  select_nodes("type", "B") %>%
  add_n_nodes_ws(3, "from", "C")

# Remove the several edges by
# specifying the node ID values
# that make up those edges
graph_delete_edges <-
  graph %>%
  delete_edge(1, 2) %>%
  delete_edge(1, 3) %>%
  delete_edge(1, 4)

graph_delete_edges %>% render_graph


Deleting Nodes or Edges Using a Selection

While the removal of several nodes or several edges can be performed with multiple statements using the delete_node() and delete_edge() functions, an often more desirable solution for greater removals is to create a selection of nodes or edges and delete the members with such selections. The latter strategy can be accomplished with the delete_nodes_ws() and delete_edges_ws() functions.

These functions only require a graph object with some selection of nodes or edges already set within the object. Recall that selections of nodes or edges can be made with a number of different functions (e.g., select_nodes(), select_edges(), select_nodes_by_id(), select_edges_by_node_id(), etc.). The following examples demonstrate how multiple nodes or edges can be removed by using a selection then invocation of either of these functions.

###
# Delete a number of nodes
# from the graph by making
# a selection and then using
# `delete_nodes_ws()`
###

library(DiagrammeR)
library(magrittr)

# Create a random graph with 150
# nodes and 180 edges
graph <-
  create_random_graph(
    150, 180,
    directed = TRUE,
    fully_connected = TRUE,
    set_seed = 20) %>%
  set_global_graph_attrs(
    "graph", "output", "visNetwork")

# Set a random seed
set.seed(20)

# Randomly assign node `type` values
# of `1`, `2`, `3`, `4`, and `5` to
# each of the graph's nodes
for (i in 1:node_count(graph)) {
  graph %<>%
    node_type(
      i, action = "add",
      sample(1:5, 1))
}

# View this new graph; differently
# colored nodes are those with
# different `type` values
graph %>% render_graph


# A table of counts by node
# `type` can be displayed
graph %>% node_count(type = TRUE)
#>  5  4  2  3  1
#> 38 19 24 33 36

# Create a selection of nodes to
# mark them for deletion; first,
# select all nodes and delete all
# of them from the graph
graph_emptied <-
  graph %>%
  select_nodes %>%
  delete_nodes_ws

# Ensure that the graph is empty
node_count(graph_emptied)
#> [1] 0

# Try a different type of
# selection that deletes all
# nodes corresponding to types
# `1` and `5`
graph_1_5_removed <-
  graph %>%
  select_nodes("type", 1) %>%
  select_nodes("type", 5) %>%
  delete_nodes_ws

graph_1_5_removed %>%
  node_count(type = TRUE)

# Ensure that nodes of types
# `1` and `5` are no longer
# in the graph
graph_1_5_removed %>%
  node_count(type = TRUE)
#>  4  2  3
#> 19 24 33

# View the modified graph, it
# looks a lot simpler now!
graph_1_5_removed %>%
  render_graph


# Try yet another type of mass
# deletion where edges are retained
# on the basis nodes present with
# large numerical data values; free
# nodes are then also removed
graph_large_node_interactions <-
  graph %>%
  select_edges_by_node_id(
    get_nodes(., "value", "<7")) %>%
  delete_edges_ws %>%
  clear_selection %>%
  select_nodes_by_degree("both", 0) %>%
  delete_nodes_ws

# View the revised graph
graph_large_node_interactions %>%
  render_graph


Working with the Node type Attribute

The node_type() function provides several means to check the type attribute for a node and perform different operations on that attribute. The different functionalities of node_type can be changed through the use of these different keywords for the action argument: read, check, add, update, and delete. With read set as the action, a node ID supplied with the graph object yields that node's type attribute. Using action = check with a node ID, you can check whether a type attribute exists (it will return TRUE or FALSE. If the type attribute hasn't been set for a node, you can add that using action = add along with a string supplied for the value argument. If a type attribute has alredy been set for a node and you'd like to change it, use action = update and include the updated string with the value argument. Deleting a type attribute for a node is easily accomplished by using action = delete.

###
# Use the `node_type()`
# function to inspect and to
# make several modifications
# to a node's `type` value
###

library(DiagrammeR)
library(magrittr)

# Create a simple NDF
nodes <-
  create_nodes(
    nodes = 1:4,
    type = c("1st", "2nd",
             "3rd", "4th"))

# Create the graph object using
# the NDF
graph <-
  create_graph(nodes_df = nodes)

# Read the node `type` attributes
graph %>% node_type(1, "read")
#> [1] "1st"

graph %>% node_type(2, "read")
#> [1] "2nd"

graph %>% node_type(3, "read")
#> [1] "3rd"

graph %>% node_type(4, "read")
#> [1] "4th"

# Get all the node types into
# a vector object
all_types <-
  graph %>%
  {
    node_types <-
      sapply(1:node_count(.),
             function(x)
             {node_type(., x,
                        "read")})
  }

# What can you expect if the node
# ID provided doesn't match belong
# to any node in the graph? (An error.)
graph %>%
  node_type(5, "read")
# --------------------------------------------------------
# Error in node_type(., 5, "read") :
#   The specified node is not present in the graph.
# --------------------------------------------------------

# Remove a type assigned to node
# `4` using either of three
# keywords: `delete`, `remove`,
# or `drop`
graph %<>%
  node_type(4, "delete")

# Now that node doesn't have a
# `type` value; it yields an
# NA when queried about that
graph %>%
  node_type(4, "read")
#> [1] NA

# Add back the type assigned to
# node `4` using either of two
# keywords: `add` or `create`
graph %<>%
  node_type(4, "add", "fourth")

# Add a node to the graph; the
# new node is added without a
# `type` value assigned
graph %<>% add_node

# Expect a value of FALSE when
# checking whether node `5` (just
# added) has a `type` value
# assigned
graph %>%
  node_type(5, "check")
#> [1] FALSE

# When trying to remove a `type`
# for a node where no type value
# is set, there won't be an
# error, and, the graph won't
# change
graph_no_change_1 <-
  graph %>%
  node_type(5, "delete")

graph_no_change_1 %>%
  node_type(5, "read")
#> [1] NA

# Attempt to add a `type` value
# for a node where a `type` value
# is already set; the value
# won't change (need to use the
# `update` mode)
graph_no_change_2 <-
  graph %>%
  node_type(1, "add", "first")

graph_no_change_2 %>%
  node_type(1, "read")
#> [1] "1st"

# Using `update` results in the
# modification of the `type`
# value, for reals...
graph %<>%
  node_type(1, "update", "first")

# ...but use `read` to be sure
graph %>%
  node_type(1, "read")
#> [1] "first"

Working with the Edge rel Attribute

The edge_rel() function is similar in principle and use to the node_type() function. In this function, the edges' rel attribute can be checked for existence, added, removed, or updated. As with the node_type() function, this function uses the action argument and performs various actions with these keywords: read, check, add, update, and delete (same keywords as those for node_type()). Using read, supply node IDs for the from and to arguments. With that, you will receive the edge's currently set rel attribute. The rel attribute may or may not be set, so, using action = check with a specified edge, the existence of the rel attribute can be verified through a TRUE or FALSE return value. An unset rel attribute for an edge can be set by using action = add and a character string for the value argument. To update an already set rel attribute for an edge, use action = update and provide the updated relationship string with the value argument. Deleting a rel attribute for an edge is done by using action = delete with an edge.

###
# Use the `edge_rel()`
# function to inspect and to
# make several modifications
# to an edge's `rel` value
###

library(DiagrammeR)
library(magrittr)

# Create a simple NDF
nodes <-
  create_nodes(
    nodes = 1:4,
    type = c("1st", "2nd",
             "3rd", "4th"))

# Create a simple EDF
edges <-
  create_edges(
    from = c(1, 2, 3),
    to = c(4, 3, 1),
    rel = c("relates_to",
            "did_with",
            "relates_with"))

# Create the graph object using
# the NDF and the EDF
graph <-
  create_graph(
    nodes_df = nodes,
    edges_df = edges)

# Using a `read` action on an
# edge with a relationship set
# will return the relationship
# label
graph %>%
  edge_rel(1, 4, "read")
#> [1] "relates_to"

# Using a `read` action on an
# edge relationship for an
# edge that doesn't exist will
# throw an error
graph %>%
  edge_rel(1, 2, "read")
# --------------------------------------------------------
# Error in edge_rel(., 1, 2, "read") :
#   The specified edge is not present in the graph.
# --------------------------------------------------------

# Remove the edge rel across
# the `1`->`4` edge using the
# `delete` action (synonymous
# with `remove` and `drop`)
graph %<>%
  edge_rel(1, 4, "delete")

# Check that the relationship
# value has been removed
# (FALSE value indidcates there
# is no `rel` set for this edge)
graph %>%
  edge_rel(1, 4, "check")
#> [1] FALSE

# Using the `read` action will
# return an NA for the same
# reason
graph %>%
  edge_rel(1, 4, "read")
#> [1] NA

# Attempting to remove the same
# edge `rel` value won't throw
# an error and the graph won't
# change
graph %<>%
  edge_rel(1, 4, "delete")

# Add a new edge `rel` value
# across the `1`->`4` edge using
# the `add` action
graph %<>%
  edge_rel(
    1, 4, "add", "relates_to")

# If you'd like to change the
# `rel` value for the `1`->`4`
# edge, use the `update` action
# (`add` only works for those
# edges where `rel` is not set)
graph %<>%
  edge_rel(
    1, 4, "update", "did_with")

# Check that the `rel` value for
# the `1`->`4` edge has been set
graph %>%
  edge_rel(1, 4, "read")
#> [1] "did_with"

Creating a Subgraph

A subgraph is a distinct graph composed of a subset of node and edges from another graph. Creating a subgraph in DiagrammeR is done by first creating a selection of nodes or edges and then invoking the create_subgraph_ws() function.

The following example demonstrates how a selection of nodes based on their type values (using select_nodes()) and the subsequent creation of subgraphs can allow for a more focussed view of a larger graph.

###
# Create a graph, and create
# subgraphs based on both
# selections of nodes and
# selections of edges
###

library(DiagrammeR)
library(magrittr)

# Create a random graph with 120 nodes
# and 145 edges
graph <-
  create_random_graph(
    120, 145,
    directed = TRUE,
    fully_connected = TRUE,
    set_seed = 20) %>%
  set_global_graph_attrs(
    "graph", "output", "visNetwork")

# Randomly assign node `type` values
# of `A`, `B`, `C`, and `D` to each
# of the graph's nodes
for (i in 1:node_count(graph)) {
  graph %<>%
    node_type(
      i, action = "add",
      sample(LETTERS[1:4], 1))
}

# View this new graph; differently
# colored nodes are those with different
# `type` values
graph %>% render_graph


# Create a subgraph solely with nodes
# where `type` is `A` and any edges
# are between nodes of the same type
subgraph_a_nodes <-
  graph %>%
  select_nodes("type", "A") %>%
  create_subgraph_ws

# View the subgraph after coloring
# all nodes `lightgray`
subgraph_a_nodes %>%
select_nodes %>%
  set_node_attrs_ws(
    "color", "lightgray") %>%
  render_graph


# Create subgraphs of all node types
# and place them into a graph series
subgraphs <-
  create_series(series_name = "subgraphs")

for (i in 1:4) {
  subgraphs <-
    graph %>%
    select_nodes("type", LETTERS[i]) %>%
    create_subgraph_ws %>%
    set_graph_name(LETTERS[i]) %>%
    add_to_series(series_of_subgraphs)
}

# With `series_info()`, you can get basic
# info about which graphs are in the series
series_info(subgraphs)
#>   graph name date_time   tz nodes edges directed
#> 1     1    A      <NA> <NA>    33    10     TRUE
#> 2     2    B      <NA> <NA>    28     6     TRUE
#> 3     3    C      <NA> <NA>    32    13     TRUE
#> 4     4    D      <NA> <NA>    27     8     TRUE

# You can any of the subgraphs with the
# `render_graph_from_series()` function

render_graph_from_series(subgraphs, 1)
render_graph_from_series(subgraphs, 2)
render_graph_from_series(subgraphs, 3)
render_graph_from_series(subgraphs, 4)


Also possible is the creation of a subgraph based on a selection of edges.

###
# Create a graph, and create
# subgraphs based on both
# selections of nodes and
# selections of edges
###

library(DiagrammeR)
library(magrittr)

# Create the same random graph
# as in the previous example
# (120 nodes and 145 edges)
graph <-
  create_random_graph(
    120, 145,
    directed = TRUE,
    fully_connected = TRUE,
    set_seed = 20) %>%
  set_global_graph_attrs(
    "graph", "output", "visNetwork")

# Randomly assign node `type` values
# of `A`, `B`, `C`, and `D` to each
# of the graph's nodes
for (i in 1:node_count(graph)) {
  graph %<>%
    node_type(
      i, action = "add",
      sample(LETTERS[1:4], 1))
}

# View the subgraph; the blue nodes
# those with `type` values of `A`
graph %>% render_graph


Setting a Graph's Name and Time Attributes

Setting the graph's name and time attributes can be useful when there is a collection of graphs and such properties can help when distinguishing the graph objects. The functions that deal with graph series objects can take advantage of any graph names and graph date-time values that are available. The create_graph() function affords the option to set these parameters upon graph creation, however, the set_graph_name() and set_graph_time provide additional opportunities to add, modify, or remove such attributes.

The set_graph_name() function takes a graph object and a value for the graph_name (this can be provided as numeric value but will be coerced to a character value. The same function can set a graph's name (changing from the default NULL) and also modify a graph's name (replacing the value).

###
# Set the graph's name, then
# modify the name
###

library(DiagrammeR)
library(magrittr)

# Create an empty graph
graph <- create_graph()

# Set the graph's name
graph %<>% set_graph_name("nice_graph")

# Check the name of the graph
graph$graph_name
#> [1] "nice_graph"

# Change the graph's name
graph %<>% set_graph_name(1)

# Verify that the name has changed
graph$graph_name
#> [1] "1"

The set_graph_time() function can be provided with a date or date-time string (for the graph_time argument). This will be useful if the graph is to be inserted into a graph series of the temporal type. An optional value for the time zone (tz) corresponding to the date or date-time string supplied as a value to graph_time. If no time zone is provided then it will be implicitly set to GMT.

###
# Set the graph's date/time value,
# then modify the these properties
###

library(DiagrammeR)
library(magrittr)

# Create an empty graph
graph <- create_graph()

# Set the graph's time attribute with
# a well-formed date ("YYYY-MM-DD")
graph %<>% set_graph_time("2015-01-30")

# Check the `graph_time` attribute
graph$graph_time
#> [1] "2015-01-30"

# Note that since the time zone was
# not provided, the default is `GMT`
graph$graph_tz
#> [1] "GMT"

# I'll update the `graph_time`
# attribute with an actual
# timestamp (i.e., date + time) and
# a time zone
graph %<>%
  set_graph_time(
    "2015-01-30 15:26:54",
    "Pacific/Pago_Pago")

# Let's check both the time and
# the time zone set for the graph
c(graph$graph_time,
  graph$graph_tz)
#> [1] "2015-01-30 15:26:54"
#> [2] "Pacific/Pago_Pago"

Setting Global Attributes for a Graph


Setting Node or Edge Attributes

Once a node or edge is in the graph, there are still opportunities to add or modify node or edge attribute values. There are four functions that help with this sort of task: set_node_attrs(), set_edge_attrs(), set_node_attrs_ws(), and set_edge_attrs_ws().

When adding or modifying node attributes, you can target all the nodes at once (using set_node_attrs() with no values provided to the nodes argument). Specific nodes can be targeted by providing a vector of node ID values to the nodes argument of the set_node_attrs() function or by creating a selection of nodes (using select_nodes(), select_nodes_by_id(), select_nodes_by_degree(), etc.) and using the set_node_attrs_ws() function. Similarly, for additions or modifications of edge attributes, the set_edge_attrs() and set_edge_attrs_ws() are used in the same manner.

###
# Create a simple graph then
# set and modify several of
# the nodes' attributes
###

library(DiagrammeR)
library(magrittr)

# Create a random graph of
# 80 nodes, 140 edges
graph <-
  create_random_graph(
    80, 140,
    directed = TRUE,
    fully_connected = TRUE,
    set_seed = 25) %>%
  set_global_graph_attrs(
    "graph", "output", "visNetwork")

# View the initial graph
graph %>% render_graph


# Create new node attributes and
# modify existing node attributes
graph_modified_node_attrs <-
  graph %>%
  set_node_attrs(
    get_nodes(.), "type", "A") %>%
  set_node_attrs(
    c(1, 2, 3), "type", "B") %>%
  set_node_attrs(
    c(1, 2, 3), "value", 50) %>%
  render_graph

# View the modified graph
graph_modified_node_attrs %>%
  render_graph


Rescaling Node and Edge Attributes

Mainly for purposes of scaling data values to values supplied to aesthetics, the rescale_node_attrs_ws() and rescale_edge_attrs_ws() functions are available. Both allow for rescaling continuous numeric values to another set of numeric values or to a color range.