Skip to contents

Introduction — What is a RAP?

The reproducibility problem in environmental epidemiology

Public health and environmental epidemiology research in Brazil faces a growing challenge: how can an analysis conducted today — say, on respiratory-disease mortality in Sao Paulo during the winter of 2022 — be reproduced, updated, and audited by another researcher three years from now? With different package versions, updated databases, and new municipalities to include?

Reproducible Analytical Pipelines (RAPs) are data science’s answer to this problem, both in government and academic settings. The concept was formalized by the UK Government Data Science unit (2022) to ensure that analyses published by public agencies are auditable, updatable, and executable by any collaborator with access to the correct environment.

In climasus4r, the RAP module serializes the entire analysis pipeline — from importing DATASUS data to temporal aggregation — into a portable text file (.R, .Rmd, or .qmd), with embedded traceability metadata. This means you can:

  • Archive the analysis alongside the article as supplementary material
  • Re-run the same pipeline for new federative units or periods with a single command
  • Compare two versions of the pipeline to identify divergences
  • Update parameters without manually reopening and editing the file
📦

Portability

The exported pipeline is a standard R text file. Any collaborator with climasus4r installed can re-run it.

🔍

Traceability

Automatic metadata records the R version, packages, date/time, and platform at the moment of export.

🔄

Updatability

Parameters such as state (UF), period, and DATASUS system can be overridden without editing the exported file.

📊

Comparability

Two versions of the pipeline can be compared side by side to identify what changed between revisions.

The rap_object class

sus_rap_export() returns an object of the S3 class rap_object, which is a named list with seven fields:

Field Type Description
metadata list R version, packages, timestamp, platform, random seed
params list Parameters detected in the pipeline (uf, years, system, etc.)
steps list Each pipeline step with its function and arguments
structure list Format, output type, total number of steps
source character Path of the exported file on disk
format character Export format ("script", "rmarkdown", etc.)
raw character Lines of the exported file (for direct inspection)
**Note:** `rap_object` inherits from `list`, which means you can access any field with `$` or `[[`. For example, `rap$params$uf` returns the federative unit recorded at the time of export.

Prerequisites

Required packages

# Instalacao do climasus4r (se ainda nao instalado)
# install.packages("remotes")
# remotes::install_github("ByMaxAnjos/climasus4r")

library(climasus4r)
library(dplyr)     # para manipulacao de dados
library(magrittr)  # para o operador %>%

Building the example pipeline

In this tutorial we will use as our driving case an analysis of respiratory-disease mortality in the state of Sao Paulo, 2020-2022, imported from SIM-DO (Mortality Information System). The pipeline is defined with quote(), which captures the expression without evaluating it:

pipeline <- quote(
  sus_data_import(uf = "SP", years = 2020:2022, system = "SIM-DO") |>
    sus_data_clean_encoding() |>
    sus_data_standardize() |>
    sus_data_filter_cid(cid_group = "respiratory") |>
    sus_data_aggregate(by = "month", lang = "pt")
)
**Tip:** Using `quote()` is essential. It creates a language object (`call`) that `sus_rap_export()` can inspect, parametrize, and serialize. If you pass the result of a pipeline that has already been executed, the RAP module will not be able to reconstruct the steps in an auditable way.

Checking the pipeline structure

# O objeto 'pipeline' e um objeto de linguagem do tipo 'call'
class(pipeline)
#> [1] "call"

# Visualizando a arvore de chamadas
lobstr::ast(!!pipeline)
#> o-`|>`
#> +-o-`|>`
#> | +-o-`|>`
#> | | +-o-`|>`
#> | | | +-sus_data_import(uf = "SP", years = 2020:2022, system = "SIM-DO")
#> | | | \-sus_data_clean_encoding()
#> | | \-sus_data_standardize()
#> | \-sus_data_filter_cid(cid_group = "respiratory")
#> \-sus_data_aggregate(by = "month", lang = "pt")

sus_rap_export() — Serializing the Pipeline

Full signature

