--- title: "Systematic Reviews" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Systematic Reviews} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} ## Use ragg for better font rendering if available if (requireNamespace("ragg", quietly = TRUE)) { knitr::opts_chunk$set( dev = "ragg_png", fig.retina = 1, collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE, out.width = "100%", dpi = 150 ) } else { knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE, out.width = "100%", dpi = 150 ) } ## Dynamic figure sizing (see enrollment_diagrams vignette for details) .flow_dims <- new.env(parent = emptyenv()) .flow_dims$width <- NULL .flow_dims$height <- NULL knitr::opts_hooks$set(use_rec_dims = function(options) { if (isTRUE(options$use_rec_dims)) { if (!is.null(.flow_dims$width)) options$fig.width <- .flow_dims$width if (!is.null(.flow_dims$height)) options$fig.height <- .flow_dims$height .flow_dims$width <- NULL .flow_dims$height <- NULL } options }) queue_flow <- function(flow, ...) { ## Measure on the same device family that renders the figures (ragg, set ## via dev = "ragg_png" above) so that non-default fonts---whose metrics ## differ between devices---are sized consistently and the canvas is not ## cropped. Falls back to recdims()'s default pdf measurement otherwise. md <- if (requireNamespace("ragg", quietly = TRUE)) { function() { tf <- tempfile(fileext = ".png") ragg::agg_png(tf, width = 10, height = 10, units = "in", res = 150) tf } } else NULL dims <- selecta::recdims(flow, ..., .measure_dev = md) .flow_dims$width <- dims["width"] .flow_dims$height <- dims["height"] invisible(flow) } ``` Systematic reviews and meta-analyses synthesize evidence across multiple studies, requiring a transparent account of the literature search and selection process. The PRISMA 2020 (Preferred Reporting Items for Systematic Reviews and Meta-Analyses) statement prescribes a flow diagram with a distinctive structure: multiple parallel identification streams converge into a single screening flow, with progressive exclusions at each stage. The MOOSE (Meta-analysis of Observational Studies in Epidemiology) guidelines follow a similar pattern for observational evidence synthesis. In `selecta`, systematic review diagrams are built around the following core functions: | Function | Purpose | |:---------|:--------| | `sources()` | Define parallel identification streams (the entry point, replacing `enroll()`) | | `combine()` | Merge streams into a single flow after deduplication | Thus, the systematic review pipeline adheres to the following basic structure: ```{r, eval = FALSE} sources(...) |> phase("Identification") |> combine(label) |> exclude(label, n, reasons) |> phase("Screening") |> exclude(label, n) |> phase("Included") |> endpoint(label) |> flowchart() ``` where `sources()` is the entry point, and `combine()` merges parallel columns into a single downstream flow. This vignette demonstrates the full range of systematic review diagrams supported by `selecta`. > *n.b.:* To ensure correct font rendering and figure sizing, the diagrams below are displayed using a vignette-only helper function (`queue_flow()`) that applies recommended dimensions from `recdims()` via the [`ragg`](https://ragg.r-lib.org/) graphics device, with the standard output function applied afterwards (`flowchart()`). In practice, replace this `queue_flow()`/`flowchart()` workflow with a call to `flowsave()` for equivalent printed results: > > ```{r, eval = FALSE} > flowsave(flow, "consort.pdf") > flowsave(flow, "consort.png", dpi = 300) > ``` > > Using `flowsave()` ensures that the figure dimensions are always large enough to accommodate the diagram content, and it is the preferred method for saving flow diagram outputs in `selecta`. --- # Preliminaries ```{r setup} library(selecta) ``` The examples in this vignette use manual mode exclusively, as systematic review diagrams are typically constructed from summary counts reported during the search and screening process rather than from a row-level dataset. --- # PRISMA — Three-Column Layout The PRISMA 2020 flow diagram uses up to three columns to organize sources: studies from previous reviews (left), databases and registers (center), and other methods such as citation searching and gray literature (right). Each column receives a header label and one source box listing individual databases or methods with their counts. ## **Example 1:** Full Three-Column PRISMA Diagram The `sources()` function accepts named vector arguments, where each argument defines a source group (column) and its named elements list the individual sources: ```{r} example1 <- sources( previous = c("Previous review" = 12, "Previous reports" = 15), databases = c("PubMed" = 1234, "Embase" = 567, "CENTRAL" = 89), other = c("Citation search" = 55, "Websites" = 34), headers = c(previous = "Previous studies", databases = "Databases and registers", other = "Other methods") ) |> phase("Identification") |> combine("Records after deduplication") |> exclude("Duplicates removed", n = 340, included_label = "Records screened") |> phase("Screening") |> exclude("Records excluded", n = 800, reasons = c("Irrelevant title/abstract" = 600, "No full text available" = 200), included_label = "Reports assessed") |> exclude("Reports excluded", n = 190, reasons = c("Wrong population" = 80, "Wrong intervention" = 60, "Wrong outcome" = 30, "Insufficient data" = 20)) |> phase("Analysis") |> endpoint("Studies included in review") ``` ```{r, echo = FALSE} queue_flow(example1) ``` ```{r, use_rec_dims = TRUE, echo = TRUE} flowchart(example1) ``` The `headers` argument maps group names to display labels for the column headers. If omitted, the argument names are title-cased and used directly (*e.g.,* `databases` becomes "Databases"). The `combine()` function inserts an inverted-Y convergence arrow connecting the parallel source columns into a single downstream node. All subsequent pipeline steps operate on the merged record pool. ## **Example 2:** Three-Column Count-First Layout Like other diagram types, convergence-style diagrams can also be formatted to have counts displayed before the category title. ```{r, echo = FALSE} queue_flow(example1, count_first = TRUE) ``` ```{r, use_rec_dims = TRUE, echo = TRUE} flowchart(example1, count_first = TRUE) ``` --- # PRISMA — Two-Column Layout Many systematic reviews search only databases and one additional source category. A two-column layout omits the "Previous studies" column: ## **Example 3:** Two-Column Sources ```{r} example3 <- sources( databases = c("PubMed" = 1234, "Embase" = 567, "CENTRAL" = 89), other = c("Citation search" = 55, "Gray literature" = 34), headers = c(databases = "Databases and registers", other = "Other methods") ) |> phase("Identification") |> combine("Records after deduplication") |> exclude("Duplicates removed", n = 340, included_label = "Records screened") |> phase("Screen") |> exclude("Records excluded", n = 900) |> phase("Analysis") |> endpoint("Studies included in review") ``` ```{r, echo = FALSE} queue_flow(example3) ``` ```{r, use_rec_dims = TRUE, echo = TRUE} flowchart(example3) ``` --- # PRISMA — Single-Column Layout For simple reviews that search a single set of databases without grouping, `sources()` accepts individual scalar arguments. These are consolidated into a single source box with no column header: ## **Example 4:** Flat Source List ```{r} example4 <- sources(PubMed = 1234, Embase = 567, CENTRAL = 89) |> phase("Identification") |> combine("Records identified") |> exclude("Duplicates removed", n = 340, included_label = "Records screened") |> phase("Screen") |> exclude("Records excluded", n = 800) |> phase("Analysis") |> endpoint("Studies included") ``` ```{r, echo = FALSE} queue_flow(example4) ``` ```{r, use_rec_dims = TRUE, echo = TRUE} flowchart(example4) ``` In this layout, no column headers are rendered and the source box appears as a single centered node above the convergence point. --- # MOOSE — Observational Meta-Analysis The MOOSE (Meta-analysis of Observational Studies in Epidemiology) guidelines prescribe a flow diagram structurally similar to PRISMA, tailored for observational evidence synthesis. The same `sources()` and `combine()` functions are used; only the labels and exclusion reasons reflect the observational context: ## **Example 5:** MOOSE Flow Diagram ```{r} example5 <- sources( databases = c("PubMed" = 892, "Embase" = 445, "Scopus" = 312), gray = c("Conference abstracts" = 67, "Dissertations" = 23), headers = c(databases = "Electronic databases", gray = "Gray literature") ) |> phase("Identification") |> combine("Records after deduplication") |> exclude("Duplicates removed", n = 420, included_label = "Records screened") |> phase("Screen") |> exclude("Records excluded", n = 850, reasons = c("Not observational design" = 380, "Irrelevant exposure" = 290, "Pediatric population" = 180), included_label = "Full-text articles assessed") |> exclude("Full-text articles excluded", n = 195, reasons = c("No relevant outcome" = 85, "Insufficient follow-up" = 60, "High risk of bias" = 50)) |> phase("Analysis") |> endpoint("Studies included in meta-analysis") ``` ```{r, echo = FALSE} queue_flow(example5) ``` ```{r, use_rec_dims = TRUE, echo = TRUE} flowchart(example5) ``` --- # Source Group Structure The `sources()` function distinguishes between two input patterns based on the structure of its arguments: | Pattern | Input | Layout | Headers | |:--------|:------|:-------|:--------| | Flat | Scalar named arguments | Single column, no header | None | | Grouped | Named vector arguments | One column per group | Auto or custom | **Flat sources** (*e.g.,* `sources(PubMed = 1234, Embase = 567)`) treat each argument as an individual database. All sources are consolidated into a single box. **Grouped sources** (*e.g.,* `sources(databases = c("PubMed" = 1234, "Embase" = 567))`) treat each argument as a group. The argument name identifies the group, and its named elements list the individual databases within that group. Each group is rendered as a separate column with an optional header. Up to three groups are supported, matching the three-column PRISMA 2020 template. The `headers` argument provides custom display labels; when omitted, group names are title-cased automatically. --- # Saving to File The `flowsave()` function saves the diagram to a file (PDF, PNG, SVG, or TIFF) with auto-computed dimensions: ```{r, eval = FALSE} flowsave(example1, "prisma_3col.pdf") flowsave(example1, "prisma_3col.png", dpi = 300) ``` Explicit dimensions override the automatic calculation: ```{r, eval = FALSE} flowsave(example1, "prisma_3col.pdf", width = 10, height = 12) ``` All visual parameters accepted by `flowchart()` are also accepted by `flowsave()`: ```{r, eval = FALSE} flowsave(example1, "prisma_poster.pdf", cex = 1.1, cex_side = 0.85, cex_phase = 1.1) ``` --- # Further Reading - [Enrollment Diagrams](enrollment_diagrams.html): CONSORT, STROBE, and STARD diagrams with permanent parallel arms - [Split-and-Recombine Diagrams](split_recombine.html): Hybrid topologies for screening validation and exposure classification - [Advanced Workflows](advanced_workflows.html): Factorial (nested-split) designs and hierarchical exclusion reasons - [Graphviz Export](graphviz_export.html): DOT output for Graphviz/DiagrammeR rendering