Skip to contents

Creates base-R plots for inspecting anchor drift across calibration waves or visualising the cumulative offset in a screened linking chain.

Usage

plot_anchor_drift(
  x,
  type = c("drift", "chain", "heatmap"),
  facet = NULL,
  preset = c("standard", "publication", "compact"),
  draw = TRUE,
  ...
)

Arguments

x

An mfrm_anchor_drift or mfrm_equating_chain object.

type

Plot type: "drift" (dot plot of element drift), "chain" (cumulative offset line plot), or "heatmap" (wave-by-element drift heatmap).

facet

Optional character vector to filter drift plots to specific facets.

preset

Visual preset ("standard", "publication", or "compact").

draw

If FALSE, return the plot data invisibly without drawing.

...

Additional graphical parameters passed to base plotting functions.

Value

A plotting-data object of class mfrm_plot_data. With draw = FALSE, result$data$table contains the filtered drift or chain table, result$data$matrix contains the heatmap matrix when requested, and the payload includes package-native title, subtitle, legend, and reference_lines.

Details

Three plot types are supported:

  • "drift" (for mfrm_anchor_drift objects): A dot plot of each element's drift value, grouped by facet. Horizontal reference lines mark the drift threshold. Red points indicate flagged elements.

  • "heatmap" (for mfrm_anchor_drift objects): A wave-by-element heat matrix showing drift magnitude. Darker cells represent larger absolute drift. Useful for spotting systematic patterns (e.g., all criteria shifting in the same direction).

  • "chain" (for mfrm_equating_chain objects): A line plot of cumulative offsets across the screened linking chain. A flatter line indicates smaller between-wave shifts; steep segments suggest larger link offsets that deserve review.

Which plot should I use?

  • Use type = "drift" with an mfrm_anchor_drift object to review flagged elements directly.

  • Use type = "heatmap" with an mfrm_anchor_drift object to spot wave-by-element patterns.

  • Use type = "chain" with an mfrm_equating_chain object after build_equating_chain() to inspect cumulative offsets across waves.

Interpreting plots

Drift is the change in an element's estimated measure between calibration waves, after accounting for the screened common-element link offset. An element is flagged when its absolute drift exceeds a threshold (typically 0.5 logits) and the drift-to-SE ratio exceeds a secondary criterion (typically 2.0), ensuring that only practically noticeable and relatively precise shifts are flagged.

  • In drift and heatmap plots, red or dark-shaded elements exceed both thresholds. Common causes include rater drift over time, item exposure effects, or curriculum changes.

  • In chain plots, uneven spacing between waves suggests differential shifts in the screened linking offsets. The \(y\)-axis shows cumulative logit-scale offsets; flatter segments indicate more stable adjacent links. Steep segments should be checked alongside LinkSupportAdequate and the retained common-element counts before making longitudinal claims.

  • For drift objects, it is usually best to read summary(x) first and then use the plot to see where the flagged values sit.

Typical workflow

  1. Build a drift or screened-linking object with detect_anchor_drift() or build_equating_chain().

  2. Start with draw = FALSE if you want the plotting data for custom reporting.

  3. Use the base-R plot for quick screening and then inspect the underlying tables for exact values.

Further guidance

For a plot-selection guide and a longer walkthrough, see mfrmr_visual_diagnostics and vignette("mfrmr-visual-diagnostics", package = "mfrmr").

Examples

toy <- load_mfrmr_data("example_core")
people <- unique(toy$Person)
d1 <- toy[toy$Person %in% people[1:12], , drop = FALSE]
d2 <- toy[toy$Person %in% people[13:24], , drop = FALSE]
fit1 <- fit_mfrm(d1, "Person", c("Rater", "Criterion"), "Score",
                 method = "JML", maxit = 10)
#> Warning: Optimizer did not fully converge (code = 1). Consider increasing maxit (current: 10) or relaxing reltol (current: 1e-06).
fit2 <- fit_mfrm(d2, "Person", c("Rater", "Criterion"), "Score",
                 method = "JML", maxit = 10)
#> Warning: Optimizer did not fully converge (code = 1). Consider increasing maxit (current: 10) or relaxing reltol (current: 1e-06).
drift <- detect_anchor_drift(list(W1 = fit1, W2 = fit2))
#> Warning: Thin linking support between 'W1' and 'W2': fewer than 5 retained common elements in Criterion, Rater.
drift_plot <- plot_anchor_drift(drift, type = "drift", draw = FALSE)
class(drift_plot)
#> [1] "mfrm_plot_data" "list"          
names(drift_plot$data)
#> [1] "plot"            "table"           "title"           "subtitle"       
#> [5] "legend"          "reference_lines" "preset"          "plot_name"      
chain <- build_equating_chain(list(F1 = fit1, F2 = fit2))
#> Warning: Thin linking support between 'F1' and 'F2': fewer than 5 retained common elements in Criterion, Rater.
chain_plot <- plot_anchor_drift(chain, type = "chain", draw = FALSE)
head(chain_plot$data$table)
#> # A tibble: 2 × 2
#>   Wave  Cumulative_Offset
#>   <chr>             <dbl>
#> 1 F1               0     
#> 2 F2              -0.0705
if (interactive()) {
  plot_anchor_drift(drift, type = "heatmap", preset = "publication")
}