sus_rap_export(
  pipeline             = NULL,
  file_path            = NULL,
  format               = c("script", "rmarkdown", "quarto", "function"),
  include_metadata     = TRUE,
  include_validation   = TRUE,
  include_documentation = c("standard", "minimal", "comprehensive"),
  output_type          = c("analysis", "dashboard", "report"),
  lang                 = "pt",
  overwrite            = FALSE
)

Exporting as an R script (default format)

The "script" format generates a self-contained .R file, with a metadata header, a parameter block, a validation block, and the pipeline itself. It is the recommended format for archiving and re-running from the command line.

rap <- sus_rap_export(
  pipeline              = pipeline,
  file_path             = "analise_respiratoria_sp.R",
  format                = "script",
  include_metadata      = TRUE,
  include_validation    = TRUE,
  include_documentation = "standard",
  lang                  = "pt"
)
#> v Pipeline exportado para 'analise_respiratoria_sp.R'
#> i Formato      : script
#> i Etapas       : 5
#> i Parametros   : uf, years, system, cid_group, by, lang
#> i Metadados    : R 4.4.1 | climasus4r 0.1.0 | 2026-06-18 09:32:14

Structure of the generated file

The exported file analise_respiratoria_sp.R has the following structure:

# ============================================================
# RAP gerado por climasus4r::sus_rap_export()
# Timestamp : 2026-06-18 09:32:14 BRT
# R version : 4.4.1 (2024-06-14)
# climasus4r: 0.1.0
# Plataforma: aarch64-apple-darwin20
# ============================================================

# -- PARAMETROS (edite aqui para reutilizar o pipeline) ------
params <- list(
  uf        = "SP",
  years     = 2020:2022,
  system    = "SIM-DO",
  cid_group = "respiratory",
  by        = "month",
  lang      = "pt"
)

# -- VALIDACAO -----------------------------------------------
stopifnot(
  is.character(params$uf),
  all(params$years >= 1979),
  params$system %in% c("SIM-DO", "SIH", "SINAN", "SIA", "CNES", "SINASC")
)

# -- PIPELINE ------------------------------------------------
resultado <- sus_data_import(
    uf = params$uf, years = params$years, system = params$system
  ) |>
  sus_data_clean_encoding() |>
  sus_data_standardize() |>
  sus_data_filter_cid(cid_group = params$cid_group) |>
  sus_data_aggregate(by = params$by, lang = params$lang)

Structure of the returned rap_object

str(rap)
#> List of 7
#>  $ metadata : list [r_version, packages, timestamp, platform, seed]
#>  $ params   : list [uf, years, system, cid_group, by, lang]
#>  $ steps    : list [5 pipeline steps]
#>  $ structure: list [type, input_params, output_params, total_steps]
#>  $ source   : chr "analise_respiratoria_sp.R"
#>  $ format   : chr "script"
#>  $ raw      : chr [linhas do arquivo exportado]
#>  - attr(*, "class")= chr [1:2] "rap_object" "list"

# Acessando campos individuais
rap$params$uf
#> [1] "SP"

rap$metadata$r_version
#> [1] "R version 4.4.1 (2024-06-14)"

rap$structure$total_steps
#> [1] 5

Exporting as R Markdown

For publishing reproducible reports with narrative text, use format = "rmarkdown". The generated .Rmd file includes a YAML header, configuration chunks, and the pipeline inside executable chunks.

rap_rmd <- sus_rap_export(
  pipeline              = pipeline,
  file_path             = "relatorio_respiratorio_sp.Rmd",
  format                = "rmarkdown",
  include_metadata      = TRUE,
  include_validation    = TRUE,
  include_documentation = "comprehensive",
  output_type           = "report",
  lang                  = "pt"
)
#> v Pipeline exportado para 'relatorio_respiratorio_sp.Rmd'
#> i Formato      : rmarkdown
#> i Etapas       : 5
#> i output_type  : report
#> i Documentacao : comprehensive

Exporting as Quarto

