-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpre-release-introduction.Rmd
More file actions
492 lines (365 loc) · 19.6 KB
/
pre-release-introduction.Rmd
File metadata and controls
492 lines (365 loc) · 19.6 KB
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
---
title: "Modelgraph"
subtitle: An R interface for the `tikz` \LaTeX{} package for making compartmental model flow diagrams
author: Éric Marty
header-includes:
- \usepackage{array}
- \tikzstyle{custom}=[fill=white, draw=black]
output:
pdf_document:
latex_engine: xelatex
includes:
in_header: modelgraphs.tex
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = T,
results = "hide")
```
```{css, echo=FALSE}
.body-code {
background-color: white;
}
```
```{r functions, include=FALSE}
source("R/modelgraph.R")
```
# Introduction
Modelgraph is designed to produce flow diagrams for compartmental models, stored as \LaTeX{} code.
As such, Modelgraph works most seamlessly within an Rmarkdown document with PDF output, where the stored \LaTeX{} code can be embedded in the document directly.
However, the \LaTeX{} code can also be saved to a `.tex` file for inclusion elsewhere.
# Installation
*Requires R >= 4.0*
`modelgraph` is under active development. It will eventually be released as an R package.
However, it is possible to use modelgraph now in its current state.
All you need to get started is the R script `R/modelgraph.R` and the LaTeX preamble file
`modelgraphs.tex`.
# Basic setup
Create a Rmarkdown document with PDF output.
In the YAML header of the Rmd document,
include the preamble file `modelgraphs.tex`,
and specify `xelatex` as the latex engine.
Other latex engines may incorrectly render opacity.
\definecolor{shadecolor}{RGB}{250,250,250}
```
output:
pdf_document:
latex_engine: xelatex
includes:
in_header: "modelgraphs.tex"
```
# Build a graph from dataframes of states and flows, using the `modelgraph()` R function.
In the R code, define dataframes of states, flows, and optionally groups.
The `modelgraph()` function takes the dataframes of states, flows and optionally groups of states, and outputs a fragment of \LaTeX{} code as a string. This string can be stored in an R object, and can be rendered in a PDF by using an in-line call to the R object in markdown. The R object can also be output to a `.tex` file.
## The `states` dataframe:
\begin{tabular}{ l l p{12cm} }
\texttt{name} & character & Internal name for the state (node), used when referring to the state in code. \\
\texttt{label} & character & (Optional.) Label for the state (node). May included \LaTeX surrounded by \$~\$.
If ommitted, \texttt{label} = \texttt{name}\\
\texttt{class} & character & (Optional.) One of a set of pre-defined "classes", used to set color of all states (nodes) with that class.\\
\texttt{group} & character & (Optional.) Group to which the state belongs.\\
\texttt{position} & character & (Optional.) Position of the state (node) relative to some other state. (See below)
\end{tabular}
**Labels:** By default, the state name will be used as the label unless a label is supplied. To ensure no label is written at all, use `""` for the label. However, if `class` is `"invisible"`, no label will be printed for the state unless a label is explicitly supplied.
**Classes:** Predefined classes: "susceptible", "exposed", "infectious", "asymptomatic", "diagnosed", "hospitalized", "recovered", "deceased", "population", "environment", "system", "invisible" (useful for drawing flows from untracked states). It is possible to create custom classes with their own visual style. See Section: **Custom classes**, below.
**Groups:** States may be grouped. For example, you may have multiple Infectious states. A box will be drawn around all states of the same group. Group membership may be defined in the `group` column of the `states` dataframe, or as a list of states in the `states` column of the `groups` dataframe (see below). Group membership defined in the `groups` dataframe overrides group memberships in the `states` dataframe.
**Positioning:** By default, each state is drawn to the right of the last state (the previous row in the states dataframe). Explicit positioning of state nodes is specified in teh `position` column using `tikz` commands. For example, `right of=S` or `below left of=R` See <http://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf> for a complete syntax. Any simple linear model can be specified without a position column.
## The `flows` dataframe:
\begin{tabular}{ l l p{10cm} }
\texttt{from} & character & Internal name for the source state (node). \\
\texttt{to} & character & Internal name for the destination state (node). \\
\texttt{label} & character & (Optional.) Label for the flow rate (edge). May include \LaTeX surrounded by \$~\$.\\
\texttt{arrow.properties} & character & (Optional.) Properties of the arrow (edge), separated by commas. (See below.)\\
\texttt{label.properties} & character & (Optional.) Properties of the label (edge label), separated by commas. (See below.)\\
\end{tabular}
**From and to:** Flows (edges) are defined by specifying the `from` and `to` states (nodes).
**Arrows:** By default, flows are drawn as straight arrows are drawn from source to destination states. Arrow styling can be changed by specifying properties as a single string of comma-separated values in the `arrow.properties` column. To produce curved arrows, it is sufficient to specify the exit angle from the source state, and the entry angle from the desintation state, e.g. `out=30, in=150`. Color, line style, thickness, etc. may also be set. See <http://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf> for details.
**Labels:** Labels may be provided, but are not required. Label positioning and styling is passed to `arrow.properties` as a comma-separated string. See <http://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf> for details.
## The `groups` dataframe:
\begin{tabular}{ l l p{12cm} }
\texttt{name} & character & Internal name for the group, used when referring to the state in code. \\
\texttt{label} & character & (Optional.) Label for the group. May include \LaTeX{} surrounded by \$~\$.
If ommitted, \texttt{label} = \texttt{name}\\
\texttt{class} & character & (Optional.) One of a set of pre-defined "classes", used to set color of all states (nodes) with that class.\\
\texttt{states} & list & (Optional.) List containing a character vector of state names belonging to the group, e.g. `list(c("E", "I"))`. If present, this column overrides the `group` column in the `states` dataframe.\\
\end{tabular}
## About \LaTeX{} in labels
\LaTeX{} is allowed in state, flow and group labels. \LaTeX{} must be surrounded with \$ \$, and slashes must be escaped with a second slash. Alternately, surround \LaTeX{} in with \$ \$ and then wrap using the `r"(...)"` raw string mechanism (see `?Quote`).
## Example 1 (minimal example):
\definecolor{shadecolor}{RGB}{248,248,255}
```{r}
states <- data.frame(
name = c("S", "I", "R")
)
flows <- data.frame(
from = c("S", "I"),
to = c("I", "R"),
label = c("$\\beta S I$","$\\gamma I$")
)
# Compile a snipet of LaTeX from the dataframes of states and flows
minimal <- modelgraph(states = states, flows = flows)
```
In the body, use an in-line call to R to reference the object containing the modelgraph \LaTeX{} code. The code will be rendered when the document is knit to PDF.
\definecolor{shadecolor}{RGB}{250,250,250}
```{md, results = "hide"}
`r minimal`
```
`r minimal`
The figure can be resized by wrapping the call in \LaTeX{}. (Use `{\textwidth}` to resize the image to full width, `{.5\textwidth}` for 50\% of full width, etc.):
```{md, results = "hide"}
\resizebox{\textwidth}{!}{`r minimal`}
```
\resizebox{\textwidth}{!}{`r minimal`}
## Example 2:
Here, we use predefined classes to color the states of an SEIRS model.
We also group all states into the group called "N".
The curved arrow from R to S is created by specifying the angle the angle of the path out of R and in to S.
The label for the flow from R to S is moved below the arrow.
\definecolor{shadecolor}{RGB}{248,248,255}
```{r}
states <- data.frame(
name = c("S", "E", "I", "R"),
label = c("$S$", "$E$", "$I$", "$R$"),
class = c("susceptible", "exposed", "infectious", "recovered"),
group = c("N", "N", "N1", "N1"),
position = c("","right of=S", "right of=E", "right of=I")
)
flows <- data.frame(
from = c("S", "E", "I", "R"),
to = c("E", "I", "R", "S"),
label = c("$\\beta S I$","$\\alpha E$", "$\\gamma I$", "$\\omega R$"),
arrow.properties = c("","","","out=-150,in=-30"),
label.properties = c("above","above", "above", "below")
)
groups <- data.frame(
name = c("N", "N1"),
label = c("$N$", "$N1$"),
class = c("population", "population")
)
# Group membership here is defined int he states dataframe. Alternately, group
# pembership could be defined by adding a states column to the group dataframe.
# groups$states <- list(c("S", "E", "I", "R"))
# Compile a snipet of LaTeX from the dataframes of states and flows
SEIRS_modelegraph <- modelgraph(states, flows, groups)
```
\definecolor{shadecolor}{RGB}{250,250,250}
```{md, results = "hide"}
`r SEIRS_modelegraph`
```
`r SEIRS_modelegraph`
# Export the graph as a \TeX{} file (`.tex`)
\definecolor{shadecolor}{RGB}{248,248,255}
```{r}
# Save R object as a `.tex` fragment file
# This file will be have the extension ".tex"
# and can be included in a LaTex or Rmd document
saveModelgraph(SEIRS_modelegraph, "SEIRS_modelegraph")
# # Save R object as a standalone `.tex` file
# This file will be have the extension ".tex"
# and can be included in a LaTex or Rmd document or rendered to PDF directly.
# The page size is cropped to the dimensions of the tikz picture (modelgraph).
saveModelgraph(SEIRS_modelegraph, stem = "SEIRS_modelegraph_standalone", standalone=TRUE)
# Save as `.pdf` file (will also create a standalone .tex file).
# The page size is cropped to the dimensions of the tikz picture (modelgraph).
saveModelgraph(SEIRS_modelegraph, stem = "SEIRS_modelegraph_standalone", format="pdf")
# Save as `.png` file (will also create a standalone .tex file and a .pdf file).
# Default dpi is 300 (sufficient for publication).
saveModelgraph(SEIRS_modelegraph, stem = "SEIRS_modelegraph_standalone", format="png",
dpi = 600)
# Save as `.tiff` file (will also create a standalone .tex file and a .pdf file).
# Default dpi is 300 (PLOS requires dpi in range 300-600).
# Default compression is "LZW" (required by PLOS).
# Compression may be one of "none", "LZW", "PackBits", "RLE", "JPEG", "deflate".
saveModelgraph(SEIRS_modelegraph, stem = "SEIRS_modelegraph_standalone", format="tiff",
dpi = 600, compression = "LZW")
```
# Include a \TeX{} fragment file built with `modelgraphs.tex`:
In the YAML header of the Rmd document, include the preamble file `modelgraphs.tex`:
```
output:
pdf_document:
includes:
in_header: "modelgraphs.tex"
```
In the body of the Rmd document, include the model file using the \LaTeX{} command `\input{file}`:
```
\resizebox{\textwidth}{!}{
\input{stoch-fitting-v1.tex}
}
```
\resizebox{\textwidth}{!}{
\input{stoch-fitting-v1.tex}
}
## Inputting a standalone tex file
```
\resizebox{\textwidth}{!}{
\input{SEIRS_modelegraph_standalone.tex}
}
```
\resizebox{\textwidth}{!}{
\input{SEIRS_modelegraph_standalone.tex}
}
## Inputting a PDF created with `saveModelgraph()`
```
{width=50%}
or `knitr::include_graphics("SEIRS_modelegraph_standalone.pdf")`
```
{width=50%}
{width=50%}
# Visual style
The file `modelgraphs.tex` is a \LaTeX{} preamble file that includes pre-defined TikZ styles for use in making compartmental flow dagrams. The `class` of a state or group is defined in the preable as a TikZ style. Styles are also used to control other aspects of the graph, such as opacity, outlining, positioning, etc.
The modelgraph classes and other styles have been designed with infectious disease modeling semantics in mind.
## Available state and group classes:##
\begin{tabular}{ l l p{12cm} }
\texttt{susceptible} & \textcolor{susceptible.color}{\Huge$\bullet$} Blue \\
\hline
\texttt{exposed} & \textcolor{exposed.color}{\Huge$\bullet$} Yellow \\
\texttt{latent} & \textcolor{latent.color}{\Huge$\bullet$} Yellow \\
\hline
\texttt{infectious} & \textcolor{infectious.color}{\Huge$\bullet$} Red \\
\texttt{infected} & \textcolor{infectious.color}{\Huge$\bullet$} Red \\
\texttt{symptomatic} & \textcolor{infectious.color}{\Huge$\bullet$} Red \\
\texttt{asymptomatic} & \textcolor{infectious.color}{\Huge$\circ$} White with red outline \\
\hline
\texttt{diagnosed} & \textcolor{diagnosed.color}{\Huge$\bullet$} Grey \\
\texttt{hospitalized} & \textcolor{hospitalized.color}{\Huge$\bullet$} Purple \\
\hline
\texttt{recovered} & \textcolor{recovered.color}{\Huge$\bullet$} Green \\
\texttt{removed} & \textcolor{removed.color}{\Huge$\bullet$} Green \\
\hline
\texttt{deceased} & \textcolor{deceased.color}{\Huge$\bullet$} Dark Magenta \\
\hline
\texttt{population} & \textcolor{population.color}{\Huge$\bullet$} Grey \\
\texttt{environment} & \textcolor{environment.color}{\Huge$\bullet$} Purple \\
\texttt{undefined} & \textcolor{black}{\Huge$\circ$} White with black outline. \\
\texttt{system} & White with thick dashed grey outline. \\
\hline
\texttt{invisible} & No circle is drawn. A label may still be drawn if desired.\\
\end{tabular}
Groups are drawn at a lower opacity than states.
Additional "add-on" classes may be used in combination with those above.
\begin{tabular}{ l l p{12cm} }
\texttt{marked} & Outlines the circle in a thick, darker line of the same color.
\end{tabular}
Usage: Combine classes in a comma-separated string.
```{r}
states <- data.frame(name = c("S", "I_undetected", "I_detected"),
label = c("$S$", "$I_u$", "$I_d$"),
class = c("susceptible", "infectious", "infectious, marked")
)
```
# Custom classes and styles
The color of a class can be redefined as by including the following code in the YAML header of the Rmd document.
Fire example to redefine the color of the `hospitalized` class as the hex color #3366FF, include the following command in your YAML header:
```
header-includes:
- \definecolor{hospitalized.color}{HTML}{3366FF}
```
It is possible to create custom classes with manually defined visual styles.
To do this, insert a `\tikzstyle{}` command in the YAML header, under `header-includes`.
For example, to create a custom class called "myclass" which will draw the state as a circle with a red outline and white fill, include the following code in the YAML header of the Rmd document:
```
header-includes:
- \tikzstyle{myclass}=[fill = white, draw = red, draw opacity = 1.0]
```
Predefined classes may also be redefined in the same manner:
```
header-includes:
- \tikzstyle{susceptible}=[fill = white, draw = blue, draw opacity = 1.0]
```
Before defining custom styles or redefining styles you should familiarize yourself with `modelgraphs.tex` to understand how styles interact. See <http://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf> for a complete syntax of tikz styles.
# Build a graph manually:
You still need `modelgraphs.tex` in the YAML header.
In the body of the Rmd document, instead of including a file or using the `modelgraph()` function, you can write \LaTeX{} `tikz` commands directly. See the documentation for TikZ at <http://mirrors.ctan.org/graphics/pgf/base/doc/pgfmanual.pdf> for the exhaustive syntax.
\LaTeX{} code needs to be treated as a "raw character string" by surrounding it with `r"(...)"`, where `...` is the \LaTeX{} code.
Note, this mechanism for quoting raw character strings is only available in R version 4 and later. See `?Quote` for more information. To avoid conficts with strings than might be confused as quote delimiters, the mechanism provides for alternate ways to delimit the quoted strings. Here, for example, we use `r"---(...)---"` to surround the code.
\definecolor{shadecolor}{RGB}{248,248,255}
```{r}
mygraph2 <- r"---(
\begin{tikzpicture}[modelgraph]
% states
\node[susceptible] (X) {$X$};
\node[exposed] (L) [right of=X] {$L$};
\node[infectious] (Y) [right of=L] {$Y$};
\node[hospitalized] (H) [right=6cm of Y] {$H$};
\node[invisible] (Yout) [below of=Y] {};
\node[invisible] (Hout) [below of=H] {};
\node[deceased] (D) [right of=Hout] {$D$};
\node[diagnosed] (Z) [above of=H] {$Z$};
\node[deceased, marked] (Dr) [right of=D] {$D_r$};
\node[hospitalized, marked] (A) [above of=Dr] {$A$};
\node[diagnosed, marked] (Zr) [above of=A] {$Z_r$};
% flows
\path [->]
(X) edge node[above] {infection\\$\frac{\beta_t X Y}{N}$} (L)
(L) edge node[above] {onset of\\transmissibility\\$\eta L$} (Y)
% (Y) edge[invisible] node {$p_{h,t} \gamma Y$\\hospitalization} (H)
(Y) edge[invisible] node
{hospitalization\\
$\left\{
\begin{array}{ c l }
p_{h,t} p_{h,\mathrm{weekend}}\gamma Y, & \textrm{if weekend} \\
p_{h,t} \gamma Y, & \textrm{otherwise}
\end{array}
\right.$}
(H)
(Y) edge[out=30,in=135] node {} (H)
(Y) edge[out=30,in=195] node {} (Z)
(Y) edge[out=30,in=150] node[above = .25cm, near end]
{admissions\\reporting}
(A)
(Y) edge node[left, align=right, near end]
{recovery of undetected infections\\$(1-p_{h,t}) (1-\rho_t) \gamma Y$}
(Yout)
(Y) edge[out=90,in=175] node[above = .25cm]
{detection\\$(1-p_{h,t}) \rho_t \gamma Y$}
(Z)
(Z) edge node[above] {case reporting\\$\gamma_{z,w} Z$} (Zr)
(H) edge node[left, align=right, near end]
{recovery\\$(1-p_d)\gamma_h H$}
(Hout)
(H) edge node[above right, align = left] {death\\$p_d \gamma_h H$} (D)
(D) edge node[above] {death\\reporting\\$\gamma_{d,w} D$} (Dr)
;
% groups
\begin{scope}[on background layer]
\node[nodegroup, diagnosed, fit=(Zr) (A) (Dr),
label={[diagnosed.color]\textsc{reports}}] (reports) {};
\end{scope}
% annotations
\node [grouplabel, above = .55cm, color=susceptible.color]
at (X) {\textsc{susceptible}};
\node [grouplabel, above = 1 cm, color=exposed.color]
at (L) {\textsc{latent}};
\node [grouplabel, above = 1 cm, align = right, color=infectious.color]
at (Y) {\textsc{Infectious}};
\node [grouplabel, right, color=hospitalized.color]
at (H) {\textsc{hospitalized}};
\node [grouplabel, below = 0, color=deceased.color]
at (D) {\textsc{deceased}};
\node [grouplabel, above = .25cm, color=diagnosed.color]
at (Z) {\textsc{diagnosed}};
\node [grouplabel, text width=1in, right = 1, color=diagnosed.color]
at (Zr) {\textsc{case\\reports}};
\node [grouplabel, text width=1in, right = 1, color=hospitalized.color]
at (A) {\textsc{admission\\reports}};
\node [grouplabel, text width=1in, right = 1, color=deceased.color]
at (Dr) {\textsc{death\\reports}};
\end{tikzpicture}
)---"
```
The raw string stored in an R object is rendered using an in-line call to R in the body text, as before.
\definecolor{shadecolor}{RGB}{250,250,250}
```{md, results = "hide"}
\begin{figure}
\resizebox{\textwidth}{!}{
`r mygraph2`
}
\caption{Graph generated from raw TikZ commands}
\end{figure}
```
\begin{figure}
\resizebox{\textwidth}{!}{
`r mygraph2`
}
\caption{Graph generated from raw TikZ commands}
\end{figure}