-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy path001-creating-a-simple-graph.Rmd
154 lines (113 loc) · 6.22 KB
/
001-creating-a-simple-graph.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
---
title: "001 - Creating a Simple Graph"
output: html_document
---
**DiagrammeR** is all about making it easy to create, modify, and analyze graphs in an **R** environment. When just starting to use the package, it's useful to learn how to generate and view simple graphs. Here, we'll use just a few functions to generate node and edge data frames (i.e. graph building blocks), to create the graph object, and to view the graph.
## Setup
Ensure that the development version of **DiagrammeR** is installed. Load in the package with `library()`. Additionally, load in the **tidyverse** packages.
```{r load_packages, message=FALSE, warning=FALSE, include=FALSE, results=FALSE}
#devtools::install_github("rich-iannone/DiagrammeR")
library(DiagrammeR)
library(tidyverse)
```
## Part 1. Creating a Simple Graph Using Data Frames
For graph diagrams you need nodes and edges. Let's use the `create_node_df()` function to specify a collection of nodes and contain them in a data frame (a node data frame, or ndf). Immediately after that, inspect the node data frame.
```{r create_node_df}
ndf <-
create_node_df(
n = 3,
label = TRUE)
ndf
```
The `n` argument is required here and it must indicate the number of nodes you intend this object to contain. The use of `label = TRUE` allows for copying of the node IDs as the node `label` (which is a node attribute). This is not always desirable, however. A better option is to specify a vector of text labels (you can use all manner of characters), but ensure that this vector is the same length as specified by `n`. If you ensure that the `label` node attribute always contains unique values, later on you can select individual nodes by `label` and perform actions on them.
You may have noticed the node attribute `type` in the output. Values may optionally be provided for this such that the values are useful for categorizing collections of nodes. Let's refine the `ndf` object and include two different `type` values.
```{r create_ndf_type}
ndf <-
create_node_df(
n = 3,
type = c("A", "A", "B"),
label = TRUE)
ndf
```
Now onto the edges, those connections between the nodes. The edge connections are also collected in a data frame (this time, an edge data frame or edf). The `create_edge_df()` function is used to generate this object.
```{r create_edge_df}
edf <-
create_edge_df(
from = c(1, 1),
to = c(2, 3))
edf
```
The `from` and `to` arguments specify which nodes for the edge are outgoing and incoming, respectively. Here, the edges are: `1->2` and `1->3`. For directed graphs, the order is essential. The `rel` argument allows for inclusion of text labels in the same manner as the node `type`. This is useful for targeting specific groups of edges during a selection or traversal. Let's refine the `edf` object and include two different `rel` values.
```{r create_edf_rel}
edf <-
create_edge_df(
from = c(1, 1),
to = c(2, 3),
rel = c("X", "Y"))
edf
```
Now that we have an ndf and an edf, we can now combine those into a graph object.
```{r create_graph}
the_graph <-
create_graph(
nodes_df = ndf,
edges_df = edf)
```
Having a graph object is a great first step and you can do a lot with them (inspect, modify, join with other graph objects, etc.). Whenever you'd like to view the graph, use the `render_graph()` function. There are three renderers for graphs:
### Graphviz
```{r render_graph_graphviz}
# Show the graph using the Graphviz engine
render_graph(graph = the_graph, output = "graph")
```
### visNetwork
```{r render_graph_visnetwork}
# Show the graph using the visNetwork engine
render_graph(graph = the_graph, output = "visNetwork")
```
## Part 2. A Shortcut to the Same Graph
You don't really need to have a node data frame in conjunction with the edge data frame to make a graph object. You can have both, either of them, or neither of them (creating an empty graph). Here is the empty graph case:
```{r create_graph_render}
# Render a just created graph; there aren't
# any nodes for the view should be empty
render_graph(
create_graph())
```
## Part 3. Graph with Nodes but No Edges
We can just display nodes without edges by passing in just a node data frame to the `create_graph()` function. This a reasonable way to initialize a graph and edges between these initial nodes can always be added in later with functions like `add_edges()`, `add_edges_w_string()`, `add_edge_df()`, and `add_edges_from_table()`.
```{r create_graph_just_nodes}
# Create the node data frame
ndf <-
create_node_df(
n = 3,
label = c("A", "B", "C"))
# Use the `create_graph()` function
the_graph <- create_graph(nodes_df = ndf)
# View the graph
render_graph(graph = the_graph)
```
Here is an example with 26 nodes, this time wrapping the `create_nodes()`, `create_graph()`, and `render_graph()` function calls into one big statement. We can provide exactly 26 capital letters as node labels by providing the built-in `LETTERS` vector to `label`.
```{r create_graph_nested_render}
render_graph(
create_graph(
nodes_df =
create_node_df(
n = 26,
label = LETTERS)))
```
Unicode characters can also be used as `label` attribute values:
```{r create_graph_nested_render_unicode}
render_graph(
create_graph(
nodes_df =
create_node_df(
n = 3,
label = c("α", "β", "γ"))))
```
Nesting calls like this becomes less readable with increasing numbers of operations. **DiagrammeR** works very well with the **magrittr** package to allow forward-piping of graph operations with the `%>%` operator. Here is the same set of functions as above, except using `%>%` to chain the operations left to right:
```{r create_graph_render_unicode_magrittr}
create_node_df(
n = 3, label = c("α", "β", "γ")) %>%
create_graph(nodes_df = .) %>%
render_graph()
```
The `.` character in the `create_graph()` statement indicates that the returned output from the previous `create_node_df()` statement should go here. Otherwise, the default behavior is that the output from a statement becomes the value for the first argument (which is often omitted entirely). The functions in **DiagrammeR** are designed to have this forward-pipe pattern work well. With further examples, you'll see how this can make even complicated graph operations easier to compose and to read.