The "quarto" format generates a .qmd file compatible with the Quarto system, ideal for modern technical documents with support for Python, Julia, and multiple execution engines.

rap_qmd <- sus_rap_export(
  pipeline   = pipeline,
  file_path  = "analise_respiratoria_sp.qmd",
  format     = "quarto",
  output_type = "dashboard",
  lang       = "pt"
)
#> v Pipeline exportado para 'analise_respiratoria_sp.qmd'
#> i Formato: quarto | output_type: dashboard

Exporting as an encapsulated function

The "function" format is best suited for integration into packages or automation scripts. The pipeline is encapsulated in an R function with all parameters as formal arguments, ready to be imported or reused programmatically.

rap_fn <- sus_rap_export(
  pipeline   = pipeline,
  file_path  = "run_analise_respiratoria.R",
  format     = "function",
  lang       = "pt"
)
#> v Pipeline exportado para 'run_analise_respiratoria.R'
#> i Formato: function
#> i Funcao gerada: run_pipeline(uf, years, system, cid_group, by, lang)

The generated file contains a function like this:

run_pipeline <- function(
    uf        = "SP",
    years     = 2020:2022,
    system    = "SIM-DO",
    cid_group = "respiratory",
    by        = "month",
    lang      = "pt"
) {
  sus_data_import(uf = uf, years = years, system = system) |>
    sus_data_clean_encoding() |>
    sus_data_standardize() |>
    sus_data_filter_cid(cid_group = cid_group) |>
    sus_data_aggregate(by = by, lang = lang)
}

Documentation levels (include_documentation)

The include_documentation parameter controls the amount of comments generated in the exported file:

Level Description
"minimal" Only the essential header and the parameter block
"standard" Header, parameters, validation, and step comments
"comprehensive" All of the above + a description of each function, expected types, and links to the documentation
# Exportacao minima -- apenas o essencial
rap_min <- sus_rap_export(
  pipeline              = pipeline,
  file_path             = "analise_minima.R",
  include_documentation = "minimal",
  lang                  = "pt"
)
# Exportacao abrangente -- maxima rastreabilidade
rap_full <- sus_rap_export(
  pipeline              = pipeline,
  file_path             = "analise_completa.R",
  include_documentation = "comprehensive",
  lang                  = "pt"
)
**Warning:** `overwrite = FALSE` is the default. If the file already exists on disk, `sus_rap_export()` aborts with an explanatory error. Use `overwrite = TRUE` to explicitly overwrite it, or specify a new path.

sus_rap_read() — Reading It Back

Once exported, the .R file (or .Rmd/.qmd) can be read back into a rap_object in any R session, even if the original pipeline no longer exists in memory.

Signature

sus_rap_read(file_path, lang = "pt", validate = TRUE)

Reading the exported file

rap2 <- sus_rap_read("analise_respiratoria_sp.R", lang = "pt")
#> v Arquivo lido: 'analise_respiratoria_sp.R'
#> v Metadados validados
#> i R version  : 4.4.1 (exportado em 2026-06-18 09:32:14)
#> i climasus4r : 0.1.0
#> i Etapas     : 5
#> i Parametros : uf = "SP" | years = 2020:2022 | system = "SIM-DO"

Printing the rap_object

The print.rap_object() method displays a formatted summary of the pipeline:

print(rap2)
#> -- RAP: analise_respiratoria_sp.R -----------------------
#> Formato   : script
#> Exportado : 2026-06-18 09:32:14 BRT
#> R version : 4.4.1 | climasus4r 0.1.0
#> Plataforma: aarch64-apple-darwin20
#>
#> -- Parametros ------------------------------------------
#> uf        : "SP"
#> years     : 2020 2021 2022
#> system    : "SIM-DO"
#> cid_group : "respiratory"
#> by        : "month"
#> lang      : "pt"
#>
#> -- Pipeline (5 etapas) ----------------------------------
#> [1] sus_data_import()
#> [2] sus_data_clean_encoding()
#> [3] sus_data_standardize()
#> [4] sus_data_filter_cid()
#> [5] sus_data_aggregate()
#> ---------------------------------------------------------
**Note:** The `validate = TRUE` argument (default) checks whether the file being read contains the required metadata fields (`timestamp`, `r_version`, `climasus4r`) and issues a warning if the file was edited manually and its metadata is incomplete. Use `validate = FALSE` to suppress this check.

