
Build a category curve export bundle (preferred alias)
Source:R/api-reports.R
category_curves_report.RdBuild a category curve export bundle (preferred alias)
Usage
category_curves_report(
fit,
theta_range = c(-6, 6),
theta_points = 241,
digits = 4,
include_fixed = FALSE,
fixed_max_rows = 400
)Arguments
- fit
Output from
fit_mfrm().- theta_range
Theta/logit range for curve coordinates.
- theta_points
Number of points on the theta grid.
- digits
Rounding digits for numeric graph output.
- include_fixed
If
TRUE, include a legacy-compatible fixed-width text block.- fixed_max_rows
Maximum rows shown in fixed-width graph tables.
Details
Preferred high-level API for category-probability curve exports.
Returns tidy curve coordinates and summary metadata for quick
plotting/report integration without calling low-level helpers directly.
The expected-score table also carries the per-curve score variance and
information function. For GPCM, the information column follows the
Muraki/Samejima identity \(a^2 \mathrm{Var}(X \mid \theta)\);
for RSM / PCM, this reduces to the usual score variance because
discrimination is fixed at one. The category_information table decomposes
that total into category-level contributions,
\(a^2 P_k(\theta)(k - E[X \mid \theta])^2\), whose sum equals the
reported information at the same theta value. The
cumulative_probabilities table follows the FACETS / Winsteps graph
convention of accumulating modeled probabilities across ordered categories
(P(X <= k) by default, with P(X >= k) also returned for flipped curves).
cumulative_boundaries reports approximate theta values where
P(X <= k) = .5, with BoundaryStatus and CrossingCount to avoid
over-interpreting boundaries outside the requested theta range or with
multiple crossings.
Interpreting output
Use this report to inspect:
where each category has highest probability across theta
where cumulative category probabilities cross .5
whether adjacent categories cross in expected order
whether probability bands look compressed (often sparse categories)
Recommended read order:
summary(out)for compact diagnostics.out$probabilities,out$expected_ogive, andout$category_informationfor custom graphics.plot(out)for a default visual check, orplot(out, type = "cumulative")to inspect cumulative probabilities.plot(out, type = "information")to inspect curve-level information. Useplot(out, type = "category_information")when category-level contributions are needed.
References
Category response curves follow Andrich's rating-scale formulation,
Masters' partial-credit model, and Muraki's generalized partial-credit
model. The Information column for bounded GPCM uses Muraki's
item-information result obtained from Samejima's general polytomous
information formula.
Andrich, D. (1978). A rating formulation for ordered response categories. Psychometrika, 43(4), 561-573.
Masters, G. N. (1982). A Rasch model for partial credit scoring. Psychometrika, 47(2), 149-174.
Muraki, E. (1992). A generalized partial credit model: Application of an EM algorithm. Applied Psychological Measurement, 16(2), 159-176. doi:10.1177/014662169201600206
Muraki, E. (1993). Information functions of the generalized partial credit model. Applied Psychological Measurement, 17(4), 351-363. doi:10.1177/014662169301700403
Typical workflow
Fit model with
fit_mfrm().Run
category_curves_report()with suitabletheta_points.Use
summary()andplot(); export tables for manuscripts/dashboard use.plot(out)gives a four-panel overview. Usepreset = "monochrome"for grayscale/line-type output andboundary_status = "none"when cumulative.5boundary lines should be suppressed.plot(out, type = "category_probability")andplot(out, type = "conditional_probability")are explicit aliases for the same category-probability curves astype = "ccc". Useplot_data(out, component = "plot_long")when rebuilding the curves with ggplot2, plotly, or another R graphics system.
Examples
# \donttest{
toy <- load_mfrmr_data("example_core")
fit <- fit_mfrm(toy, "Person", c("Rater", "Criterion"), "Score", method = "JML", maxit = 30)
#> Warning: Optimization convergence review did not produce an inference-ready numerical solution (code = 1, status = iteration_limit). Optimizer reached the iteration limit before the terminal gradient became small enough for review-only acceptance. Inspect the model specification, data support, and starting values. Do not interpret estimates until the review is resolved.
out <- category_curves_report(fit, theta_points = 101)
summary(out)
#> mfrmr Category Curves Summary
#> Class: mfrm_category_curves
#> Components: 8
#>
#> Curve grid summary
#> Metric Value
#> curve_groups 1.000
#> theta_points 101.000
#> categories 4.000
#> legacy_graph_rows 101.000
#> expected_ogive_rows 101.000
#> probability_rows 404.000
#> probability_columns 4.000
#> cumulative_probability_rows 808.000
#> cumulative_boundary_rows 3.000
#> category_information_rows 404.000
#> boundary_rows_needing_review 0.000
#> boundary_rows_outside_theta_range 0.000
#> boundary_rows_with_multiple_crossings 0.000
#> max_total_information 0.661
#> max_category_information 0.283
#>
#> Boundary / curve rows: cumulative_boundaries
#> CurveGroup BoundaryOrder LowerOrEqualCategory AboveCategory ThresholdCategory
#> Common 1 1 2 2
#> Common 2 2 3 3
#> Common 3 3 4 4
#> CumulativeDirection TargetProbability ThurstonianThreshold InThetaRange
#> at_or_below 0.5 -1.540 TRUE
#> at_or_below 0.5 -0.034 TRUE
#> at_or_below 0.5 1.572 TRUE
#> CrossingCount BoundaryStatus BoundaryLabel
#> 1 in_range P(X <= 1) = 0.5
#> 1 in_range P(X <= 2) = 0.5
#> 1 in_range P(X <= 3) = 0.5
#>
#> Settings
#> Setting Value
#> theta_range -6, 6
#> theta_points 101
#> digits 4
#> include_fixed FALSE
#> fixed_max_rows 400
#> scales <table 1x2>
#>
#> Notes
#> - Category-curve bundle with probabilities, cumulative probabilities, total
#> information, and category-specific information.
#> - Category-specific information contributions sum to total information at the
#> same curve and theta point.
#> - Cumulative .5 boundary rows are in range with a single crossing where
#> reported.
head(out$probabilities[, c("CurveGroup", "Theta", "Category", "Probability")])
#> CurveGroup Theta Category Probability
#> 1 Common -6.00 1 0.9907
#> 2 Common -5.88 1 0.9896
#> 3 Common -5.76 1 0.9882
#> 4 Common -5.64 1 0.9868
#> 5 Common -5.52 1 0.9851
#> 6 Common -5.40 1 0.9832
p_overview <- plot(out, draw = FALSE)
p_overview$data$plot
#> [1] "overview"
p_cum <- plot(out, type = "cumulative", draw = FALSE)
head(p_cum$data$cumulative_boundaries)
#> CurveGroup BoundaryOrder LowerOrEqualCategory AboveCategory ThresholdCategory
#> 1 Common 1 1 2 2
#> 2 Common 2 2 3 3
#> 3 Common 3 3 4 4
#> CumulativeDirection TargetProbability ThurstonianThreshold InThetaRange
#> 1 at_or_below 0.5 -1.5400 TRUE
#> 2 at_or_below 0.5 -0.0335 TRUE
#> 3 at_or_below 0.5 1.5722 TRUE
#> CrossingCount BoundaryStatus BoundaryLabel
#> 1 1 in_range P(X <= 1) = 0.5
#> 2 1 in_range P(X <= 2) = 0.5
#> 3 1 in_range P(X <= 3) = 0.5
p_info <- plot(out, type = "category_information", draw = FALSE)
head(p_info$data$category_information)
#> CurveGroup Theta Category Probability ExpectedScore ScoreVariance Information
#> 1 Common -6.00 1 0.9907 1.0093 0.0092 0.0092
#> 2 Common -5.88 1 0.9896 1.0105 0.0104 0.0104
#> 3 Common -5.76 1 0.9882 1.0118 0.0117 0.0117
#> 4 Common -5.64 1 0.9868 1.0133 0.0132 0.0132
#> 5 Common -5.52 1 0.9851 1.0150 0.0149 0.0149
#> 6 Common -5.40 1 0.9832 1.0169 0.0167 0.0167
#> CategoryInformation CategoryInformationShare Slope Model
#> 1 1e-04 0.0092 1 RSM
#> 2 1e-04 0.0104 1 RSM
#> 3 1e-04 0.0117 1 RSM
#> 4 2e-04 0.0132 1 RSM
#> 5 2e-04 0.0148 1 RSM
#> 6 3e-04 0.0167 1 RSM
curve_long <- plot_data(out, component = "plot_long")
head(curve_long[, c("PlotType", "Theta", "Series", "Value")])
#> PlotType Theta Series Value
#> 1 ogive -6.00 Common 1.0093
#> 2 ogive -5.88 Common 1.0105
#> 3 ogive -5.76 Common 1.0118
#> 4 ogive -5.64 Common 1.0133
#> 5 ogive -5.52 Common 1.0150
#> 6 ogive -5.40 Common 1.0169
# }