Title: Test Robustness with Directed Acyclic Graphs
Version: 0.2.4
Description: Provides robustness checks driven by directed acyclic graphs (DAGs). Given a 'dagitty' DAG object and a model specification, 'DAGassist' classifies variables by causal roles, flags problematic controls, and generates a report comparing the original model with minimal and canonical adjustment sets. Exports publication-grade reports in 'LaTeX', 'Word', 'Excel', or plain text. 'DAGassist' is built on 'dagitty', an 'R' package that uses the 'DAGitty' web tool (https://dagitty.net/) for creating and analyzing DAGs. Methods draw on Pearl (2009) <doi:10.1017/CBO9780511803161> and Textor et al. (2016) <doi:10.1093/ije/dyw341>.
License: GPL-2 | GPL-3 [expanded from: GPL (≥ 2)]
URL: https://github.com/grahamgoff/DAGassist, https://grahamgoff.github.io/DAGassist/
BugReports: https://github.com/grahamgoff/DAGassist/issues
Depends: R (≥ 3.5)
Imports: broom, cli, crayon, dagitty, magrittr, stats, tools, utils, writexl
Suggests: fixest, ggdag, knitr, modelsummary, rmarkdown, testthat (≥ 3.0.0), tidyverse
VignetteBuilder: knitr
Config/Needs/website: pkgdown, rmarkdown
Config/testthat/edition: 3
Encoding: UTF-8
RoxygenNote: 7.3.2
NeedsCompilation: no
Packaged: 2025-09-15 16:22:42 UTC; grahamgoff
Author: Graham Goff ORCID iD [aut, cre], Michael Denly ORCID iD [ctb]
Maintainer: Graham Goff <goffgrahamc@gmail.com>
Repository: CRAN
Date/Publication: 2025-09-21 14:00:12 UTC

Pipe operator

Description

See magrittr::%>% for details.

Usage

lhs %>% rhs

Arguments

lhs

A value or the magrittr placeholder.

rhs

A function call using the magrittr semantics.

Value

The result of calling rhs(lhs).


Produce a compact DAGassist report (console/LaTeX/Word/Excel/Text)

Description

DAGassist() validates a DAG + model specification, classifies node roles, builds minimal and canonical adjustment sets, fits comparable models, and renders a compact report in several formats (console, LaTeX fragment, DOCX, XLSX, plain text). It also supports passing a single engine call (e.g. feols(Y ~ X + Z | fe, data = df)) instead of a plain formula.

Usage

DAGassist(
  dag,
  formula,
  data,
  exposure,
  outcome,
  engine = stats::lm,
  labels = NULL,
  verbose = TRUE,
  type = c("console", "latex", "word", "docx", "excel", "xlsx", "text", "txt"),
  out = NULL,
  imply = FALSE,
  omit_intercept = TRUE,
  omit_factors = TRUE,
  engine_args = list()
)

Arguments

dag

A dagitty object (see dagitty::dagitty()).

formula

Either (a) a standard model formula Y ~ X + ..., or (b) a single engine call such as feols(Y ~ X + Z | fe, data = df, ...). When an engine call is provided, engine, data, and extra arguments are automatically extracted from the call.

data

A data.frame (or compatible, e.g. tibble). Optional if supplied via the engine call in formula.

exposure

Optional character scalar; if missing/empty, inferred from the DAG (must be unique).

outcome

Optional character scalar; if missing/empty, inferred from the DAG (must be unique).

engine

Modeling function, default stats::lm. Ignored if formula is a single engine call (in that case the function is taken from the call).

labels

Optional variable labels (named character vector or data.frame).

verbose

Logical (default TRUE). Controls verbosity in the console printer (formulas + notes).

type

Output type. One of "console" (default), "latex"/"docx"/"word", "excel"/"xlsx", "text"/"txt".

out

Output file path for the non-console types:

  • type="latex": a LaTeX fragment written to out (must end with .tex).

  • type="docx"/"word": a Word (.docx) file written to out.

  • type="excel"/"xlsx": an Excel (.xlsx) file written to out.

  • type="text"/"txt": a plain-text file written to out. Ignored for type="console".

imply

Logical; default FALSE. Evaluation scope.

  • If FALSE (default): restrict DAG evaluation to variables named in the formula (prune the DAG to exposure, outcome, and RHS terms). Roles/sets/bad-controls are computed on this pruned graph, and the roles table only shows those variables. This is most useful if you want to refine your specific call.

  • If TRUE: evaluate on the full DAG and allow DAG-implied controls in the minimal/canonical sets; roles table shows all nodes. This is most useful if you want to refine your overall control variable selection.

omit_intercept

Logical; drop intercept rows from the model comparison (default TRUE).

omit_factors

Logical; drop factor-level rows from the model comparison (default TRUE).

engine_args

Named list of extra arguments forwarded to engine(...). If formula is an engine call, arguments from the call are merged with engine_args (call values take precedence).

Details

Engine-call parsing. If formula is a call (e.g., feols(Y ~ X | fe, data=df)), DAGassist extracts the engine function, formula, data argument, and any additional engine arguments directly from that call; these are merged with engine/engine_args you pass explicitly (call arguments win).

Fixest tails. For engines like fixest that use | to denote FE/IV parts, DAGassist preserves any ⁠| ...⁠ tail when constructing minimal/canonical formulas (e.g., Y ~ X + controls | fe | iv(...)).

Roles grid. The roles table displays short headers:

Bad controls. For total-effect estimation, DAGassist flags as ⁠bad controls⁠ any variables that are MED, COL, IO, DMed, or DCol. These are warned in the console and omitted from the model-comparison table. Valid confounders (pre-treatment) are eligible for minimal/canonical adjustment sets.

Output types.

Dependencies. Core requires {dagitty}. Optional enhancements: {modelsummary} (pretty tables), {broom} (fallback tidying), {rmarkdown} + Pandoc (DOCX), {writexl} (XLSX).

Value

An object of class "DAGassist_report", invisibly for file outputs, and printed for type="console". The list contains:

Interpreting the output

ROLES. Variables in your formula are classified by DAG-based causal role:

MODEL COMPARISON.

Errors and edge cases

See Also

print.DAGassist_report() for the console printer, and the helper exporters in ⁠report_*⁠ modules.

Examples




# generate a console DAGassist report
DAGassist(dag = g, formula = lm(Y ~ X + Z + C + M, data = df))

# generate a LaTeX DAGassist report

DAGassist(dag = g, formula = lm(Y ~ X + Z + C + M, data = df),
          type = "latex", out = file.path(tempdir(), "frag.tex"))



flag bad controls (mediator/collider/desc of Y) among a candidate set

Description

flag bad controls (mediator/collider/desc of Y) among a candidate set

Usage

bad_controls_in(dag, controls, exposure, outcome)

Arguments

dag

A dagitty DAG object.

controls

Character vector of variable names.

exposure

Character; exposure node name (X).

outcome

Character; outcome node name (Y).

Value

A character vector (possibly empty) containing the elements of controls that are identified as "bad controls".

This is essentially the inverse of pick_minimal_controls(), as it returns bad controls, rather than the minimal/canonical set of good controls

Examples


d <- ggdag::dagify(
Y ~ X + M + Z,
M ~ X + Z,
C ~ X + Y,
exposure = "X",
outcome = "Y")
# M: mediator / Z: confounder / C: collider

# hypothetical candidate controls
controls <- c("Z", "M", "C")

# Flag controls that would bias the total effect of X on Y:
bad_controls_in(d, controls = c("Z","M","C"), exposure = "X", outcome = "Y")

# expected: c("M", "C")  # mediator & collider are "bad controls"; Z is OK


Classify DAG nodes

Description

Labels each node as one of: exposure, outcome, confounder, mediator, collider, descendant_of_outcome, or other.

Usage

classify_nodes(dag, exposure, outcome)

Arguments

dag

A dagitty DAG object.

exposure

Optional– inferred from DAG if not set; character; exposure node name (X).

outcome

Optional– inferred from DAG if not set; character; outcome node name (Y).

Details

label definitions confounder – ancestor of both X and Y, and not a descendant of X mediator – descendant of X and ancestor of Y collider – node with 2 or more parents on an X / Y path (non-structural) descendant_of_outcome – any descendant of Y exposure / outcome labeled explicitly in function call

Notes:

Value

A data.frame with one row per node and columns:

Examples

  d1 <- dagitty::dagitty("dag { Z -> X; Z -> Y; X -> Y }") # confounder Z
  classify_nodes(d1, exposure = "X", outcome = "Y")

  d2 <- dagitty::dagitty("dag { X -> M -> Y }") # mediator M
  classify_nodes(d2, "X", "Y")

  d3 <- dagitty::dagitty("dag { X -> C <- Y }") # collider C
  classify_nodes(d3, "X", "Y")


Print method for DAGassist reports

Description

Nicely prints the roles table, highlights potential bad controls, shows minimal/canonical adjustment sets, optionally shows formulas, and renders a compact model comparison (using {modelsummary} if available, falling back to {broom} or basic coef() preview).

Usage

## S3 method for class 'DAGassist_report'
print(x, ...)

Arguments

x

A "DAGassist_report" object returned by DAGassist().

...

Additional arguments (currently unused; present for S3 compatibility).

Details

The printer respects the verbose flag in the report: when TRUE, it includes formulas and a brief note on variables added by DAG logic (minimal and canonical sets). Fitting errors are shown inline per model column and do not abort printing.

Value

Invisibly returns x.


Print node classifications (aligned)

Description

Print node classifications (aligned)

Usage

## S3 method for class 'DAGassist_roles'
print(x, n = Inf, ...)

Arguments

x

Output of classify_nodes() (class "DAGassist_roles")

n

Max rows to print (default all)

...

(ignored)

Value

Invisibly returns x


Minimal, clean printout for validation results with color coding

Description

Minimal, clean printout for validation results with color coding

Usage

## S3 method for class 'DAGassist_validation'
print(x, n = 10, ...)

Arguments

x

the list (class out) from validate_spec

n

Max number of issues to show (default 10).

...

Ignored.

Value

Invisibly returns x.