sus_rap_inspect() — Inspecting and Comparing

Signature

sus_rap_inspect(rap, rap2 = NULL, verbose = TRUE, lang = "pt")

5.1 Inspecting a single RAP

With just one rap_object, sus_rap_inspect() displays a detailed summary of the pipeline: steps, parameters, metadata, and, with verbose = TRUE, the raw code of the exported file.

sus_rap_inspect(rap2, verbose = TRUE)
#> == Inspecao: analise_respiratoria_sp.R ==================
#>
#> METADADOS
#>   Timestamp : 2026-06-18 09:32:14 BRT
#>   R version : 4.4.1
#>   climasus4r: 0.1.0
#>   Plataforma: aarch64-apple-darwin20
#>   Semente   : nao definida
#>
#> ESTRUTURA
#>   Formato      : script
#>   Total etapas : 5
#>   Output type  : analysis
#>   Documentacao : standard
#>
#> PARAMETROS
#>   uf        = "SP"
#>   years     = 2020:2022
#>   system    = "SIM-DO"
#>   cid_group = "respiratory"
#>   by        = "month"
#>   lang      = "pt"
#>
#> PIPELINE
#>   [1] sus_data_import(uf, years, system)
#>   [2] sus_data_clean_encoding()
#>   [3] sus_data_standardize()
#>   [4] sus_data_filter_cid(cid_group)
#>   [5] sus_data_aggregate(by, lang)
#>
#> CODIGO (raw)
#>   [ver arquivo: analise_respiratoria_sp.R]
#> =========================================================

5.2 Comparing two RAPs (diff)

When passed two rap_objects, sus_rap_inspect() performs a structured diff, identifying:

  • Parameters that changed value
  • Steps added or removed
  • Discrepancies in metadata (package version, platform)

The scenario below compares the Sao Paulo pipeline with an equivalent version exported for Rio de Janeiro:

# Primeiro, exportamos o pipeline para o RJ
pipeline_rj <- quote(
  sus_data_import(uf = "RJ", years = 2020:2022, system = "SIM-DO") |>
    sus_data_clean_encoding() |>
    sus_data_standardize() |>
    sus_data_filter_cid(cid_group = "respiratory") |>
    sus_data_aggregate(by = "month", lang = "pt")
)

sus_rap_export(
  pipeline  = pipeline_rj,
  file_path = "analise_respiratoria_rj.R",
  lang      = "pt"
)

rap_rj <- sus_rap_read("analise_respiratoria_rj.R")
sus_rap_inspect(rap2, rap_rj)
#> == Diff: [1] analise_respiratoria_sp.R vs [2] analise_respiratoria_rj.R ==
#>
#> PARAMETROS ALTERADOS
#>   uf        : "SP"  -->  "RJ"
#>
#> PARAMETROS IDENTICOS
#>   years, system, cid_group, by, lang
#>
#> ETAPAS
#>   Identicas : 5/5  (nenhuma etapa adicionada ou removida)
#>
#> METADADOS
#>   Timestamps : diferentes (2026-06-18 09:32:14  vs  2026-06-18 09:45:07)
#>   R version  : identicas (4.4.1)
#>   climasus4r : identicas (0.1.0)
#>
#> CONCLUSAO: pipelines equivalentes com parametro 'uf' distinto.
#> =========================================================
**Tip:** The diff is especially useful for peer review. If a collaborator modifies the pipeline and re-exports it, you can compare the original RAP with the new one to understand exactly what changed, without having to read the code line by line.

sus_rap_run() — Re-running with New Parameters

Signature

