Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add <epiparameter> diagram to design principles vignette #383

Merged
merged 8 commits into from
Oct 7, 2024
6 changes: 4 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,20 @@ Suggests:
bookdown,
DT,
ggplot2,
RColorBrewer,
jsonlite,
knitr,
rmarkdown,
spelling,
testthat (>= 3.0.0),
vdiffr (>= 1.0.7)
vdiffr (>= 1.0.7),
visNetwork
VignetteBuilder:
knitr
Config/Needs/check: mrc-ide/epireview
Config/Needs/website: epiverse-trace/epiversetheme, mrc-ide/epireview
Config/testthat/edition: 3
Config/potools/style: explicit
Config/testthat/edition: 3
Encoding: UTF-8
Language: en-GB
LazyData: true
Expand Down
102 changes: 102 additions & 0 deletions vignettes/design_principles.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,108 @@ The output of the `epiparameter()` constructor function is an `<epiparameter>` o

Other functions return the simplest type possible, this may be an atomic vector (including single element vectors), or un-nested lists.

## Package architecture

Much of the {epiparameter} package is centred around the `<epiparameter>` class. Here is a diagram showing the class with it's S3 methods (the diagram below is interactive so can adjusted if labels are overlapping).

```{r, echo=FALSE, fig.width=8, fig.height=5}
# read NAMESPACE
namespace <- base::parseNamespaceFile("epiparameter", .libPaths()[1L]) # nolint: undesirable_function_linter
s3methods <- namespace$S3methods
epiparameter_class_methods <-
s3methods[which(s3methods[, 2] == "epiparameter"), 1]

# create network with all methods around the central node
getters <- c("family()", "get_citation()", "get_parameters()")
modifiers <- c("discretise()", "as.function()")
distribution_functions <- c("cdf()", "density()", "generate()", "quantile()")
utilities <- c("print()", "plot()", "mean()", "c()", "format()")
checkers <- c("is_epiparameter()", "is_parameterised()", "is_truncated()")
conversions <- c(
"convert_params_to_summary_stats()", "convert_summary_stats_to_params()"
)
coercion <- "as.data.frame()"

# add one to each for the intermediate group nodes
groups <- data.frame(
group = c(
rep("Getters", length(getters) + 1),
rep("Modifiers", length(modifiers) + 1),
rep("Distribution functions", length(distribution_functions) + 1),
rep("Utilities", length(utilities) + 1),
rep("Checkers", length(checkers) + 1),
rep("Conversions", length(conversions) + 1),
rep("Coercion", length(coercion) + 1)
),
functions = c(
c("Getters", getters),
c("Modifiers", modifiers),
c("Distribution functions", distribution_functions),
c("Utilities", utilities),
c("Checkers", checkers),
c("Conversions", conversions),
c("Coercion", coercion)
)
)

nodes <- data.frame(
id = seq_len(nrow(groups) + 1),
group = c("<epiparameter>", groups$group),
label = c("<epiparameter>", groups$functions),
shape = "box",
stringsAsFactors = FALSE
)

from <- seq_len(nrow(groups))

# plus one for the central node
to <- 2:(nrow(groups) + 2)

for (grp in unique(groups$group)) {
# plus one for central node
from[which(groups$group == grp) + 1] <- min(which(groups$group == grp)) + 1
}

# set intermediate nodes to connect to central node
from[groups$group == groups$functions] <- 1

edges <- data.frame(
from = from,
to = to,
color = "black",
stringsAsFactors = FALSE
)

colours <- RColorBrewer::brewer.pal(
n = length(unique(nodes$group)),
name = "Set3"
)

# functions from parseNamespaceFile() need parentheses to match formatting
epiparameter_class_methods <- paste0(epiparameter_class_methods, "()")
if (!all(epiparameter_class_methods %in% groups$functions)) {
message(
"This diagram is out of date, as new methods have been added to the ",
"package which are not included."
)
}

library(visNetwork)
visNetwork(nodes, edges) |>
visNodes(font = list(size = 18)) |>
visGroups(groupname = "<epiparameter>", color = colours[1]) |>
visGroups(groupname = "Getters", color = colours[2]) |>
visGroups(groupname = "Modifiers", color = colours[3]) |>
visGroups(
groupname = "Distribution functions",
color = colours[4]
) |>
visGroups(groupname = "Utilities", color = colours[5]) |>
visGroups(groupname = "Checkers", color = colours[6]) |>
visGroups(groupname = "Conversions", color = colours[7]) |>
visGroups(groupname = "Coercion", color = colours[8])
```

## Design decisions

* The `<epiparameter>` class is designed to be a core unit for working with epidemiological parameters. It is designed in parallel to other epidemiological data structures such as a the `<contactmatrix>` class from the [{contactmatrix} R package](https://socialcontactdata.github.io/contactmatrix/index.html). The design principles of the `<epiparameter>` class are aligned with the [`<contactmatrix>` design principles](https://socialcontactdata.github.io/contactmatrix/articles/design-principles.html). These include:
Expand Down