| Title: | Visualization Tools for Sensitivity Analysis of Unmeasured Confounding |
|---|---|
| Description: | Provides visualization tools for sensitivity analysis to unmeasured confounding in observational studies. Includes contour-based sensitivity plots, robustness curves, and benchmark-oriented graphics that help researchers assess how strong omitted confounding would need to be to attenuate, invalidate, or reverse estimated effects. Supports regression-based sensitivity analysis frameworks, including impact threshold approaches (Frank, 2000, <doi:10.1177/0049124100029002001>), partial R-squared methods (Cinelli and Hazlett, 2020, <doi:10.1111/rssb.12348>), and E-value style metrics (VanderWeele and Ding, 2017, <doi:10.7326/M16-2607>). Emphasizes clear, interpretable, and publication-ready graphical summaries for transparent reporting of causal sensitivity analyses across the social, behavioral, health, and educational sciences. |
| Authors: | Subir Hait [aut, cre] (ORCID: <https://orcid.org/0009-0004-9871-9677>) |
| Maintainer: | Subir Hait <[email protected]> |
| License: | GPL-3 |
| Version: | 0.1.0 |
| Built: | 2026-06-01 08:21:27 UTC |
| Source: | https://github.com/causalfragility-lab/confoundvis |
Converts a data frame containing sensitivity analysis results into a
confoundsens object suitable for use with confoundvis plotting functions.
as_confoundsens( data, lambda = "lambda", theta = "theta", level = NULL, se = NULL, t = NULL )as_confoundsens( data, lambda = "lambda", theta = "theta", level = NULL, se = NULL, t = NULL )
data |
A data.frame containing sensitivity analysis results. |
lambda |
Character string; name of the column containing lambda values.
Default |
theta |
Character string; name of the column containing theta values.
Default |
level |
Optional character string; name of the column containing level
identifiers (e.g., |
se |
Optional character string; name of the column containing standard
errors for |
t |
Optional character string; name of the column containing test statistics. |
A confoundsens object.
df <- data.frame( lambda = seq(0, 0.2, length.out = 10), theta = seq(1, 0.5, length.out = 10), se = rep(0.1, 10), level = rep(c("within", "between"), length.out = 10) ) x <- as_confoundsens(df) xdf <- data.frame( lambda = seq(0, 0.2, length.out = 10), theta = seq(1, 0.5, length.out = 10), se = rep(0.1, 10), level = rep(c("within", "between"), length.out = 10) ) x <- as_confoundsens(df) x
Coerce a confoundsens object to a data frame
## S3 method for class 'confoundsens' as.data.frame(x, ...)## S3 method for class 'confoundsens' as.data.frame(x, ...)
x |
A |
... |
Unused; included for S3 method consistency. |
A data.frame with columns lambda and theta, plus optional
columns level, se, and t when present in x.
x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 5), theta = seq(1, 0.8, length.out = 5), se = rep(0.05, 5) ) as.data.frame(x)x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 5), theta = seq(1, 0.8, length.out = 5), se = rep(0.05, 5) ) as.data.frame(x)
Fits a second-order Taylor (quadratic) approximation of an effect path
near using ordinary least squares:
fit_local_quadratic( data = NULL, delta = NULL, theta = NULL, local_max_delta = 0.2, include_intercept = TRUE, tol = 1e-12 )fit_local_quadratic( data = NULL, delta = NULL, theta = NULL, local_max_delta = 0.2, include_intercept = TRUE, tol = 1e-12 )
data |
Optional data.frame containing columns named |
delta |
Optional numeric vector of delta values. Used only when
|
theta |
Optional numeric vector of theta values. Used only when
|
local_max_delta |
Positive numeric scalar giving the half-width of the
local window: only observations with |
include_intercept |
Logical; if |
tol |
Non-negative numeric scalar tolerance used when selecting observations within the local window. |
You may supply either a data.frame containing columns delta and theta,
or supply numeric vectors delta and theta directly.
A named list with elements:
coef — named coefficient vector from stats::lm().
intercept, slope, quad — individual coefficients (NA when absent).
model — the fitted lm object.
local_data — the data.frame used for fitting.
local_max_delta — the window half-width used.
df <- data.frame( delta = seq(0, 0.3, length.out = 60), theta = 0.4 - 0.7 * seq(0, 0.3, length.out = 60) + 0.4 * seq(0, 0.3, length.out = 60)^2 ) fit_local_quadratic(df, local_max_delta = 0.2)df <- data.frame( delta = seq(0, 0.3, length.out = 60), theta = 0.4 - 0.7 * seq(0, 0.3, length.out = 60) + 0.4 * seq(0, 0.3, length.out = 60)^2 ) fit_local_quadratic(df, local_max_delta = 0.2)
Constructs a confoundsens object — a lightweight container for storing
sensitivity paths (e.g., ) and optional uncertainty or
stratification information used by confoundvis plotting functions.
new_confoundsens(lambda, theta, level = NULL, se = NULL, t = NULL)new_confoundsens(lambda, theta, level = NULL, se = NULL, t = NULL)
lambda |
Numeric vector of sensitivity strength values (e.g., ITCV lambda or delta). Should be nondecreasing; a warning is issued otherwise. |
theta |
Numeric vector of effect estimates along the sensitivity path.
Must be the same length as |
level |
Optional character (or coercible) vector of level identifiers
(e.g., |
se |
Optional numeric vector of standard errors for |
t |
Optional numeric vector of test statistics along the path. Must be
the same length as |
A confoundsens object (a list with class "confoundsens").
x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 10), theta = seq(1, 0.6, length.out = 10), se = rep(0.1, 10) ) xx <- new_confoundsens( lambda = seq(0, 0.2, length.out = 10), theta = seq(1, 0.6, length.out = 10), se = rep(0.1, 10) ) x
Produces a two-panel plot comparing the reversal cone cross-sections for
the within-cluster and between-cluster confounding components in multilevel
settings. Each panel calls plot_reversal_cone() and they are displayed
side by side using faceting.
plot_cone_comparison( theta0_within = 0.35, theta0_between = 0.5, delta_within = 0.2, delta_between = 0.3, ... )plot_cone_comparison( theta0_within = 0.35, theta0_between = 0.5, delta_within = 0.2, delta_between = 0.3, ... )
theta0_within |
Numeric; within-cluster baseline effect. |
theta0_between |
Numeric; between-cluster baseline effect. |
delta_within |
Numeric; within-cluster confounding magnitude (> 0). |
delta_between |
Numeric; between-cluster confounding magnitude (> 0). |
... |
Additional arguments passed to |
Invisibly, a list with ggplot objects within and between.
The plots are drawn side-by-side to the current device.
plot_cone_comparison( theta0_within = 0.35, theta0_between = 0.50, delta_within = 0.20, delta_between = 0.30 )plot_cone_comparison( theta0_within = 0.35, theta0_between = 0.50, delta_within = 0.20, delta_between = 0.30 )
Produces a three-panel figure (linear / concave-down / convex-up) showing a simulated confounding path together with its first-order (tangent) and second-order (local quadratic) approximations. The panels correspond to the three curvature regimes in the mITCV framework.
plot_figure2_taylor_panels( delta_max = 1.5, step = 0.02, theta0 = 0.4, slope = -0.7, kappa = 0.4, local_max_delta = 0.2 )plot_figure2_taylor_panels( delta_max = 1.5, step = 0.02, theta0 = 0.4, slope = -0.7, kappa = 0.4, local_max_delta = 0.2 )
delta_max |
Positive numeric scalar. Upper bound of the delta grid. |
step |
Positive numeric scalar. Grid step size. |
theta0 |
Numeric scalar. Baseline effect at delta = 0. |
slope |
Numeric scalar. First-order slope at delta = 0. |
kappa |
Non-negative numeric scalar. Curvature magnitude. |
local_max_delta |
Positive numeric scalar <= |
A named list with ggplot objects A (linear), B (concave), and
C (convex), returned invisibly. The three panels are also printed to
the active graphics device via gridExtra::grid.arrange() if
gridExtra is installed, or via graphics::layout() otherwise.
plots <- plot_figure2_taylor_panels() # Access individual panels plots$Aplots <- plot_figure2_taylor_panels() # Access individual panels plots$A
Plots local Taylor series components (or any multi-series decomposition)
as a function of delta from a long-form data.frame. Lines are
distinguished by colour and linetype, keyed by series.
plot_local_taylor(df, facet = FALSE)plot_local_taylor(df, facet = FALSE)
df |
A data.frame in long form with columns:
|
facet |
Logical; if |
A ggplot2::ggplot() object.
df <- data.frame( delta = rep(seq(0, 0.2, length.out = 25), 3), series = rep(c("path", "tangent", "quadratic"), each = 25), value = c( 0.4 - 0.7 * seq(0, 0.2, length.out = 25) - 0.4 * seq(0, 0.2, length.out = 25)^2, 0.4 - 0.7 * seq(0, 0.2, length.out = 25), 0.4 - 0.7 * seq(0, 0.2, length.out = 25) + 0.2 * seq(0, 0.2, length.out = 25)^2 ) ) plot_local_taylor(df) plot_local_taylor(df, facet = TRUE)df <- data.frame( delta = rep(seq(0, 0.2, length.out = 25), 3), series = rep(c("path", "tangent", "quadratic"), each = 25), value = c( 0.4 - 0.7 * seq(0, 0.2, length.out = 25) - 0.4 * seq(0, 0.2, length.out = 25)^2, 0.4 - 0.7 * seq(0, 0.2, length.out = 25), 0.4 - 0.7 * seq(0, 0.2, length.out = 25) + 0.2 * seq(0, 0.2, length.out = 25)^2 ) ) plot_local_taylor(df) plot_local_taylor(df, facet = TRUE)
Visualizes the two-dimensional cross-section of the reversal cone
at a fixed confounding effect magnitude . The cone
partitions the confounding parameter space into an
attenuation zone (where the effect shrinks but does not reverse sign)
and a reversal zone (where the sign changes). The boundary between
zones is the reversal curve derived from the multilevel mITCV framework.
plot_reversal_cone( theta0 = 0.4, delta = 0.2, q_range = c(0, 1), p_range = c(-1, 1), grid_n = 200L, show_boundary = TRUE, show_volume = TRUE )plot_reversal_cone( theta0 = 0.4, delta = 0.2, q_range = c(0, 1), p_range = c(-1, 1), grid_n = 200L, show_boundary = TRUE, show_volume = TRUE )
theta0 |
Numeric; baseline estimated effect at zero confounding (must be nonzero). |
delta |
Numeric; the fixed confounding effect magnitude |
q_range |
Numeric vector of length 2; range of the confounding
prevalence parameter |
p_range |
Numeric vector of length 2; range of the confounding
impact parameter |
grid_n |
Integer; grid resolution for each axis (default 200). |
show_boundary |
Logical; draw the reversal boundary curve. |
show_volume |
Logical; annotate with the cone volume proportion. |
A ggplot object.
plot_reversal_cone(theta0 = 0.40, delta = 0.20) plot_reversal_cone(theta0 = 0.40, delta = 0.50)plot_reversal_cone(theta0 = 0.40, delta = 0.20) plot_reversal_cone(theta0 = 0.40, delta = 0.50)
Plots the sensitivity path stored in a confoundsens object as a function
of lambda. By default, plots the effect path theta(lambda); optionally
plots the test-statistic path t(lambda). Pointwise 95% confidence bands
are drawn when standard errors are available.
plot_robustness_curve( x, what = c("theta", "t"), bands = TRUE, points = TRUE, facet_level = TRUE )plot_robustness_curve( x, what = c("theta", "t"), bands = TRUE, points = TRUE, facet_level = TRUE )
x |
A |
what |
Character; which path to plot: |
bands |
Logical; if |
points |
Logical; if |
facet_level |
Logical; if |
A ggplot2::ggplot() object.
x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 25), theta = 1 - 2 * seq(0, 0.2, length.out = 25), se = rep(0.05, 25), level = rep(c("within", "between"), length.out = 25) ) plot_robustness_curve(x) plot_robustness_curve(x, bands = FALSE, facet_level = FALSE)x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 25), theta = 1 - 2 * seq(0, 0.2, length.out = 25), se = rep(0.05, 25), level = rep(c("within", "between"), length.out = 25) ) plot_robustness_curve(x) plot_robustness_curve(x, bands = FALSE, facet_level = FALSE)
Draws an ITCV-style hyperbolic boundary in space
and optionally overlays observed covariate benchmarks as labelled points.
The robust region is the interior of the hyperbola where
threshold.
plot_sensitivity_contour(threshold, grid_n = 200, benchmarks = NULL)plot_sensitivity_contour(threshold, grid_n = 200, benchmarks = NULL)
threshold |
Positive numeric scalar; the ITCV-style product threshold.
The boundary satisfies |
grid_n |
Integer >= 50; number of points used per branch of the boundary curve. Larger values give smoother curves. |
benchmarks |
Optional data.frame with columns |
A ggplot2::ggplot() object.
b <- data.frame( r_yu = c(0.10, 0.15), r_du = c(0.20, 0.12), label = c("SES", "BMI") ) plot_sensitivity_contour(threshold = 0.02, benchmarks = b)b <- data.frame( r_yu = c(0.10, 0.15), r_du = c(0.20, 0.12), label = c("SES", "BMI") ) plot_sensitivity_contour(threshold = 0.02, benchmarks = b)
Benchmarks a sensitivity threshold against the empirical distribution of observed covariate impacts in a "Love plot"-style display. Each covariate appears as a point on a horizontal impact axis; the sensitivity threshold is shown as a vertical reference line. Covariates to the left of the line are weaker than the threshold; those to the right pose a credible threat.
plot_sensitivity_love(df, threshold, sort = TRUE, top = NULL)plot_sensitivity_love(df, threshold, sort = TRUE, top = NULL)
df |
A data.frame with at least two columns:
|
threshold |
Single non-missing numeric value to draw as a vertical reference line (the sensitivity threshold). |
sort |
Logical; if |
top |
Optional positive integer. If supplied, only the |
A ggplot2::ggplot() object.
df <- data.frame( covariate = c("SES", "BMI", "Gender", "Race", "Age"), impact = c(0.12, 0.05, 0.02, 0.08, 0.03) ) plot_sensitivity_love(df, threshold = 0.10) plot_sensitivity_love(df, threshold = 0.10, top = 3)df <- data.frame( covariate = c("SES", "BMI", "Gender", "Race", "Age"), impact = c(0.12, 0.05, 0.02, 0.08, 0.03) ) plot_sensitivity_love(df, threshold = 0.10) plot_sensitivity_love(df, threshold = 0.10, top = 3)
Prints a concise summary of the key fields in a confoundsens object.
## S3 method for class 'confoundsens' print(x, ...)## S3 method for class 'confoundsens' print(x, ...)
x |
A |
... |
Unused; included for S3 method consistency. |
x, invisibly.
x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 5), theta = seq(1, 0.8, length.out = 5) ) print(x)x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 5), theta = seq(1, 0.8, length.out = 5) ) print(x)
Generates three synthetic sensitivity paths — linear, concave-down, and
convex-up — sharing the same baseline effect and first-order
slope, but differing in second-order curvature. These toy paths illustrate
the difference between tangent-based (first-order) and local quadratic
(second-order) sensitivity approximations.
simulate_taylor_demo( delta_max = 1.5, step = 0.02, theta0 = 0.4, slope = -0.7, kappa = 0.4 )simulate_taylor_demo( delta_max = 1.5, step = 0.02, theta0 = 0.4, slope = -0.7, kappa = 0.4 )
delta_max |
Single positive numeric scalar. Upper bound of the
|
step |
Single positive numeric scalar. Step size for the grid. |
theta0 |
Single numeric scalar. Baseline effect at |
slope |
Single numeric scalar. First-order slope at |
kappa |
Single non-negative numeric scalar. Curvature magnitude. |
The three regimes are:
Linear:
Concave-down:
Convex-up:
A named list with elements linear, concave, and convex, each
a new_confoundsens() object.
sims <- simulate_taylor_demo( delta_max = 1, step = 0.05, theta0 = 0.4, slope = -0.7, kappa = 0.4 ) sims$linear plot_robustness_curve(sims$concave)sims <- simulate_taylor_demo( delta_max = 1, step = 0.05, theta0 = 0.4, slope = -0.7, kappa = 0.4 ) sims$linear plot_robustness_curve(sims$concave)
Produces a concise numerical summary of the sensitivity path, optionally broken down by level.
## S3 method for class 'confoundsens' summary(object, ...)## S3 method for class 'confoundsens' summary(object, ...)
object |
A |
... |
Unused; included for S3 method consistency. |
An object of class summary.confoundsens containing a table
data.frame with per-level summary statistics.
x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 10), theta = seq(1, 0.6, length.out = 10), se = rep(0.08, 10), level = rep(c("within", "between"), length.out = 10) ) summary(x)x <- new_confoundsens( lambda = seq(0, 0.2, length.out = 10), theta = seq(1, 0.6, length.out = 10), se = rep(0.08, 10), level = rep(c("within", "between"), length.out = 10) ) summary(x)