sus_rap_run(rap, ..., envir = parent.frame(), dry_run = FALSE, lang = "pt")

The arguments passed via ... override the RAP’s parameters only for the current execution — the file on disk is not modified. To permanently modify the file, use sus_rap_update() (section 7).

6.1 Simulation with dry_run = TRUE

Before running the pipeline with new parameters, it is recommended to check the code that would be executed using dry_run = TRUE. No connection to DATASUS is opened, no data is downloaded.

sus_rap_run(rap2, uf = "RJ", years = 2021:2023, dry_run = TRUE)
#> -- [dry_run] Codigo que seria executado ------------------
#>
#> sus_data_import(uf = "RJ", years = 2021:2023, system = "SIM-DO") |>
#>   sus_data_clean_encoding() |>
#>   sus_data_standardize() |>
#>   sus_data_filter_cid(cid_group = "respiratory") |>
#>   sus_data_aggregate(by = "month", lang = "pt")
#>
#> Parametros substituidos: uf = "RJ" | years = 2021:2023
#> Parametros mantidos    : system, cid_group, by, lang
#> ----------------------------------------------------------
#> i Nenhum dado foi baixado (dry_run = TRUE)

6.2 Actual execution

Once the code is confirmed, remove dry_run = TRUE to run the pipeline:

resultado_rj <- sus_rap_run(
  rap2,
  uf    = "RJ",
  years = 2021:2023,
  lang  = "pt"
)
#> -- Executando RAP: analise_respiratoria_sp.R -------------
#> i Parametros substituidos: uf = "RJ" | years = 2021:2023
#> v [1/5] sus_data_import()     ... 148.392 registros importados
#> v [2/5] sus_data_clean_encoding() ... concluido
#> v [3/5] sus_data_standardize() ... concluido
#> v [4/5] sus_data_filter_cid()  ... 42.817 registros (cid_group = "respiratory")
#> v [5/5] sus_data_aggregate()   ... 36 linhas (mensal, 2021-2023)
#> -- Pipeline concluido em 4.2 segundos --------------------

class(resultado_rj)
#> [1] "climasus_df" "tbl_df"      "tbl"         "data.frame"

6.3 Overriding multiple parameters

You can override as many parameters as you want in a single call:

resultado_mg_anual <- sus_rap_run(
  rap2,
  uf    = "MG",
  years = 2019:2023,
  by    = "year",
  lang  = "en"
)
#> -- Executando RAP: analise_respiratoria_sp.R -------------
#> i Parametros substituidos: uf = "MG" | years = 2019:2023 | by = "year"
#> v Pipeline concluido em 6.1 segundos

6.4 Controlling the execution environment

The envir argument defines in which environment the pipeline is evaluated. The default parent.frame() is suitable for interactive use. For automated executions in scripts or functions, pass envir = new.env() to isolate the pipeline:

env_isolado <- new.env(parent = baseenv())
resultado_iso <- sus_rap_run(
  rap2,
  uf   = "CE",
  envir = env_isolado
)
**Warning:** `sus_rap_run()` requires an internet connection to download data from DATASUS via `microdatasus`. Make sure the execution environment has access to the DATASUS server before calling the function.

sus_rap_update() — Updating Parameters in the File

Signature

sus_rap_update(rap, ..., backup = TRUE, lang = "pt")

While sus_rap_run() overrides parameters only for the current execution (without touching the file), sus_rap_update() permanently edits the parameter block in the file on disk. This is useful when you want the “official” version of the pipeline to reflect a permanent change in scope.

Updating the state (UF) and the period

sus_rap_update(
  rap2,
  uf    = c("RJ", "MG"),
  years = 2021:2023,
  lang  = "pt"
)
#> i Backup criado: analise_respiratoria_sp.R.bak (2026-06-18 10:02:31)
#> v Parametros atualizados em 'analise_respiratoria_sp.R':
#>   uf    : "SP"          -->  c("RJ", "MG")
#>   years : 2020:2022     -->  2021:2023
#> i Parametros nao alterados: system, cid_group, by, lang

