The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

confoundvis is an R package for visualizing sensitivity
analysis to unmeasured confounding in observational studies. It
implements visualization tools for three major sensitivity frameworks —
the Impact Threshold (Frank, 2000), Partial
R-squared / Robustness Value (Cinelli & Hazlett, 2020), and
E-value style metrics (VanderWeele & Ding, 2017) —
helping researchers assess how strong omitted confounding would need to
be to attenuate, invalidate, or reverse an estimated causal effect, and
communicate those findings through clear, publication-ready
graphics.
Core functions:
| Function | Description |
|---|---|
new_confoundsens() |
Construct a sensitivity analysis object |
plot_sensitivity_contour() |
Contour plot of robustness values |
plot_robustness_curve() |
Robustness curve across effect sizes |
plot_sensitivity_love() |
Love-plot style sensitivity display |
plot_local_taylor() |
Local Taylor approximation around estimates |
fit_local_quadratic() |
Fit local quadratic to sensitivity path |
simulate_taylor_demo() |
Simulate data for Taylor approximation demos |
Install the development version from GitHub:
# install.packages("pak")
pak::pak("causalfragility-lab/confoundvis")library(confoundvis)
# Construct a sensitivity analysis object
obj <- new_confoundsens(
estimate = 0.5,
se = 0.1,
df = 200,
r2dz_x = seq(0.01, 0.4, by = 0.01),
r2yz_dx = seq(0.01, 0.4, by = 0.01),
benchmark_r2dz = 0.1,
benchmark_r2yz = 0.15
)
# Contour plot of robustness values
plot_sensitivity_contour(obj)
# Robustness curve across effect sizes
plot_robustness_curve(obj)
# Love-plot style sensitivity display
plot_sensitivity_love(obj)
# Local Taylor approximation
plot_local_taylor(obj)# Contour plot
plot_sensitivity_contour(obj)
# Robustness curve
plot_robustness_curve(obj)
# Love plot
plot_sensitivity_love(obj)
# Taylor approximation
plot_local_taylor(obj)The package operationalises three sensitivity frameworks:
| Framework | Reference | Key Quantity |
|---|---|---|
| Impact threshold | Frank (2000) | % cases that must be replaced to nullify effect |
| Partial R-squared / Robustness value | Cinelli & Hazlett (2020) | R² of confounder with treatment and outcome |
| E-value style metrics | VanderWeele & Ding (2017) | Minimum confounding risk ratio to explain away effect |
A simulation with theta0 = 0.5,
slope = -0.7, kappa3 = 0.6, and window widths
w ∈ {0.05, 0.1, 0.2, 0.3, 0.4, 0.5} confirms that local
quadratic approximation consistently outperforms first-order (tangent)
approximation as the local window widens.
library(confoundvis)
library(ggplot2)
library(scales)
set.seed(2025)
theta0 <- 0.5
slope <- -0.7
kappa3 <- 0.6
windows <- c(0.05, 0.1, 0.2, 0.3, 0.4, 0.5)
kappa_vals <- c(-0.4, 0, 0.4)
delta <- seq(0, 0.5, length.out = 1000)
results <- list()
for (kap in kappa_vals) {
theta_true <- theta0 + slope * delta + kap * delta^2 + kappa3 * delta^3
simdat <- data.frame(delta = delta, theta = theta_true)
for (w in windows) {
local_dat <- subset(simdat, delta <= w)
pred_t <- theta0 + slope * local_dat$delta
mae_t <- mean(abs(local_dat$theta - pred_t))
fit_q <- lm(theta ~ delta + I(delta^2), data = local_dat)
mae_q <- mean(abs(local_dat$theta - predict(fit_q, newdata = local_dat)))
results[[length(results) + 1]] <- data.frame(
kappa = kap, window = w, mae_tangent = mae_t, mae_quadratic = mae_q
)
}
}
df <- do.call(rbind, results)
df_long <- rbind(
data.frame(kappa = df$kappa, window = df$window,
type = "Tangent", mae = df$mae_tangent),
data.frame(kappa = df$kappa, window = df$window,
type = "Quadratic", mae = df$mae_quadratic)
)
df_long$kappa_lab <- factor(
df_long$kappa,
levels = c(-0.4, 0, 0.4),
labels = c("Concave (K < 0)", "Linear (K = 0)", "Convex (K > 0)")
)
ggplot(df_long, aes(x = window, y = mae, color = type, linetype = type)) +
geom_line(linewidth = 0.9) +
geom_point(size = 1.8) +
scale_y_log10(labels = label_scientific()) +
facet_wrap(~ kappa_lab, nrow = 1) +
labs(
title = "Taylor Approximation MAE vs Local Window Width",
subtitle = "True path includes cubic term (kappa3 = 0.6)",
x = "Local window width (w)",
y = "Mean Absolute Error (log scale)",
color = "Approximation",
linetype = "Approximation"
) +
theme_bw(base_size = 11) +
theme(
legend.position = "bottom",
panel.grid.minor = element_blank(),
strip.background = element_rect(fill = "grey92", colour = NA),
plot.title = element_text(face = "bold")
)Key finding: Quadratic approximation yields substantially lower error than the tangent at every window width. Approximation error grows with window width, and curvature accelerates the deterioration of first-order linear approximation.
When the true sensitivity path is nonlinear, using a linear approximation to locate the zero-crossing introduces systematic bias.
theta0_vals <- c(0.2, 0.4, 0.6)
slope_vals <- c(-0.3, -0.6, -0.9)
kappa_vals2 <- seq(-0.6, 0.6, by = 0.2)
find_true <- function(t0, s, k) {
if (abs(k) < 1e-10) return(-t0 / s)
disc <- s^2 - 4 * k * t0
if (disc < 0) return(NA_real_)
roots <- c((-s + sqrt(disc)) / (2 * k), (-s - sqrt(disc)) / (2 * k))
roots <- roots[roots > 0]
if (length(roots) == 0) return(NA_real_)
min(roots)
}
res2 <- list()
for (t0 in theta0_vals) {
for (s in slope_vals) {
for (k in kappa_vals2) {
l_lin <- -t0 / s
l_true <- find_true(t0, s, k)
if (is.na(l_true)) next
res2[[length(res2) + 1]] <- data.frame(
theta0 = t0, slope = s, kappa = k,
lambda_linear = l_lin, lambda_true = l_true,
error = l_lin - l_true
)
}
}
}
df2 <- do.call(rbind, res2)
df2$theta0_lab <- factor(
df2$theta0,
levels = c(0.2, 0.4, 0.6),
labels = c("theta0 = 0.2", "theta0 = 0.4", "theta0 = 0.6")
)
ggplot(df2, aes(x = kappa, y = error,
color = factor(slope), group = factor(slope))) +
geom_hline(yintercept = 0, linetype = "dashed", colour = "grey50") +
geom_line(linewidth = 0.9) +
geom_point(size = 1.8) +
facet_wrap(~ theta0_lab, nrow = 1) +
labs(
title = "Signed Error in lambda* Under Linearity Mis-specification",
subtitle = "Positive = over-estimation by linear approximation",
x = "True curvature (kappa)",
y = "Estimated lambda* (linear) - true lambda*",
color = "Slope"
) +
theme_bw(base_size = 11) +
theme(
legend.position = "bottom",
panel.grid.minor = element_blank(),
strip.background = element_rect(fill = "grey92", colour = NA),
plot.title = element_text(face = "bold")
)Key finding: Under concavity, linear approximation over-estimates the fragility threshold; under convexity, it under-estimates. The bias grows with both curvature magnitude and initial effect size.
Frank, K. A. (2000). Impact of a confounding variable on a regression coefficient. Sociological Methods & Research, 29(2), 147–194. https://doi.org/10.1177/0049124100029002001
Cinelli, C., & Hazlett, C. (2020). Making sense of sensitivity: Extending omitted variable bias. Journal of the Royal Statistical Society: Series B, 82(1), 39–67. https://doi.org/10.1111/rssb.12348
VanderWeele, T. J., & Ding, P. (2017). Sensitivity analysis in observational research: Introducing the E-value. Annals of Internal Medicine, 167(4), 268–274. https://doi.org/10.7326/M16-2607
citation("confoundvis")Hait, S. (2025). confoundvis: Visualization Tools for Sensitivity Analysis to Unmeasured Confounding. R package version 0.1.0. https://github.com/causalfragility-lab/confoundvis
Subir Hait
Michigan State University
haitsubi@msu.edu
ORCID: 0009-0004-9871-9677
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.