% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/targeting_plot.R
\name{RMtargeting}
\alias{RMtargeting}
\title{Person-Item Targeting Plot (Wright Map)}
\usage{
RMtargeting(
  data,
  robust = FALSE,
  sort_items = c("data", "location"),
  bins,
  xlim = c(-4, 4),
  ci_level = 0.95,
  person_fill = "#0072B2",
  threshold_fill = "#D55E00",
  height_ratios = c(3, 2, 5),
  output = "patchwork"
)
}
\arguments{
\item{data}{A data.frame or matrix of item responses. Items must be scored
starting at 0 (non-negative integers). Missing values (\code{NA}) are allowed.}

\item{robust}{Logical. If \code{FALSE} (the default), histogram annotations use
mean ± SD. If \code{TRUE}, median ± MAD is used instead.}

\item{sort_items}{Character string controlling item ordering on the y-axis
of the bottom panel. \code{"data"} (the default) preserves the column order in
\code{data} (first item at top). \code{"location"} sorts items by their average
threshold location (easiest at top, hardest at bottom).}

\item{bins}{Integer. Number of bins for both histograms. Default is number of
unique scores divided by 2, but no less than 11.}

\item{xlim}{Numeric vector of length 2. Initial lower and upper limits for
the shared x-axis. Automatically expanded if any person or item threshold
values fall outside these limits.}

\item{ci_level}{Numeric. Confidence level for the item threshold error bars.
Default is \code{0.95} (95\% CI). Set to \code{NULL} to hide error bars.}

\item{person_fill}{Fill colour for the person histogram. Default
\code{"#0072B2"} (blue).}

\item{threshold_fill}{Fill colour for the item threshold histogram. Default
\code{"#D55E00"} (vermillion).}

\item{height_ratios}{Numeric vector of length 3 specifying the relative
heights of the top (person), middle (threshold), and bottom (dot-whisker)
panels. Default \code{c(3, 2, 5)}.}

\item{output}{Character string. \code{"patchwork"} (the default) returns the
combined patchwork plot. \code{"list"} returns a named list of the three
ggplot objects (\code{p1}, \code{p2}, \code{p3}) for further customisation.}
}
\value{
\itemize{
\item If \code{output = "patchwork"}: a \code{patchwork} object (combined \code{ggplot}).
\item If \code{output = "list"}: a named list with elements \code{p1} (person histogram),
\code{p2} (threshold histogram), and \code{p3} (item threshold dot-whisker plot).
}
}
\description{
Produces a three-panel targeting plot with a shared logit scale x-axis:
\enumerate{
\item \strong{Top}: Histogram of person location estimates, with a
reference line for the mean (or median) and shading for ±1 SD
(or ±1 MAD).
\item \strong{Middle}: Inverted histogram of item threshold locations,
with the same summary annotations.
\item \strong{Bottom}: Dot-and-whisker plot of individual item thresholds
with confidence intervals based on threshold standard errors.
}
}
\details{
Together, the top and middle panels form a back-to-back histogram that
makes it easy to assess whether the test is well-targeted to the sample.

\strong{Estimation method selection.}
The function checks whether any item response category has fewer than 3
observations. If all categories have at least 3 responses, item threshold
locations and their standard errors are estimated via Conditional Maximum
Likelihood (CML) using \code{psychotools::pcmodel()} (a dichotomous item is a
2-category PCM). If any category has fewer than 3 responses, the function
falls back to Marginal Maximum Likelihood (MML) estimation via
\code{mirt::mirt()} with \code{itemtype = "Rasch"} and \code{SE = TRUE}, which is more
numerically stable under sparse-category conditions. A message is emitted
when the MML fallback is used.

In both cases, item threshold locations are centered (shifted so the grand
mean of all thresholds equals zero).

\strong{Person estimates} are obtained by Warm's weighted likelihood (WLE)
from the fitted item thresholds, consistent with the rest of the package.
WLE is finite at extreme scores, so all-zero and perfect responders are
located rather than dropped.

\strong{Confidence intervals} for item thresholds are based on Wald-type
intervals: threshold estimate ± z × SE, where z is the standard normal
quantile corresponding to \code{ci_level}.

The \code{ggplot2} and \code{patchwork} packages must be installed (they are in
Suggests, not Imports).
}
\examples{
\donttest{
if (requireNamespace("ggplot2", quietly = TRUE) &&
    requireNamespace("patchwork", quietly = TRUE)) {
  # Polytomous example
  set.seed(42)
  sim_data <- as.data.frame(
    matrix(sample(0:3, 200 * 8, replace = TRUE), nrow = 200, ncol = 8)
  )
  colnames(sim_data) <- paste0("Item", 1:8)

  # Default: mean/SD, data order, 95\% CI
  RMtargeting(sim_data)

  # Robust (median/MAD), sorted by location, 84\% CI
  RMtargeting(sim_data, robust = TRUE, sort_items = "location",
              ci_level = 0.84)

  # Get list of sub-plots for customisation
  plots <- RMtargeting(sim_data, output = "list")
  plots$p1 + ggplot2::ggtitle("My custom title")

  # Dichotomous example
  sim_bin <- as.data.frame(
    matrix(sample(0:1, 200 * 10, replace = TRUE), nrow = 200, ncol = 10)
  )
  colnames(sim_bin) <- paste0("Item", 1:10)
  RMtargeting(sim_bin)
}
}
}
\references{
Wright, B. D. & Stone, M. H. (1979). \emph{Best Test Design}. MESA Press.
}
\seealso{
\code{\link[psychotools:pcmodel]{psychotools::pcmodel()}}, \code{\link[mirt:mirt]{mirt::mirt()}}
}