The parameter block before and after

Before the update:

# -- PARAMETROS (edite aqui para reutilizar o pipeline) ------
params <- list(
  uf        = "SP",
  years     = 2020:2022,
  system    = "SIM-DO",
  cid_group = "respiratory",
  by        = "month",
  lang      = "pt"
)

After the update:

# -- PARAMETROS (edite aqui para reutilizar o pipeline) ------
# Atualizado por sus_rap_update() em 2026-06-18 10:02:31
params <- list(
  uf        = c("RJ", "MG"),
  years     = 2021:2023,
  system    = "SIM-DO",
  cid_group = "respiratory",
  by        = "month",
  lang      = "pt"
)

Automatic backup

By default, backup = TRUE creates a copy of the original file before any modification, with a .bak suffix and timestamp. This ensures that you never lose the previous version of the pipeline:

# O backup e criado automaticamente:
# analise_respiratoria_sp.R.bak.2026-06-18_10-02-31

# Para restaurar manualmente:
file.copy(
  "analise_respiratoria_sp.R.bak.2026-06-18_10-02-31",
  "analise_respiratoria_sp.R",
  overwrite = TRUE
)
**Versioning tip:** For projects under Git, combine `sus_rap_update()` with regular commits. The history of the exported file is the most robust traceability mechanism available, especially for external audits.

Reloading the updated RAP

After the update, re-read the file to obtain a rap_object with the new parameters reflected in memory:

rap2_atualizado <- sus_rap_read("analise_respiratoria_sp.R")

# Confirme a atualizacao
rap2_atualizado$params$uf
#> [1] "RJ" "MG"

rap2_atualizado$params$years
#> [1] 2021 2022 2023

Complete Workflow

The full life cycle of a RAP in climasus4r passes through six stages. The diagram below illustrates the typical sequence of use:

quote(pipeline) → sus_rap_export() → sus_rap_read() → sus_rap_inspect() → sus_rap_run() → sus_rap_update()

Full reference script

The code below brings together all the steps in a single reference script:

library(climasus4r)

# 1. Definir o pipeline com quote()
pipeline <- quote(
  sus_data_import(uf = "SP", years = 2020:2022, system = "SIM-DO") |>
    sus_data_clean_encoding() |>
    sus_data_standardize() |>
    sus_data_filter_cid(cid_group = "respiratory") |>
    sus_data_aggregate(by = "month", lang = "pt")
)

# 2. Exportar para disco
rap <- sus_rap_export(
  pipeline              = pipeline,
  file_path             = "analise_respiratoria_sp.R",
  format                = "script",
  include_documentation = "standard",
  lang                  = "pt"
)

# 3. Reler de disco (simula colaborador recebendo o arquivo)
rap2 <- sus_rap_read("analise_respiratoria_sp.R")

# 4. Inspecionar
sus_rap_inspect(rap2, verbose = TRUE)

# 5. Simular execucao com novos parametros (sem baixar dados)
sus_rap_run(rap2, uf = "RJ", years = 2021:2023, dry_run = TRUE)

# 6. Executar de verdade
resultado <- sus_rap_run(rap2, uf = "RJ", years = 2021:2023)

# 7. Atualizar parametros no arquivo para escopo ampliado
sus_rap_update(rap2, uf = c("RJ", "MG"), years = 2021:2023)

Quick reference table

Function Input Output Modifies disk?
sus_rap_export() quote(pipeline) rap_object Yes (creates file)
sus_rap_read() file path rap_object No
sus_rap_inspect() 1 or 2 rap_object console output No
sus_rap_run() rap_object climasus_df No
sus_rap_update() rap_object + params rap_object (invisible) Yes (edits file)

References


Navigation: Previous: Thematic Tutorials | Next: RAP 2 - Pipelines with targets

climasus4r · Integrated health-climate-environment analysis in Brazil

Found an issue or have suggestions for this tutorial?

🐛 Report on GitHub