--- title: "Plotting model fit, diagnostics, and spatial patterns" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Plotting model fit, diagnostics, and spatial patterns} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE ) ``` This vignette walks through plotting helpers that summarize model fit and spatial patterns in **trafficCAR**: - `plot_observed_fitted()` for observed vs predicted values. - `plot_mcmc_diagnostics()` for quick effective sample size diagnostics. - `plot_predicted()` and `plot_relative_congestion()` for spatial maps. The workflow below creates a small synthetic outcome on the bundled road network, fits a Gaussian CAR model, and uses the plotting helpers to visualize results. ## Load data and build segment adjacency ```{r} library(trafficCAR) library(sf) library(ggplot2) data("roads_small", package = "trafficCAR") roads <- roads_small segments <- roads_to_segments( roads, crs_m = 3857, split_at_intersections = TRUE ) # Keep the example lightweight for vignette builds. if (nrow(segments) > 200) { segments <- segments[seq_len(200), ] } adjacency <- build_adjacency(segments, crs_m = 3857) # Drop isolated segments to keep the example compatible with a proper CAR model. if (any(adjacency$isolates)) { segments <- segments[!adjacency$isolates, ] adjacency <- build_adjacency(segments, crs_m = 3857) } ``` ## Simulate an outcome and fit a CAR model To keep the example lightweight, the code below simulates a response using segment length as a covariate and fits a modest MCMC run. Adjust `n_iter` and `burn_in` upward for applied work. ```{r} set.seed(123) segment_length <- segments$length_m segment_length <- scale(segment_length)[, 1] speed <- 40 + 6 * segment_length + rnorm(nrow(segments), sd = 3) traffic_data <- data.frame( segment_id = segments$seg_id, speed = speed ) X <- cbind( intercept = 1, length = segment_length ) fit <- fit_car( y = traffic_data$speed, A = adjacency$A, X = X, type = "proper", rho = 0.9, tau = 1, n_iter = 300, burn_in = 150, thin = 2 ) ``` ## Prepare a plotting-ready fit object The plotting helpers expect draws of the linear predictor (`mu`) alongside the raw `x` draws. The helper below derives `mu` from the CAR fit and returns an object compatible with the plotting functions. ```{r} make_plot_fit <- function(base_fit, X, outcome_col, outcome_label) { x_draws <- base_fit$draws$x beta_draws <- base_fit$draws$beta if (is.null(beta_draws) || ncol(beta_draws) == 0) { mu_draws <- x_draws } else { mu_draws <- beta_draws %*% t(X) + x_draws } plot_fit <- list( draws = list( mu = mu_draws, x = x_draws, beta = beta_draws, sigma2 = base_fit$draws$sigma2 ), outcome_col = outcome_col, outcome_label = outcome_label ) class(plot_fit) <- "traffic_fit" plot_fit } plot_fit <- make_plot_fit( fit, X = X, outcome_col = "speed", outcome_label = "Speed (mph)" ) ``` ## Plot observed vs fitted values ```{r, fig.width=7, fig.height=5} plot_observed_fitted(plot_fit, data = traffic_data) ``` Use this plot to check for systematic bias. Points should fall around the 45° line if predictions match observed data on average. ## Plot MCMC diagnostics `plot_mcmc_diagnostics()` provides quick effective sample size (ESS) diagnostics. In current versions, it returns a list with a `ggplot` and a summary data frame. For robustness in vignette builds, the code below falls back to computing ESS directly if a plot/summary is not returned. ```{r, fig.width=7, fig.height=4} diag <- plot_mcmc_diagnostics(plot_fit) if (is.list(diag) && !is.null(diag$plot)) { diag$plot } else { ess <- vapply(plot_fit$draws, posterior::ess_basic, numeric(1)) ess_df <- data.frame( parameter = names(ess), ess = as.numeric(ess), row.names = NULL ) ggplot2::ggplot(ess_df, ggplot2::aes(parameter, ess)) + ggplot2::geom_col() + ggplot2::coord_flip() + ggplot2::labs( title = "Effective sample size by parameter", x = NULL, y = "ESS" ) } ``` If you want the underlying ESS table: ```{r} if (is.list(diag) && !is.null(diag$summary)) { head(diag$summary) } else { ess <- vapply(plot_fit$draws, posterior::ess_basic, numeric(1)) head(data.frame(parameter = names(ess), ess = as.numeric(ess), row.names = NULL)) } ``` Low ESS values indicate slow mixing. Consider increasing the number of iterations or adjusting priors if ESS is consistently low. ## Plot spatial predictions `plot_predicted()` visualizes the posterior mean of the linear predictor on the road network, while `plot_relative_congestion()` highlights areas with above- or below-average spatial effects. ```{r, fig.width=7, fig.height=6} plot_predicted(plot_fit, segments) plot_relative_congestion(plot_fit, segments) ``` ## Tips for applied workflows - Always verify that the ordering of rows in `segments` matches the adjacency matrix used to fit the model. - Use the observed vs fitted plot alongside residual diagnostics to assess model adequacy. - Pair the spatial plots with domain knowledge (e.g., known bottlenecks) to interpret relative congestion.