| Title: | Analysis and Visualization of Circular Data |
|---|---|
| Description: | Circumplex models, which organize constructs in a circle around two underlying dimensions, are popular for studying interpersonal functioning, mood/affect, and vocational preferences/environments. This package provides tools for analyzing and visualizing circular data, including scoring functions for relevant instruments and a generalization of the bootstrapped structural summary method from Zimmermann & Wright (2017) <doi:10.1177/1073191115621795> and functions for creating publication-ready tables and figures from the results. |
| Authors: | Jeffrey Girard [aut, cre] (ORCID: <https://orcid.org/0000-0002-7359-3746>), Johannes Zimmermann [aut] (ORCID: <https://orcid.org/0000-0001-6975-2356>), Aidan Wright [aut] (ORCID: <https://orcid.org/0000-0002-2369-0601>) |
| Maintainer: | Jeffrey Girard <[email protected]> |
| License: | GPL-3 |
| Version: | 2.0.0 |
| Built: | 2026-07-24 05:01:29 UTC |
| Source: | https://github.com/jmgirard/circumplex |
Display the anchors of a circumplex instrument including the total number of anchors and each anchor's numerical value and text label. Anchors are the response options that respondants select from (e.g., 0 = No, 1 = Yes).
anchors(x)anchors(x)
x |
Required. An object of the instrument class. |
The same input object. Prints text to console.
Other instrument functions:
instruments(),
items(),
norms(),
scales()
anchors(csip)anchors(csip)
Unwrap a temporally ordered sequence of angular displacements (e.g., one
displacement per measurement wave) onto a continuous numeric branch, so
that a trajectory drifting across the 0/360 boundary becomes a smooth
sequence suitable for linear growth modeling. Each input is first wrapped
to [0, 360) (any real numbers are accepted); the output then starts at the
first wave's wrapped value and accumulates the shortest signed rotation
between successive waves, so successive values never differ by more than
180 degrees. For example, c(350, 10, 30) unwraps to c(350, 370, 390).
angle_unwrap(x)angle_unwrap(x)
x |
A numeric vector of angles in degrees, in temporal order. Any real values are accepted and are wrapped to [0, 360) first. |
Two conventions are pinned. An exact 180-degree step is directionally
ambiguous; it is resolved as +180 (ascending), matching the package's
contrast convention of reporting an exact half-turn as +180. A missing
wave makes every subsequent step branch-ambiguous, so NA propagates from
the missing wave onward rather than silently bridging the gap.
Unwrapping assumes the sequence really does move by less than a half-turn between successive waves; when the truth moves faster than the sampling (or persons occupy heterogeneous locations with no common branch), the unwrapped branch is wrong without warning. See the package's growth modeling vignette for these failure modes and the bivariate (x, y) alternative that avoids them.
A plain numeric vector of the same length: the unwrapped angles in degrees on a continuous branch anchored at the first wave's wrapped value. Values may legitimately fall outside [0, 360); the LM = 360 reporting convention applies to displacements, not to the unwrapped branch (an input of 360 anchors at 0).
angle_unwrap(c(350, 10, 30)) angle_unwrap(c(10, 350, 330)) angle_unwrap(c(350, NA, 30))angle_unwrap(c(350, 10, 30)) angle_unwrap(c(10, 350, 330)) angle_unwrap(c(350, NA, 30))
A small example dataset containing standardized scores on eight hypothetical circumplex scales. Taken from Wright, Pincus, Conroy, & Hilsenroth (2009).
aw2009aw2009
A data frame with 5 observations and 8 variables:
circumplex scale at 90 degrees
circumplex scale at 135 degrees
circumplex scale at 180 degrees
circumplex scale at 225 degrees
circumplex scale at 270 degrees
circumplex scale at 315 degrees
circumplex scale at 360 degrees
circumplex scale at 45 degrees
Estimate the reliability (and standard error of measurement) of the two
circumplex axes of an octant instrument with the item-level restricted
tau-equivalent CFA of Strack, Jacobs, and Grosse Holtforth (2013). The model
decomposes each item's variance into orthogonal components – a general
factor, the two circumplex axes, scale specificity, and item specificity –
and reads the axes' reliability off the isolated axes-variance component with
the Spearman-Brown formula. It is a confirmatory, item-level complement to
fit_structure()'s exploratory scale-level criteria.
axes_reliability(data, items, angles = NULL, instrument = NULL, sd = "std")axes_reliability(data, items, angles = NULL, instrument = NULL, sd = "std")
data |
A data frame (or matrix) containing the circumplex items. |
items |
Item selection. With |
angles |
A numeric vector of the scales' angles in degrees (one per
scale), required for the explicit map and forbidden with |
instrument |
Optional. A |
sd |
The scale for the standard error of measurement: |
The model is fit to the item correlation matrix (the items are z-standardized) as a flat fixed-links CFA: every item loads on the two axes with fixed cosine weights, on a general factor with weight one, and on its scale's specificity factor with weight one; the two axis variances are held equal (the circumplex "no preferred rotation" axiom) and every scale-specificity variance shares one value, while item errors stay free (tau-equivalent). Only the axes-variance component feeds reliability.
The Nunnally-Bernstein axis reliability (nb_reliability) is reported
alongside for comparison: it overestimates axis reliability when scale
specificity is large, because it charges scale-specificity variance to the
axis rather than isolating it (Strack et al. 2013, Figure 3).
Because the model is fit to the item correlation matrix as if it were a
covariance matrix (the paper's own practice), the component point estimates
and the reliabilities are correct, but the component standard errors and the
global chi-square are approximate (Cudeck, 1989). Results are reported
per axis (X and Y): for a balanced octant instrument the two axes carry
the same axes-variance estimate and differ only through item_n.
Missing data are handled by listwise deletion only (a message reports the
complete-case count); pairwise correlation input is never used. A boundary
fit (a non-positive estimated axes variance, or any negative estimated
variance) returns NA reliability and SEm with a warning and a boundary flag
rather than a clipped or negative value.
An object of class circumplex_axes_reliability with print() and
summary() methods: results (one row per axis: the axes variance, item_n,
reliability, SEm, Nunnally-Bernstein reliability, and boundary flag),
components (the estimated variance components with SEs), fit (global fit
indices), and details.
Strack, S., Jacobs, K. A., & Grosse Holtforth, M. (2013). The reliability of circumplex axes. SAGE Open, 3(2). doi:10.1177/2158244013486115
Cudeck, R. (1989). Analysis of correlation matrices using covariance structure models. Psychological Bulletin, 105(2), 317-327.
fit_structure() for exploratory circumplex-structure criteria.
# A simulated 32-item octant dataset (four items per octant scale). data("simulated_items") # Map the item columns to their eight scales (four items each), in the # octants() angle order, then estimate the axes reliability. items <- split(names(simulated_items), rep(1:8, each = 4)) res <- axes_reliability(simulated_items, items = items, angles = octants()) res summary(res)# A simulated 32-item octant dataset (four items per octant scale). data("simulated_items") # Map the item columns to their eight scales (four items each), in the # octants() angle order, then estimate the axes reliability. items <- split(names(simulated_items), rep(1:8, each = 4)) res <- axes_reliability(simulated_items, items = items, angles = octants()) res summary(res)
A ggplot2 coordinate system that maps Structural Summary Method
parameters onto the circular circumplex canvas: the displacement aesthetic
(degrees, counterclockwise from the right, with the 0/360 pole labelled 360)
becomes the angle and the amplitude aesthetic becomes the radius. It owns
the amplitude-to-radius scaling, so geom_ssm_point() and geom_ssm_arc()
no longer take an amax, and the canvas and data layers can never disagree.
coord_circumplex(amax = NULL, center = 0, r_axis_angle = NULL, ...)coord_circumplex(amax = NULL, center = 0, r_axis_angle = NULL, ...)
amax |
Optional. A single positive number giving the amplitude
represented by the outer ring. |
center |
Optional. A single number giving the amplitude at the center of the circle (default = 0). Ring labels and the amplitude-to-radius mapping are guaranteed to agree. |
r_axis_angle |
Optional. A single number giving the displacement (in
degrees) along which the amplitude (radial) axis and its labels are drawn.
|
... |
Reserved for future extensions; currently unused. |
coord_circumplex() subclasses ggplot2::coord_radial() and hard-pins the
angular convention (displacement 0 at the right, increasing counterclockwise,
the 0/360 range with no expansion) so the circumplex angle invariants survive
the transform. The amplitude at the circle's center and at its outer ring are
the radial limits, set once here.
A ggplot2 coordinate system that can be added to a plot with
+.
Other circumplex layers:
geom_ssm_arc(),
geom_ssm_path(),
geom_ssm_point(),
ggcircumplex(),
scale_x_circumplex(),
theme_circumplex()
data("jz2017") res <- ssm_analyze(jz2017, scales = 2:9, measures = "NARPD") ggplot2::ggplot(res$results) + coord_circumplex(amax = 0.5) + geom_ssm_point(ggplot2::aes(amplitude = a_est, displacement = d_est))data("jz2017") res <- ssm_analyze(jz2017, scales = 2:9, measures = "NARPD") ggplot2::ggplot(res$results) + coord_circumplex(amax = 0.5) + geom_ssm_point(ggplot2::aes(amplitude = a_est, displacement = d_est))
Estimate Browne's (1992) circular stochastic process model (CPM) for the correlational structure of a set of circumplex scales or items, the native replacement for the archived CircE package. Each variable is modeled as a point on a circle at an estimated angle, with a communality index and a shared correlation function; the fit of that structure is summarized with the usual covariance-structure indices (chi-square, RMSEA, SRMR, CFI, TLI).
cpm_fit( data = NULL, scales = NULL, angles = octants(), cormat = NULL, n = NULL, m = 3, model = c("quasi-circumplex", "constrained-angles", "equal-communality", "circulant"), scaling = c("unit", "free"), reference = 1, interval = 0.95, ci_method = c("bootstrap", "analytic"), boots = 2000, listwise = TRUE )cpm_fit( data = NULL, scales = NULL, angles = octants(), cormat = NULL, n = NULL, m = 3, model = c("quasi-circumplex", "constrained-angles", "equal-communality", "circulant"), scaling = c("unit", "free"), reference = 1, interval = 0.95, ci_method = c("bootstrap", "analytic"), boots = 2000, listwise = TRUE )
data |
A data frame or matrix containing the circumplex scales (raw-data
path). Supply exactly one of |
scales |
For the raw-data path, a character vector of column names (or a
numeric vector of column indexes) selecting the circumplex scales. For the
|
angles |
A numeric vector of the theoretical angular displacement of
each scale, in degrees, used both as the reference/identifying angle and as
optimization start values (default = |
cormat |
A correlation matrix (the matrix-input path, CircE-style).
Supply exactly one of |
n |
For the |
m |
The number of harmonics in the correlation function (default = 3,
the octant-scale convention). Capped at |
model |
The model variant (design of Browne 1992): |
scaling |
The covariance-scaling family, orthogonal to |
reference |
The index into |
interval |
The confidence level for the parameter intervals (default = 0.95). The RMSEA interval is always the conventional 90 percent. |
ci_method |
How to construct the parameter confidence intervals:
|
boots |
The number of bootstrap resamples for
|
listwise |
Whether to handle missing values by listwise deletion. Only listwise deletion is supported in this release (default = TRUE). |
A circumplex_cpm object: a list with results (a data frame of
estimated angles and communality indices with confidence intervals),
betas (the correlation-function weights), fit (the fit indices),
corfun (the estimated correlation function), matrices (the sample and
model-implied matrices and residuals), and details (model, diagnostics,
and settings). See print.circumplex_cpm() and summary.circumplex_cpm().
The bootstrap (the raw-data default) refits the model to each resampled
correlation matrix, warm-started from the reported solution, and forms
percentile intervals; angle replicates are pooled with the package's
circular quantile machinery, so an angle interval that straddles the
0/360 boundary is reported wrapped (its lower limit numerically exceeds
its upper limit, as with displacement intervals in ssm_analyze()).
Resamples with a degenerate (non-positive-definite) correlation matrix or
a refit failing the convergence acceptance criterion are excluded with a
warning reporting how many; the intervals are then conditional on
estimability. Analytic (Wald) intervals are asymptotically valid but can
materially mis-cover at field-typical sample sizes; summary() prints a
caution below n = 2000. Analytic angle intervals are reported on the
unwrapped branch of the estimate (endpoints may fall outside [0, 360)
near the boundary).
Only the bootstrap consumes R's random number stream; the engine's point
estimates, fit indices, and the analytic intervals are deterministic, so
the estimates are identical across seeds and the default cormat-path
fit never touches the stream. Call set.seed() immediately before
cpm_fit() for reproducible bootstrap intervals. All resample indices
are drawn in one block before any refitting, so a given seed yields the
same intervals regardless of how many replicates are later excluded.
Browne, M. W. (1992). Circumplex models for correlation matrices. Psychometrika, 57(4), 469-497.
Other analysis functions:
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
# Raw-data path on the eight IIP-SC octant scales (bootstrap CIs; a small # `boots` keeps the example fast -- the default is 2000) data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") set.seed(12345) fit <- cpm_fit(jz2017, scales = scales, boots = 100) fit # Matrix-input path (supply the sample size; analytic CIs) R <- cor(jz2017[scales]) cpm_fit(cormat = R, scales = scales, n = nrow(jz2017))# Raw-data path on the eight IIP-SC octant scales (bootstrap CIs; a small # `boots` keeps the example fast -- the default is 2000) data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") set.seed(12345) fit <- cpm_fit(jz2017, scales = scales, boots = 100) fit # Matrix-input path (supply the sample size; analytic CIs) R <- cor(jz2017[scales]) cpm_fit(cormat = R, scales = scales, n = nrow(jz2017))
Draw n standardized observations from the model-implied correlation matrix
of a fitted cpm_fit() object, using the low-rank factor
representation (Browne, 1992;
design sec. 1.3/sec. 5.4). Each observation is generated as
with independent
standard-normal common-factor scores and unique deviates
, so the draws are exactly positive semidefinite by
construction (no eigenvalue clamping) and their population correlation matrix
is exactly.
cpm_simulate(object, n)cpm_simulate(object, n)
object |
A |
n |
The number of observations (rows) to simulate; a positive whole number. |
This is the mean-based simulation path of the SSM CI-trustworthiness
diagnostic (ssm_ci_accuracy(); the M4 Brief-B contract): a caller draws
standardized data here and rescales it to a group's means and SDs. The
correlation-based (augmented scales-plus-measures) path is not produced
here – it reduces to the returned population block object$matrices$Phat,
from which the caller assembles and repairs its own joint matrix.
A numeric matrix with n rows and one column per fitted scale,
columns in the fitted scale order with colnames set to the scale names
(rownames are NULL). The population covariance is
object$matrices$Phat, so cov() of the returned matrix converges to it
as n grows. Under the default unit scaling Phat is a correlation matrix
(zero-mean, unit-variance margins), so cor() converges to it too; under
scaling = "free" the margins carry the fitted variance ratios
.
cpm_simulate() consumes R's global random number stream (the
common-factor scores then the unique deviates, drawn in that fixed order),
so it follows the package's set.seed()-immediately-before convention: a
given seed reproduces the draw exactly. It is one of the package's
stochastic entry points (alongside ssm_analyze() and the bootstrap path
of cpm_fit()); the fit itself is deterministic.
Browne, M. W. (1992). Circumplex models for correlation matrices. Psychometrika, 57(4), 469-497.
Other analysis functions:
cpm_fit(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") fit <- cpm_fit(cormat = cor(jz2017[scales]), scales = scales, n = nrow(jz2017)) set.seed(1) x <- cpm_simulate(fit, n = 500) round(cor(x) - fit$matrices$Phat, 2)data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") fit <- cpm_fit(cormat = cor(jz2017[scales]), scales = scales, n = nrow(jz2017)) set.seed(1) x <- cpm_simulate(fit, n = 500) round(cor(x) - fit$matrices$Phat, 2)
Run the exploratory circumplex-structure criteria of Acton and Revelle (2004) on a set of scales and return one object bundling all of the tests. Four criteria are computed from the first two unrotated principal-axis factors of the scales' correlation matrix – the Fisher Test of equal axes, the Gap Test of equal spacing, the Variance Test (VT2) and Rotation Test of interstitiality – and each statistic is classified against simulation-derived, scoring- and scale-count-specific cutoffs. A fifth test, RANDALL (Hubert & Arabie, 1987; Tracey, 1997), evaluates the hypothesised circular order of the scales with a randomization test that yields a genuine p-value.
fit_structure( data, scales, scoring = c("deviation", "raw"), ridge = 0, n_perm = NULL, listwise = TRUE )fit_structure( data, scales, scoring = c("deviation", "raw"), ridge = 0, n_perm = NULL, listwise = TRUE )
data |
A data frame (or matrix) containing the circumplex scales. |
scales |
A character vector of column names (or a numeric vector of column indexes) selecting the circumplex scales, in hypothesised circular order (the order is RANDALL's order hypothesis). At least four scales are required. |
scoring |
Either |
ridge |
A non-negative ridge added to the diagonal of the correlation
matrix (then rescaled to a unit diagonal) to repair a non-positive-definite
matrix before factoring; default |
n_perm |
|
listwise |
A logical indicating whether missing values are handled by
listwise deletion ( |
The four factor-analytic criteria have the most power when there is no large
general factor, which deviation scoring (centering each respondent on their
own mean across the scales, exactly what ipsatize() does) approximates by
removing it (Acton & Revelle, 2004, p. 9). Deviation scoring is therefore the
default and is applied to all five tests; pass scoring = "raw" to leave the
scores untouched. The two scorings carry different cutoffs, matched
automatically.
The interpretive cutoffs are heuristic likelihood classifications read off
simulated distributions, not significance tests, and they are specific to
the number of scales. Only eight scales (the canonical octant instrument) are
calibrated; with any other count the statistics are still reported but no
interpretation is attached (see print()/summary()). The cutoffs were
re-derived under Acton and Revelle's own generating model at eight scales;
see vignette("evaluating-circumplex-structure"). RANDALL needs no cutoffs:
with up to nine scales its null distribution is enumerated exactly, so its
p-value is available at any scale count of four or more.
An object of class circumplex_structure with print(),
summary(), and plot() methods. Its components are results (a data
frame with one row per factor-analytic criterion: statistic, cutoffs, and
interpretive category), randall (the RANDALL index, p-value, and method),
loadings (the two unrotated principal-axis factors), and details.
Acton, G. S., & Revelle, W. (2004). Evaluation of ten psychometric criteria for circumplex structure. Methods of Psychological Research Online, 9(1), 1-27.
Hubert, L., & Arabie, P. (1987). Evaluating order hypotheses within proximity matrices. Psychological Bulletin, 102(1), 172-178.
Tracey, T. J. G. (1997). RANDALL: A Microsoft FORTRAN program for a randomization test of hypothesized order relations. Educational and Psychological Measurement, 57(1), 164-168.
cpm_fit() for a confirmatory circumplex model; ipsatize() for
deviation scoring.
data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") res <- fit_structure(jz2017, scales = scales) res summary(res)data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") res <- fit_structure(jz2017, scales = scales) res summary(res)
A ggplot2 layer that draws, for each profile, the wedge spanning its
amplitude confidence interval (radially) and its displacement confidence
interval (angularly) on a circumplex canvas built with coord_circumplex()
(for example the canvas from ggcircumplex()). The bounds are supplied
directly in SSM units; the coordinate system bends the (displacement,
amplitude) rectangle into an annular wedge.
geom_ssm_arc( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., amax = NULL, n = NULL, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )geom_ssm_arc( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., amax = NULL, n = NULL, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )
mapping, data, stat, position, show.legend, inherit.aes, ...
|
Standard
ggplot2 layer arguments. |
amax |
(Deprecated) The amplitude represented by
the outer ring is now owned by |
n |
(Deprecated) Arc smoothness is now owned by the coordinate system, which curves the wedge automatically; a value supplied here is ignored with a one-time note. |
na.rm |
If |
Each arc spans counterclockwise from displacement_min to
displacement_max (both in degrees). Supply them in [0, 360] (a bound of
exactly 360 is the 0/360 pole under the package's LM = 360 labeling). A
displacement_min greater than displacement_max is read as an interval
that crosses the 0/360 seam and is drawn the short way across it (e.g.
350 -> 10 is a 20 degree arc, matching how the package stores a
displacement CI that straddles the boundary). The interval must describe
less than a full circle; bounds that imply a span of 360 degrees or more
(for example, values outside [0, 360]) are rejected, since they do not
name a unique arc.
A ggplot2 layer.
Other circumplex layers:
coord_circumplex(),
geom_ssm_path(),
geom_ssm_point(),
ggcircumplex(),
scale_x_circumplex(),
theme_circumplex()
data("jz2017") res <- ssm_analyze(jz2017, scales = 2:9, measures = "NARPD") ggcircumplex(octants(), amax = 0.5) + geom_ssm_arc( data = res$results, mapping = ggplot2::aes( amplitude_min = a_lci, amplitude_max = a_uci, displacement_min = d_lci, displacement_max = d_uci ), alpha = 0.4 )data("jz2017") res <- ssm_analyze(jz2017, scales = 2:9, measures = "NARPD") ggcircumplex(octants(), amax = 0.5) + geom_ssm_arc( data = res$results, mapping = ggplot2::aes( amplitude_min = a_lci, amplitude_max = a_uci, displacement_min = d_lci, displacement_max = d_uci ), alpha = 0.4 )
A ggplot2 layer that connects a profile's successive positions on a
circumplex canvas built with coord_circumplex() (for example the canvas
from ggcircumplex()), so change in amplitude and displacement reads as
movement through circumplex space. Each segment is curved along the polar
geodesic by the coordinate system, which owns the transform; the layer owns
the ordering, the 0/360 seam handling, and the optional arrowheads.
geom_ssm_path( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., arrow = NULL, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )geom_ssm_path( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., arrow = NULL, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )
mapping, data, stat, position, show.legend, inherit.aes, ...
|
Standard
ggplot2 layer arguments. |
arrow |
An arrow specification produced by |
na.rm |
If |
Points are connected in the order the rows appear in the data, exactly as
ggplot2::geom_path() does, and the group aesthetic separates one series
from another. Sort the data into time order before plotting: an occasion
label sorted as text puts T10 before T2, which silently reverses time.
ssm_plot_circle(path = TRUE) does this sorting for you, taking the order
from the object's own occasion list.
Consecutive occasions are joined the short way around the circle. The
displacements of each group are unwrapped onto a continuous branch before the
coordinate system sees them, so a step from 350 to 10 degrees is drawn as
the 20 degree arc across the pole rather than a 340 degree sweep the long way
round. Unwrapped values may therefore fall outside [0, 360). This assumes
the profile rotates less than a half-turn between consecutive occasions at
which its displacement is defined; no data can verify that, so widely spaced
occasions should be read with it in mind.
An occasion with no defined location – a flat or zero-amplitude profile, whose displacement is undefined – breaks the path rather than being interpolated through, and the segment after the gap is still drawn on the correct branch. Non-finite amplitudes and displacements are treated the same way, since an infinite angle names no position on the circle.
A ggplot2 layer.
Other circumplex layers:
coord_circumplex(),
geom_ssm_arc(),
geom_ssm_point(),
ggcircumplex(),
scale_x_circumplex(),
theme_circumplex()
data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") # Three occasions that actually move: shifting the octant scores by one # position rotates the fitted profile by 45 degrees per occasion. waves <- lapply(1:3, function(k) { idx <- ((seq_along(scales) - 1 + (k - 1)) %% length(scales)) + 1 d <- jz2017[, scales[idx]] names(d) <- scales d$id <- seq_len(nrow(d)) d$occasion <- paste0("T", k) d }) res <- ssm_analyze_long(do.call(rbind, waves), scales = scales, id = "id", occasion = "occasion" ) ggcircumplex(octants(), amax = 0.5) + geom_ssm_point( data = res$results, mapping = ggplot2::aes(amplitude = a_est, displacement = d_est), size = 2 ) + geom_ssm_path( data = res$results, mapping = ggplot2::aes(amplitude = a_est, displacement = d_est), arrow = ggplot2::arrow( length = ggplot2::unit(0.18, "inches"), type = "closed" ) )data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") # Three occasions that actually move: shifting the octant scores by one # position rotates the fitted profile by 45 degrees per occasion. waves <- lapply(1:3, function(k) { idx <- ((seq_along(scales) - 1 + (k - 1)) %% length(scales)) + 1 d <- jz2017[, scales[idx]] names(d) <- scales d$id <- seq_len(nrow(d)) d$occasion <- paste0("T", k) d }) res <- ssm_analyze_long(do.call(rbind, waves), scales = scales, id = "id", occasion = "occasion" ) ggcircumplex(octants(), amax = 0.5) + geom_ssm_point( data = res$results, mapping = ggplot2::aes(amplitude = a_est, displacement = d_est), size = 2 ) + geom_ssm_path( data = res$results, mapping = ggplot2::aes(amplitude = a_est, displacement = d_est), arrow = ggplot2::arrow( length = ggplot2::unit(0.18, "inches"), type = "closed" ) )
A ggplot2 layer that places a point for each profile at its amplitude
and displacement on a circumplex canvas built with coord_circumplex() (for
example the canvas from ggcircumplex()). The amplitude and displacement are
supplied directly in SSM units (amplitude in the score metric, displacement
in degrees); the coordinate system performs the polar transform.
geom_ssm_point( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., amax = NULL, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )geom_ssm_point( mapping = NULL, data = NULL, stat = "identity", position = "identity", ..., amax = NULL, na.rm = TRUE, show.legend = NA, inherit.aes = TRUE )
mapping, data, stat, position, show.legend, inherit.aes, ...
|
Standard
ggplot2 layer arguments. |
amax |
(Deprecated) The amplitude represented by
the outer ring is now owned by |
na.rm |
If |
A ggplot2 layer.
Other circumplex layers:
coord_circumplex(),
geom_ssm_arc(),
geom_ssm_path(),
ggcircumplex(),
scale_x_circumplex(),
theme_circumplex()
data("jz2017") res <- ssm_analyze(jz2017, scales = 2:9, measures = "NARPD") ggcircumplex(octants(), amax = 0.5) + geom_ssm_point( data = res$results, mapping = ggplot2::aes(amplitude = a_est, displacement = d_est) )data("jz2017") res <- ssm_analyze(jz2017, scales = 2:9, measures = "NARPD") ggcircumplex(octants(), amax = 0.5) + geom_ssm_point( data = res$results, mapping = ggplot2::aes(amplitude = a_est, displacement = d_est) )
Build an empty circular canvas – the amplitude rings, displacement spokes,
and scale labels that circumplex figures are drawn on – as a ggplot2
object. Additional layers (points, arcs, annotations) can be added to it
with +, so it serves as the reusable foundation for custom circumplex
visualizations. The package's own ssm_plot_circle() draws on the same
canvas.
ggcircumplex( angles = octants(), labels = NULL, amax = 0.5, font_size = 12, instrument = NULL )ggcircumplex( angles = octants(), labels = NULL, amax = 0.5, font_size = 12, instrument = NULL )
angles |
Optional. A numeric vector of the angular position (in
degrees) of each circumplex scale, going counterclockwise from the right
(default = |
labels |
Optional. Either |
amax |
Optional. A single positive number giving the amplitude at the outer ring, which sets the amplitude-axis labels; the center of the circle is fixed at amplitude 0 (default = 0.5). |
font_size |
Optional. A single positive number giving the size (in pt) of the scale and amplitude labels (default = 12). |
instrument |
Optional. Either |
A ggplot2 object containing the empty circumplex canvas.
coord_circumplex(), which owns the transform this canvas is built
on; ssm_plot_circle(), which draws SSM results on this canvas.
Other circumplex layers:
coord_circumplex(),
geom_ssm_arc(),
geom_ssm_path(),
geom_ssm_point(),
scale_x_circumplex(),
theme_circumplex()
# A default octant canvas ggcircumplex() # Label the scales with their circumplex pole abbreviations ggcircumplex(octants(), labels = PANO()) # Derive the angles and labels from a circumplex instrument ggcircumplex(instrument = csip)# A default octant canvas ggcircumplex() # Label the scales with their circumplex pole abbreviations ggcircumplex(octants(), labels = PANO()) # Derive the angles and labels from a circumplex instrument ggcircumplex(instrument = csip)
Format a data frame as an HTML table and render it to the web viewer.
html_render(df, caption = NULL, align = "l", ...)html_render(df, caption = NULL, align = "l", ...)
df |
A data frame to be rendered as an HTML table. |
caption |
A string to be displayed above the table. |
align |
A string indicating the alignment of the cells (default = "l"). |
... |
Other arguments to pass to |
HTML syntax for the df table.
Other table functions:
ssm_table()
The circumplex package includes information about numerous circumplex
instruments including instructions for scoring and standardizing items.
Individual instruments can be loaded using the instrument function.
instruments()instruments()
Other instrument functions:
anchors(),
items(),
norms(),
scales()
instruments()instruments()
Rescore each circumplex item using deviation scoring across variables. In other words, subtract each observation's mean response from each response. This effectively removes the presence of a general factor, which can make certain circumplex fit analyses more powerful.
ipsatize(data, items, na.rm = TRUE, prefix = "", suffix = "_i", append = TRUE)ipsatize(data, items, na.rm = TRUE, prefix = "", suffix = "_i", append = TRUE)
data |
Required. A data frame or matrix containing at least circumplex scales. |
items |
Required. A character vector containing the column names, or a
numeric vector containing column indexes, of item variables in |
na.rm |
Optional. A logical that determines whether missing values should be ignored during the calculation of the mean during ipsatization (default = TRUE). |
prefix |
Optional. A string that will be added to the start of each
|
suffix |
Optional. A string that will be added to the end of each
|
append |
Optional. A logical that determines whether to append the
ipsatized scores to |
A data frame that matches data except that the variables specified
in items have been rescored using ipsatization.
Other tidying functions:
norm_standardize(),
score(),
self_standardize()
data("raw_iipsc") ipsatize(raw_iipsc, items = 1:32) ipsatize(raw_iipsc, items = sprintf("IIP%02d", 1:32))data("raw_iipsc") ipsatize(raw_iipsc, items = 1:32) ipsatize(raw_iipsc, items = sprintf("IIP%02d", 1:32))
Display the items of a circumplex instrument including the total number of
items and each item's number and text. The item ordering/numbering displayed
here is the same ordering/numbering assumed by the score() function.
items(x)items(x)
x |
Required. An object of the instrument class. |
The same input object. Prints text to console.
Other instrument functions:
anchors(),
instruments(),
norms(),
scales()
items(csip)items(csip)
A large example dataset containing gender, raw mean scores on the Inventory of Interpersonal Problems - Short Circumplex (IIP-SC), and raw sum scores on the Personality Diagnostic Questionnaire - 4th Edition Plus (PDQ-4+).
jz2017jz2017
A data frame with 1166 observations and 19 variables:
Self-reported Gender
Domineering Problems (IIP-SC) 90 degrees
Vindictive Problems (IIP-SC) 135 degrees
Cold Problems (IIP-SC) 180 degrees
Socially Avoidant Problems (IIP-SC) 225 degrees
Nonassertive Problems(IIP-SC) 270 degrees
Easily Exploited Problems (IIP-SC) 315 degrees
Overly Nurturant Problems (IIP-SC) 360 degrees
Intrusive Problems (IIP-SC) 45 degrees
Paranoid PD Symptoms (PDQ-4+)
Schizoid PD Symptoms (PDQ-4+)
Schizotypal PD Symptoms (PDQ-4+)
Antisocial PD Symptoms (PDQ-4+)
Borderline PD Symptoms (PDQ-4+)
Histrionic PD Symptoms (PDQ-4+)
Narcissistic PD Symptoms (PDQ-4+)
Avoidant PD Symptoms (PDQ-4+)
Dependent PD Symptoms (PDQ-4+)
Obsessive-Compulsive PD Symptoms (PDQ-4+)
Take in a data frame containing circumplex scales, angle definitions for each scale, and normative data (from the package or custom) and return that same data frame with each specified circumplex scale transformed into standard scores (i.e., z-scores) based on comparison to the normative data.
norm_standardize( data, scales, angles = octants(), instrument, sample = 1, prefix = "", suffix = "_z", append = TRUE )norm_standardize( data, scales, angles = octants(), instrument, sample = 1, prefix = "", suffix = "_z", append = TRUE )
data |
Required. A data frame or matrix containing at least circumplex scales. |
scales |
Required. A character vector containing the column names, or a numeric vector containing the column indexes, for the variables (scale scores) to be standardized. |
angles |
Required. A numeric vector containing the angular displacement
of each circumplex scale included in |
instrument |
Required. An instrument object from the package. To see the
available circumplex instruments, see |
sample |
Required. An integer corresponding to the normative sample to
use in standardizing the scale scores (default = 1). See |
prefix |
Optional. A string to include at the beginning of the newly
calculated scale variables' names, before the scale name and |
suffix |
Optional. A string to include at the end of the newly
calculated scale variables' names, after the scale name and |
append |
Optional. A logical that determines whether the calculated
standardized scores should be added as columns to |
A data frame that contains the norm-standardized versions of scales.
Other tidying functions:
ipsatize(),
score(),
self_standardize()
data("jz2017") norm_standardize(jz2017, scales = 2:9, instrument = iipsc, sample = 1)data("jz2017") norm_standardize(jz2017, scales = 2:9, instrument = iipsc, sample = 1)
Display the norms for a circumplex instrument including the total number of normative data sets available and each data set's number, sample size, population, and source reference and hyperlink. If another normative data set exists that is not yet included in the package, please let us know.
norms(x)norms(x)
x |
Required. An object of the instrument class. |
The same input object. Prints text to console.
Other instrument functions:
anchors(),
instruments(),
items(),
scales()
norms(csip)norms(csip)
Return a vector of angular displacements, in degrees, for eight equally
spaced circumplex scales corresponding to the circumplex octants. Can be
passed to the angles parameter of other functions in this package.
octants()octants()
A numeric vector with eight elements, each corresponding to the angular displacement (in degrees) of a subscale, in the following order: PA, BC, DE, FG, HI, JK, LM, NO.
octants()octants()
Return a vector of abbreviations for octant circumplex scales, from PA to NO.
PANO(case = "upper")PANO(case = "upper")
case |
An optional string the determines whether the abbreviations should be in uppercase or lowercase. (default = "upper") |
A character vector with eight elements, each corresponding to the abbreviation of an octant subscale: PA, BC, DE, FG, HI, JK, LM, NO.
PANO() PANO(case = "lower")PANO() PANO(case = "lower")
Draw the empirical coverage from an ssm_ci_accuracy() run against its
amplitude-ladder conditions: one panel per SSM parameter (including
displacement conditional on guardrail certification), one line per profile
row, with 95% Wilson score intervals as error bars, Bradley's (1978)
liberal robustness band shaded, and the nominal confidence level as a
dashed line. Amplitude rungs whose coverage is structurally zero (a
percentile interval of strictly positive amplitude replicates cannot
contain a zero truth; see ssm_ci_accuracy()) are drawn as open symbols.
This is a Cartesian diagnostic plot, not a circumplex figure.
## S3 method for class 'circumplex_ci_accuracy' plot(x, ...)## S3 method for class 'circumplex_ci_accuracy' plot(x, ...)
x |
A |
... |
Currently ignored. |
A ggplot2 object.
Other ssm functions:
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other visualization functions:
ssm_plot_circle(),
ssm_plot_contrast(),
ssm_plot_curve(),
ssm_plot_trajectory()
data("jz2017") set.seed(12345) res <- ssm_analyze( jz2017[1:200, ], scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), boots = 100 ) set.seed(23456) acc <- ssm_ci_accuracy(res, reps = 25) plot(acc)data("jz2017") set.seed(12345) res <- ssm_analyze( jz2017[1:200, ], scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), boots = 100 ) set.seed(23456) acc <- ssm_ci_accuracy(res, reps = 25) plot(acc)
Draw the estimated item configuration of a cpm_fit() object on the circular
canvas from ggcircumplex(). Each scale is placed at its estimated angle
(), at a radius given by its communality
(, the share of
its variance explained by the common circumplex factors), so items that the
model explains well sit near the outer ring and items it explains poorly sit
near the centre. The canvas spokes mark the theoretical angles supplied to
cpm_fit(), so the gap between a point and its spoke shows how far the
estimated angle departed from the hypothesised one. Where the confidence
intervals are estimable, a wedge spans each item's angle CI (angularly) and
communality CI (radially).
## S3 method for class 'circumplex_cpm' plot(x, amax = 1, angle_labels = NULL, legend = TRUE, ...)## S3 method for class 'circumplex_cpm' plot(x, amax = 1, angle_labels = NULL, legend = TRUE, ...)
x |
A |
amax |
A single positive number giving the communality represented by the canvas's outer ring (default = 1, the maximum possible communality). |
angle_labels |
Either |
legend |
A logical: draw a legend keying the colours to the scale names
(default = |
... |
Not used. Supplying an unrecognized argument produces a warning. |
A ggplot2 object.
data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") set.seed(12345) fit <- cpm_fit(jz2017, scales = scales, boots = 100) plot(fit)data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") set.seed(12345) fit <- cpm_fit(jz2017, scales = scales, boots = 100) plot(fit)
Draw the two-factor loading configuration of a fit_structure() object on
the circular canvas from ggcircumplex(). Each scale is placed at its
estimated angle (atan2 of its two principal-axis loadings) and at a radius
given by its communality (the share of its variance on the first two
factors), so a clean circumplex shows the scales spread evenly around a ring
of similar radius, unequal axes show scales at differing radii (what the
Fisher Test measures), and simple structure shows scales bunched near a few
angles (what the Gap and interstitiality tests measure). The canvas spokes
mark the same estimated angles, labelled by scale.
## S3 method for class 'circumplex_structure' plot(x, amax = 1, legend = TRUE, ...)## S3 method for class 'circumplex_structure' plot(x, amax = 1, legend = TRUE, ...)
x |
A |
amax |
A single positive number giving the communality represented by
the canvas's outer ring (default = 1). Principal-axis communalities can
exceed 1 in a Heywood case; when any scale's communality exceeds |
legend |
A logical: draw a legend keying the colours to the scale names
(default = |
... |
Not used. Supplying an unrecognized argument produces a warning. |
A ggplot2 object.
fit_structure(), ggcircumplex()
data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") plot(fit_structure(jz2017, scales = scales))data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") plot(fit_structure(jz2017, scales = scales))
Return a vector of angular displacements, in degrees, for four equally spaced
circumplex scales corresponding to the circumplex poles. Can be passed to the
angles parameter of other functions in this package.
poles()poles()
A numeric vector with four elements, each corresponding to the angular displacement (in degrees) of a subscale, in the following order: PA, DE, HI, LM.
poles()poles()
Compact display of an axes_reliability() object: the per-axis reliability,
SEm, and Nunnally-Bernstein comparison, with the correlation-as-covariance
standard-error caveat.
## S3 method for class 'circumplex_axes_reliability' print(x, digits = 3, ...)## S3 method for class 'circumplex_axes_reliability' print(x, digits = 3, ...)
x |
A |
digits |
The number of decimal places to display (default = 3). |
... |
Not used. |
x, invisibly.
Compact display of a cpm_fit() object: the estimated angles and communality
indices with confidence intervals, a one-line fit summary, and any
boundary/convergence notes.
## S3 method for class 'circumplex_cpm' print(x, digits = 3, ...)## S3 method for class 'circumplex_cpm' print(x, digits = 3, ...)
x |
A |
digits |
The number of decimal places to display (default = 3). |
... |
Not used. |
x, invisibly.
Compact display of a fit_structure() object: the four factor-analytic
criteria with their statistics and interpretive classifications, and the
RANDALL order test with its randomization p-value.
## S3 method for class 'circumplex_structure' print(x, digits = 3, ...)## S3 method for class 'circumplex_structure' print(x, digits = 3, ...)
x |
A |
digits |
The number of decimal places to display (default = 3). |
... |
Not used. |
x, invisibly.
Return a vector of angular displacements, in degrees, for four equally spaced
circumplex scales corresponding to the circumplex quadrants. Can be passed to
the angles parameter of other functions in this package.
quadrants()quadrants()
A numeric vector with eight elements, each corresponding to the angular displacement (in degrees) of a subscale, in the following order: BC, FG, JK, NO.
quadrants()quadrants()
A small example dataset containing raw item responses on the Inventory of Interpersonal Problems, Short Circumplex (IIP-SC). This data set is useful for testing functions that operate on item-level data.
raw_iipscraw_iipsc
A data frame with 10 observations and 32 variables.
A ggplot2 continuous position scale for the angle axis of a linear
circumplex plot, such as the score-by-angle curve drawn by
ssm_plot_curve(). It places axis breaks at the circumplex scale angles and
labels them, by default, with their angular position in degrees. Custom text
labels or a circumplex_instrument can be supplied instead, using the same
conventions as ggcircumplex(), so the linear axis and the circular canvas
label their scales consistently.
scale_x_circumplex(angles = octants(), labels = NULL, instrument = NULL, ...)scale_x_circumplex(angles = octants(), labels = NULL, instrument = NULL, ...)
angles |
Optional. A numeric vector of the angular position (in
degrees) of each circumplex scale (default = |
labels |
Optional. Either |
instrument |
Optional. Either |
... |
Additional arguments passed to
|
A ggplot2 scale object that can be added to a plot with +.
Other circumplex layers:
coord_circumplex(),
geom_ssm_arc(),
geom_ssm_path(),
geom_ssm_point(),
ggcircumplex(),
theme_circumplex()
# Degree-labeled angle axis scale_x_circumplex(octants()) # Label the axis with an instrument's scale abbreviations scale_x_circumplex(instrument = csip)# Degree-labeled angle axis scale_x_circumplex(octants()) # Label the axis with an instrument's scale abbreviations scale_x_circumplex(instrument = csip)
Display the scales of a circumplex instrument including the total number of scales and each scale's abbreviation, hypothetical angle, and text label.
scales(x, items = FALSE)scales(x, items = FALSE)
x |
Required. An object of the instrument class. |
items |
Optional. A logical determining whether the items for each scale should be displayed below its other information (default = FALSE). |
The same input object. Prints text to console.
Other instrument functions:
anchors(),
instruments(),
items(),
norms()
scales(csip) scales(csip, items = TRUE)scales(csip) scales(csip, items = TRUE)
Calculate mean scores on circumplex scales from item responses by using a set of scoring instructions, which may be loaded from the package or created as a custom data frame.
score( data, items, instrument, na.rm = TRUE, prefix = "", suffix = "", append = TRUE )score( data, items, instrument, na.rm = TRUE, prefix = "", suffix = "", append = TRUE )
data |
Required. A data frame or matrix containing at least circumplex scales. |
items |
Required. The variable names or column numbers for the variables
in |
instrument |
Required. An instrument object from the package. To see the
available circumplex instruments, use |
na.rm |
Optional. A logical that determines if missing values should be omitted from the calculation of scores (default = TRUE). When set to TRUE, scales with missing data are essentially calculated with mean imputation. |
prefix |
Optional. A string to include at the beginning of the newly
calculated scale variables' names, before |
suffix |
Optional. A string to include at the end of the newly
calculated scale variables' names, after |
append |
Optional. A logical that determines whether the calculated
score variables will be appended to |
A data frame that matches .data except that new variables are
appended that contain mean scores on each variable included in key.
Other tidying functions:
ipsatize(),
norm_standardize(),
self_standardize()
data("raw_iipsc") score(raw_iipsc, items = 1:32, instrument = iipsc, prefix = "IIPSC_")data("raw_iipsc") score(raw_iipsc, items = 1:32, instrument = iipsc, prefix = "IIPSC_")
Take in a data frame containing circumplex scales (or items) and return that same data frame with each specified variable transformed into standard scores (i.e., z-scores) based on observed means and SDs.
self_standardize( data, scales, na.rm = TRUE, prefix = "", suffix = "_z", append = TRUE )self_standardize( data, scales, na.rm = TRUE, prefix = "", suffix = "_z", append = TRUE )
data |
Required. A data frame or matrix containing at least circumplex scales. |
scales |
Required. A character vector containing the column names, or a numeric vector containing the column indexes, for the variables (scale scores) to be standardized. |
na.rm |
Optional. A logical that determines whether to remove missing values from scales when calculating the means and SDs used for standardization (default = TRUE). |
prefix |
Optional. A string to include at the beginning of the newly
calculated scale variables' names, before the scale name and |
suffix |
Optional. A string to include at the end of the newly
calculated scale variables' names, after the scale name and |
append |
Optional. A logical that determines whether the calculated
standardized scores should be added as columns to |
A data frame that contains the self-standardized versions of
scales.
Other tidying functions:
ipsatize(),
norm_standardize(),
score()
self_standardize(aw2009, scales = 1:8)self_standardize(aw2009, scales = 1:8)
A simulated item-level dataset for demonstrating axes_reliability(). It
contains 1-7 Likert responses from 500 respondents on 32 items – four items
on each of the eight octant circumplex scales (PA at 90 degrees through
NO at 45 degrees, following octants()). The items were drawn from the
five-component population of Strack, Jacobs, and Grosse Holtforth (2013): a
general factor, two equal circumplex axes (axes variance .18), one shared
scale-specificity component (.10), and free item error, giving an axes
reliability of about .78. The data are synthetic – there is no public
raw-data source for the method – and are generated by a seeded script
(data-raw/simulated_items.R).
simulated_itemssimulated_items
A data frame with 500 observations and 32 variables named
PA_1–PA_4, BC_1–BC_4, ..., NO_1–NO_4 (four items per octant
scale).
Strack, S., Jacobs, K. A., & Grosse Holtforth, M. (2013). The reliability of circumplex axes. SAGE Open, 3(2). doi:10.1177/2158244013486115
Calculate SSM parameters with confidence intervals (bootstrapped by
default, or Monte Carlo via method) for a variety of different analysis
types. Depending on what arguments are supplied, either mean-based or
correlation-based analyses will be performed, one or more groups will be
used to stratify the data, and contrasts between groups or measures will be
calculated.
ssm_analyze( data, scales = NULL, angles = octants(), measures = NULL, grouping = NULL, contrast = FALSE, boots = 2000, interval = 0.95, listwise = TRUE, measures_labels = NULL, parallel = "no", ncpus = 1, method = "bootstrap", occasions = NULL )ssm_analyze( data, scales = NULL, angles = octants(), measures = NULL, grouping = NULL, contrast = FALSE, boots = 2000, interval = 0.95, listwise = TRUE, measures_labels = NULL, parallel = "no", ncpus = 1, method = "bootstrap", occasions = NULL )
data |
Required. A data frame or matrix containing at least circumplex scales. |
scales |
Required unless |
angles |
Optional. A numeric vector containing the angular displacement
of each circumplex scale included in |
measures |
Optional. Either |
grouping |
Optional. Either |
contrast |
Optional. A logical indicating whether to output the
difference between two measures', two groups', or two occasions' SSM
parameters. Can only be set to TRUE when exactly one of these holds: two
measures and one group; one measure and two groups; no measures and two
groups; or two occasions and one group (default = FALSE). The contrast is
always the second level minus the first. For two groups, this is the
second level of |
boots |
Optional. A single positive whole number indicating how many
bootstrap resamples (or, when |
interval |
Optional. A single positive number between 0 and 1 (exclusive) that indicates what confidence level to use when estimating the confidence intervals (default = 0.95). |
listwise |
Optional. A logical indicating whether missing values should
be handled by listwise deletion (TRUE) or pairwise deletion (FALSE). Note
that pairwise deletion may result in different missing data patterns in
each bootstrap resample and is slower to compute (default = TRUE).
Occasions analyses require |
measures_labels |
Optional. Either |
parallel |
Optional. A string indicating whether to distribute the
bootstrap computation across multiple CPU cores: "no" (default),
"multicore" (process forking; available on macOS and Linux, ignored on
Windows), or "snow" (a local PSOCK cluster; available on all platforms).
Passed to |
ncpus |
Optional. A single positive whole number indicating how many
CPU cores to use when |
method |
Optional. A string indicating how to estimate the confidence
intervals: "bootstrap" (default) resamples the data, whereas "montecarlo"
draws parameter replicates from the asymptotic sampling distribution of
the group mean vector (mean-based analyses) or the measure-scale
correlation vector (correlation-based analyses) – a multivariate normal
with empirically estimated covariance – and propagates them through the
SSM parameter transformation. The Monte Carlo method is much faster for
large samples but relies on the asymptotic normality of the means or
correlations, so prefer the bootstrap for small samples; it also requires
listwise-complete data. Correlations are drawn jointly across measures
within each group on the Fisher z scale and back-transformed. The
|
occasions |
Optional. Either |
A list containing the results and description of the analysis.
results |
A data frame with the SSM parameter estimates |
details |
A list with the number of bootstrap resamples or Monte Carlo draws (boots), the confidence interval percentage level (interval), the angular displacement of scales (angles), and the interval estimation method (method) |
call |
A language object containing the function call that created this object |
scores |
A data frame containing the mean scale scores |
type |
A string indicating what type of SSM analysis was done |
The profile displacement parameter is reported in the half-open interval
[0, 360) degrees. A profile that peaks exactly at the 0/360 degree
boundary is reported as approximately 360 (equivalently 0, the same
direction); which of the two appears is a floating-point detail and both
denote the same pole. A displacement confidence-interval endpoint that
lands exactly on that pole is always reported as 360 (never 0), matching
the package's LM = 360 labeling. Contrast displacements are instead
reported as a signed difference in (-180, 180] degrees (see the
"Contrast" block in the printed output).
Degenerate profiles (flat or zero-amplitude) have undefined displacement
(and fit, if flat), which is reported as NA with a warning. Bootstrap
resamples that produce degenerate profiles (e.g., a resampled measure
with zero variance) are excluded from the confidence intervals with a
warning reporting how many were dropped; the intervals are then
conditional on estimability.
[0, 360)degrees. A profile that peaks exactly at the 0/360 degree boundary is reported as approximately 360 (equivalently 0, the same direction); which of the two appears is a floating-point detail and both denote the same pole. A displacement *confidence-interval endpoint* that lands exactly on that pole is always reported as 360 (never 0), matching the package's LM = 360 labeling. Contrast displacements are instead reported as a signed difference in(-180, 180]: R:0,%20360)%60%20degrees.%20A%20profile%20that%20peaks%20exactly%20at%20the%200/360%20degree%0A%20%20boundary%20is%20reported%20as%20approximately%20360%20(equivalently%200,%20the%20same%0A%20%20direction);%20which%20of%20the%20two%20appears%20is%20a%20floating-point%20detail%20and%20both%0A%20%20denote%20the%20same%20pole.%20A%20displacement%20confidence-interval%20endpoint%20that%0A%20%20lands%20exactly%20on%20that%20pole%20is%20always%20reported%20as%20360%20(never%200),%20matching%0A%20%20the%20package's%20LM%20=%20360%20labeling.%20Contrast%20displacements%20are%20instead%0A%20%20reported%20as%20a%20signed%20difference%20in%20%60(-180,%20180
This function consumes R's random number stream (so do
cpm_fit(ci_method = "bootstrap"), cpm_simulate(), and
ssm_ci_accuracy(); ssm_score()/ssm_parameters() and the tidying
functions are deterministic). Call set.seed() immediately before
ssm_analyze() for reproducible confidence intervals:
Bootstrap (method = "bootstrap", the default): the
same seed gives byte-identical results, regardless of the
parallel/ncpus settings (see their descriptions below), because
boot::boot() draws all resample indices from the seed before any
work is parallelized.
Monte Carlo (method = "montecarlo"): the same seed
gives byte-identical results. Adding a group or measure, or
reordering scales/measures, changes the random draw sequence, so
results are reproducible for a fixed call but will not match after
such structural edits even with the same seed.
The two methods are not expected to agree numerically
for the same seed – they consume the random stream in unrelated
ways. Their statistical agreement (validated on real data; see
vignette("introduction-to-ssm-analysis")) is a separate property
from RNG reproducibility.
Increasing boots changes the CI by design (more resamples/draws
should tighten Monte Carlo error), so results are not expected to be
stable across different boots values, only within a fixed call.
Supplying occasions analyzes the same circumplex scales measured at
k >= 2 occasions on the same persons (wide data, one row per person).
Each occasion yields its own profile row; with contrast = TRUE
(exactly 2 occasions, single group) the paired within-person contrast
is estimated with both engines preserving the within-person dependence
(the bootstrap resamples persons; the Monte Carlo engine draws the
stacked occasion mean vectors jointly).
Interpretation notes. A paired displacement-contrast CI is interpretable only when both occasions' amplitudes are reliably nonzero (both profiles print without the amplitude note); if only one occasion's profile is interpretable, do not read the contrast as directional change. Paired designs are not unconditionally more efficient than independent groups: the paired elevation contrast has a narrower CI exactly when the within-person elevation correlation is positive, while for the amplitude and displacement contrasts the paired CI is narrower only when the gradient-projected cross-occasion covariance is positive – under isotropic dependence this is proportional to cos(displacement change), so paired CIs are narrower for displacement changes under 90 degrees and can be wider than independent-groups CIs for changes beyond 90 degrees, even with strongly positive within-person correlation.
With method = "montecarlo" the per-group draw has dimension k x p
(occasions times scales); group sizes should comfortably exceed k x p
for the asymptotic covariance to be well estimated (the percentile
bootstrap is the safer small-sample choice). Grouping is time-invariant
by construction (one group per person-row).
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
# Load example data data("jz2017") # Single-group mean-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") ) # Single-group correlation-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = c("NARPD", "ASPD") ) # Monte Carlo confidence intervals (faster for large samples) ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), method = "montecarlo" ) # Multiple-group mean-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), grouping = "Gender" ) # Multiple-group mean-based SSM with contrast ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), grouping = "Gender", contrast = TRUE ) # Single-group correlation-based SSM with contrast ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = c("NARPD", "ASPD"), contrast = TRUE ) # Multiple-group correlation-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = "NARPD", grouping = "Gender" ) # Multiple-group correlation-based SSM with contrast ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = "NARPD", grouping = "Gender", contrast = TRUE )# Load example data data("jz2017") # Single-group mean-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") ) # Single-group correlation-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = c("NARPD", "ASPD") ) # Monte Carlo confidence intervals (faster for large samples) ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), method = "montecarlo" ) # Multiple-group mean-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), grouping = "Gender" ) # Multiple-group mean-based SSM with contrast ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), grouping = "Gender", contrast = TRUE ) # Single-group correlation-based SSM with contrast ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = c("NARPD", "ASPD"), contrast = TRUE ) # Multiple-group correlation-based SSM ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = "NARPD", grouping = "Gender" ) # Multiple-group correlation-based SSM with contrast ssm_analyze( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = "NARPD", grouping = "Gender", contrast = TRUE )
A convenience wrapper around the occasions interface of ssm_analyze()
for data stored in long format (one row per person per occasion). It
reshapes the data into the wide, one-row-per-person layout that
ssm_analyze() consumes and then delegates to it; all estimation is
performed by ssm_analyze() unchanged. See the occasions argument of
ssm_analyze() for the analysis semantics – per-occasion profiles, paired
within-person contrasts, and the listwise-only handling of missing waves
(a person missing any occasion is dropped from all occasions).
ssm_analyze_long( data, scales, angles = octants(), id, occasion, grouping = NULL, contrast = FALSE, boots = 2000, interval = 0.95, parallel = "no", ncpus = 1, method = "bootstrap" )ssm_analyze_long( data, scales, angles = octants(), id, occasion, grouping = NULL, contrast = FALSE, boots = 2000, interval = 0.95, parallel = "no", ncpus = 1, method = "bootstrap" )
data |
Required. A data frame (or matrix) in long format containing an identifier column, an occasion column, and the circumplex scale scores (one set of score columns, repeated across occasions in different rows). |
scales |
Required. A character vector of column names, or a numeric
vector of column indexes, giving the circumplex scale scores in |
angles |
Optional. A numeric vector containing the angular displacement
of each circumplex scale included in |
id |
Required. A single column name or index identifying the person that each row belongs to. |
occasion |
Required. A single column name or index identifying the
occasion (wave) that each row belongs to. Occasion order – which governs
the second-minus-first direction of a paired contrast – is taken from the
factor levels of this column when it is a factor, and otherwise from the
order in which the occasions first appear in |
grouping |
Optional. A single column name or index giving a time-invariant grouping variable (one value per person; an error is raised if a person's grouping value varies across occasions). |
contrast |
Optional. A logical value; if |
boots, interval, parallel, ncpus, method
|
Optional. Passed through to
|
A list containing the results and description of the analysis, as
returned by ssm_analyze() (with an Occasion column). See
ssm_analyze().
ssm_analyze() for the wide-format interface and the analysis
semantics this wrapper delegates to.
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
# Build a small two-occasion dataset in long format (one row per person per # occasion). In practice `data` already stores the repeated occasions this # way; here we stack two copies of jz2017 as an illustration. data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") t1 <- jz2017[, scales] t1$id <- seq_len(nrow(t1)) t1$occasion <- "T1" t2 <- t1 t2$occasion <- "T2" long <- rbind(t1, t2) # Per-occasion SSM profiles from long-format data ssm_analyze_long(long, scales = scales, id = "id", occasion = "occasion")# Build a small two-occasion dataset in long format (one row per person per # occasion). In practice `data` already stores the repeated occasions this # way; here we stack two copies of jz2017 as an illustration. data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") t1 <- jz2017[, scales] t1$id <- seq_len(nrow(t1)) t1$occasion <- "T1" t2 <- t1 t2$occasion <- "T2" long <- rbind(t1, t2) # Per-occasion SSM profiles from long-format data ssm_analyze_long(long, scales = scales, id = "id", occasion = "occasion")
Estimate, by simulation, whether the confidence intervals of a fitted
ssm_analyze() object would cover the true SSM parameters at their nominal
rate if the population looked like the fitted estimates, at the observed
sample size(s). Following Zimmermann & Wright (2017), the population's scale
intercorrelation structure is characterized by fitting Browne's (1992)
circular process model (cpm_fit()) to the pooled within-group scale
correlations; each of reps datasets is then simulated from that plug-in
population at the object's exact group sizes and the object's own interval
procedure (same engine, same boots, same interval) is rerun on it.
Coverage is reported per profile row, parameter, and amplitude condition,
with 95% Wilson score intervals classified against Bradley's (1978) liberal
robustness band at the as-estimated condition.
ssm_ci_accuracy( ssm_object, reps = 1000, amplitude_factors = c(1, 0.5, 0.25, 0), structure = c("cpm", "observed"), m = NULL, cpm = NULL, data = NULL, parallel = "no", ncpus = 1 )ssm_ci_accuracy( ssm_object, reps = 1000, amplitude_factors = c(1, 0.5, 0.25, 0), structure = c("cpm", "observed"), m = NULL, cpm = NULL, data = NULL, parallel = "no", ncpus = 1 )
ssm_object |
Required. A |
reps |
Optional. The number of simulated datasets per amplitude condition (default = 1000, binomial SE about 0.7 percentage points; 500 is a reasonable quick-look floor). |
amplitude_factors |
Optional. Numeric vector of amplitude scaling
factors in |
structure |
Optional. |
m |
Optional. The number of harmonics passed to |
cpm |
Optional. A pre-fitted |
data |
Optional. The original data set, required only for ssm objects created before sufficient statistics were stored at analysis time; the statistics are then recomputed and checked against the stored profile vectors. |
parallel |
Optional. |
ncpus |
Optional. Number of cores when |
Displacement coverage is angular: the truth is inside the reported interval
as an arc (membership modulo 360 degrees), so populations peaking at the
0/360 boundary and contrast intervals reported beyond +/-180 degrees are
handled without special-casing. Because displacement is only interpreted
when the printed amplitude guardrail certifies it, displacement coverage is
also reported conditional on certification under the shipped decision rule
a_lci / (a_uci - a_lci) >= 0.35 (the rule the printed ssm_analyze()
output applies): the amplitude CI's lower bound must sit at least 0.35 CI
widths above zero. The rule is scale-free (invariant to the score metric)
and print-independent, so no scale-dependent threshold is reported; the
0.35 constant is calibrated for the default 95% confidence interval. A
contrast row is a
signed difference, not a prototypicality measure, so
print.circumplex_ssm() never certification-gates it; its displacement
verdict and printed coverage are therefore reported unconditionally
(matching that profiles-only stance). Its certification-conditional
coverage – where "certified" means both profile rows were certified – is
still computed and retained in the returned object as a descriptive that no
display consumes.
The amplitude_factors ladder manufactures populations whose closed-form
amplitude is scaled toward zero (the regime where percentile amplitude
intervals are theoretically weakest) while keeping the residual profile
content fixed. The ladder is defined through the estimator functional (a
3x3 solve on the images of 1, cos, and sin), so the condition-c truths are
exact for any angle spacing: elevation is unchanged and the amplitude is
exactly c times the estimate. Truths are nevertheless recomputed from
each condition's population profile. At c = 0 amplitude coverage is
structurally zero (a percentile interval of strictly positive amplitude
replicates cannot contain 0; such rows are flagged in the Structural
column) and displacement truth is undefined (reported NA); the guardrail
certification rate carries the inferential weight there, and the
informative rungs for amplitude coverage are the small c > 0 ones.
When a profile row's amplitude estimate is itself below half its observed
CI width, the relative ladder degenerates: the analysis already sits in
the near-zero regime. One absolute rung is then added at the certification
margin (c chosen so c times the amplitude estimate equals the observed
amplitude-CI half-width, the largest such c across affected rows) and
summary() notes the regime. On the correlation path this rung is dropped
with a warning if it would push a population correlation to +/-1.
A circumplex_ci_accuracy object: a list with coverage (per
Profile x Parameter x Condition: coverage, its Monte Carlo SE, the
one-sided miss rates, median CI width, and for displacement the
certification-conditional coverage with the number of certified
replicates behind it – for a contrast row this conditional column is
retained as a joint-certification descriptive that no display consumes;
Structural flags the amplitude rows whose zero
coverage is a theorem rather than a measurement), guardrail (per
Profile x Condition: certification rate with its 95% Wilson score
interval, the user-expectation benchmark (1 - interval) / 2, the
stored false-certification caution decision at the c = 0 rung
(Caution, true when the Wilson lower bound exceeds the benchmark;
NA off that rung, and NA for a contrast row, which
print.circumplex_ssm() never gates), fit-pass
rate, and the
branch-pathology rate – the rate at which a displacement point estimate
falls geometrically outside its own interval), verdict
(Wilson-vs-Bradley classification of elevation, amplitude, and
displacement coverage at the as-estimated condition – a profile's
displacement is classified certification-conditionally (Parameter
"d_conditional"), a contrast's unconditionally (Parameter "d") –
plus an
overall worst-of row per profile; note the printed verdict headline
additionally elevates to CAUTION whenever the guardrail Caution fired,
so it can read worse than the overall coverage class),
cpm (the embedded cpm_fit() object, or NULL when
structure = "observed"), population (per profile row: the population
profile vectors, truth parameters, and any positive-semidefiniteness
repair magnitude, by condition), and details. The plot() method
draws coverage against the amplitude ladder with the Bradley band
shaded; summary() adds a plain-language verdict (see
summary.circumplex_ci_accuracy()).
This function is stochastic: call set.seed() immediately before it.
It draws one sample.int() value from the caller's random number stream
to seed an internal L'Ecuyer-CMRG stream, gives every simulated dataset
its own deterministic substream, and then restores the caller's
.Random.seed and generator kind on exit, so results for a given seed
are identical regardless of parallel/ncpus and the caller's stream
is advanced by exactly that one draw.
Coverage is evaluated at the fitted structure, not the unknown truth ("would the procedure work in a population like your estimates", not "did your interval cover"). Simulated populations are multivariate normal with the fitted correlation structure; heavy tails or skew in the real data can degrade coverage further than reported. The diagnostic assesses the complete-data procedure (missing data are not simulated), and groups are assumed to share one circumplex structure. When the Browne model fits poorly, the simulated population may misrepresent the data; the embedded fit and its diagnostics are returned for inspection.
For an occasions (repeated-measures) analysis the population is instead a
multivariate normal with the observed stacked cross-occasion covariance
(no circular-model idealization): the within-person dependence across
occasions is carried directly, and no structure/cpm alternative is
offered. When the stacked covariance is rank-deficient (per-group sample
size at or below the number of occasions times scales) the simulated
population is a proper degenerate normal, so the reported coverage and
width remain valid but the fit-statistic pass rate is descriptive only.
For a paired contrast, the joint-certification rate (both occasions
certified) is reported as a descriptive caveat on the contrast's
interpretability. Assessing the occasions object per occasion via
scales = one occasion's columns instead uses the default "cpm"
structure and can give slightly different per-occasion verdicts – a
structure-sensitivity fact, not a bug.
Zimmermann, J., & Wright, A. G. C. (2017). Beyond description in interpersonal construct validation: Methodological advances in the circumplex Structural Summary Approach. Assessment, 24(1), 3-23.
Browne, M. W. (1992). Circumplex models for correlation matrices. Psychometrika, 57(4), 469-497.
Bradley, J. V. (1978). Robustness? British Journal of Mathematical and Statistical Psychology, 31(2), 144-152.
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
data("jz2017") set.seed(12345) res <- ssm_analyze( jz2017[1:200, ], scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), boots = 100 ) # Small reps/boots keep the example fast; use the defaults in practice set.seed(23456) acc <- ssm_ci_accuracy(res, reps = 25, amplitude_factors = c(1, 0.25)) acc summary(acc)data("jz2017") set.seed(12345) res <- ssm_analyze( jz2017[1:200, ], scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), boots = 100 ) # Small reps/boots keep the example fast; use the defaults in practice set.seed(23456) acc <- ssm_ci_accuracy(res, reps = 25, amplitude_factors = c(1, 0.25)) acc summary(acc)
Transform posterior draws from a user-fitted Bayesian model (e.g., a brms cosine regression) into Structural Summary Method parameter draws and summarize them with the package's circular-statistics machinery. Two draw shapes are accepted, distinguished explicitly (never guessed):
ssm_draws(draws, angles = NULL, interval = 0.95, type = NULL)ssm_draws(draws, angles = NULL, interval = 0.95, type = NULL)
draws |
Required. A numeric matrix or data frame of posterior draws: one row per draw, columns per the shape rules above. |
angles |
Optional. A numeric vector of angular displacements (in
degrees) for profile draws, one per column of |
interval |
Optional. A single number between 0 and 1 giving the credible level for the equal-tailed intervals (default = 0.95). |
type |
Optional. |
Parameter draws (angles = NULL, type = "parameters"): a numeric
matrix or data frame with exactly three columns interpreted in column
order as (e, x, y) – elevation (intercept), the cosine coefficient
(x), and the sine coefficient (y). Each row is mapped to amplitude
a = sqrt(x^2 + y^2) and displacement d = atan2(y, x) wrapped to
[0, 360] (the 0/360 pole is reported as 360, the package's LM = 360
convention). Column names are not used to reorder: when names are present
but do not look (intercept, cos, sin)-like, a message states the
assumed mapping. A row with exactly zero amplitude has undefined
displacement (NA); model fit is undefined for parameter draws
(fit = NA) because no profile is available to measure it against.
Profile draws (angles supplied): a numeric matrix with one column
per circumplex scale (ncol(draws) == length(angles)); each row goes
through the closed-form SSM transform exactly as a bootstrap replicate
would, inheriting the standing degenerate-profile NA semantics.
With angles = NULL and a column count other than 3 the input matches
neither shape and an error explains both. With angles = NULL and
exactly 3 columns the shape is ambiguous (a p = 3 instrument's profile
draws look like parameter draws), so type = "parameters" is required.
Point estimates are posterior medians for e, x, y, a, and fit (amplitude
is right-skewed, so a mean would be biased upward), and the circular mean
for displacement. Marginal summaries are not jointly coherent: the
reported a is not sqrt(x^2 + y^2) of the reported (x, y), and the
reported d is not their direction – each is the honest marginal summary
of its own posterior. Intervals are equal-tailed credible intervals
(percentile quantiles of the draws), with displacement handled by the
package's circular quantile machinery (centered on the circular mean, so
intervals straddling 0/360 wrap correctly). Draws with undefined
displacement are excluded from the displacement summaries only, which are
therefore conditional on estimability (measure-zero for continuous
parameter-draw posteriors; can bind for profile draws). A diffuse
posterior with zero circular resultant has an undefined circular mean,
reported as NA rather than invented.
Note that independent priors on (x, y) induce a non-uniform prior on (a, d) – roughly Rayleigh-shaped on amplitude, with mass pushed away from a = 0 – so the prior on the SSM scale should be inspected (e.g., by prior-predictive simulation) rather than assumed flat; see the package's Bayesian SSM vignette.
An object of class "circumplex_ssm_draws" holding draws (the
SSM parameter draws, one row per posterior draw, columns e, x, y, a, d,
fit, displacement in degrees [0, 360], pole reported as
360), results (the point summaries
and credible bounds), and details, whose certified field records the
package's displacement-interpretability certification applied to the
amplitude credible interval (a_lci / (a_uci - a_lci) >= 0.35): when it
fails, the displacement interval is not interpretable and printing adds
a note saying so. Printing shows the summary table;
summary() adds the analysis details.
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
# Parameter draws (e.g., brms fixed-effect draws b_Intercept, b_cos, b_sin) set.seed(1) draws <- cbind(rnorm(500, 0.4, 0.1), rnorm(500, 0.9, 0.1), rnorm(500, -0.3, 0.1)) ssm_draws(draws, type = "parameters")# Parameter draws (e.g., brms fixed-effect draws b_Intercept, b_cos, b_sin) set.seed(1) draws <- cbind(rnorm(500, 0.4, 0.1), rnorm(500, 0.9, 0.1), rnorm(500, -0.3, 0.1)) ssm_draws(draws, type = "parameters")
Calculate SSM parameters (without confidence intervals) for a set of scores
and generate a data frame with customizable labels for each parameter value.
This function requires the input to be a numeric vector (or coercable to one)
and returns only the parameters. See ssm_score() for a similar
function that calculates SSM parameters for each row of a data frame.
ssm_parameters( scores, angles = octants(), prefix = "", suffix = "", e_label = "Elev", x_label = "Xval", y_label = "Yval", a_label = "Ampl", d_label = "Disp", f_label = "Fit" )ssm_parameters( scores, angles = octants(), prefix = "", suffix = "", e_label = "Elev", x_label = "Xval", y_label = "Yval", a_label = "Ampl", d_label = "Disp", f_label = "Fit" )
scores |
Required. A numeric vector (or single row data frame) containing one score for each of a set of circumplex scales. |
angles |
Required. A numeric vector containing the angular displacement
of each circumplex scale included in |
prefix |
Optional. A string to append to the beginning of all of the SSM parameters' variable names (default = ""). |
suffix |
Optional. A string to append to the end of all of the SSM parameters' variable names (default = ""). |
e_label |
Optional. A string representing the variable name of the SSM elevation parameter (default = "Elev"). |
x_label |
Optional. A string representing the variable name of the SSM x-value parameter (default = "Xval"). |
y_label |
Optional. A string representing the variable name of the SSM y-value parameter (default = "Yval"). |
a_label |
Optional. A string representing the variable name of the SSM amplitude parameter (default = "Ampl"). |
d_label |
Optional. A string representing the variable name of the SSM displacement parameter (default = "Disp"). |
f_label |
Optional. A string representing the variable name of the SSM
fit or R-squared value (default = "Fit"). This value is a bounded
R-squared in |
A data frame containing the SSM parameters calculated from scores.
For degenerate profiles the undefined parameters are returned as NA
with a warning: a flat profile (zero variance) has undefined displacement
and fit, and a profile with real variance but zero amplitude (i.e., no
first-harmonic component) has undefined displacement and a fit of 0.
Note that this applies only to amplitudes that are zero up to machine
precision; small real amplitudes are always estimated, and their
uncertainty is expressed through confidence intervals (see
ssm_analyze()).
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
# Manually enter octant scores scores <- c(0.55, 0.58, 0.62, 0.76, 1.21, 1.21, 1.48, 0.90) ssm_parameters(scores) # Customize several of the labels ssm_parameters(scores, x_label = "LOV", y_label = "DOM") # Add a prefix to all labels ssm_parameters(scores, prefix = "IIP_")# Manually enter octant scores scores <- c(0.55, 0.58, 0.62, 0.76, 1.21, 1.21, 1.48, 0.90) ssm_parameters(scores) # Customize several of the labels ssm_parameters(scores, x_label = "LOV", y_label = "DOM") # Add a prefix to all labels ssm_parameters(scores, prefix = "IIP_")
Score each person's own circumplex profile through the closed-form SSM
transform and return a per-person parameter table. When id is NULL,
every row of data is treated as one person's profile (like
ssm_score(), but returning a fresh table rather than appending columns).
When id names a column, rows sharing an id (e.g., occasions of intensive
longitudinal data) are first averaged within person – each scale's mean
uses that person's available (non-missing) rows – and the within-person
mean profile is scored.
ssm_parameters_id(data, scales, angles = octants(), id = NULL)ssm_parameters_id(data, scales, angles = octants(), id = NULL)
data |
Required. A data frame or matrix containing at least
circumplex scales, with one row per person or (with |
scales |
Required. The variable names or column numbers for the
variables in |
angles |
Optional. A numeric vector containing the angular
displacement of each circumplex scale included in |
id |
Optional. A single variable name or column number identifying
persons. If |
Degenerate profiles keep their row and are reported as NA, never
silently dropped: a flat (zero-variance) profile has undefined
displacement and fit, a profile with real variance but zero
first-harmonic amplitude has undefined displacement and a fit of 0, and a
person with a completely missing scale has an undefined profile (all
parameters NA). The na_rate column exposes each person's share of
missing scale cells so missingness is visible alongside its consequences.
A data frame of class "circumplex_ssm_id" with one row per
person, in order of first appearance: the id column (named after id,
or id when NULL), n_obs (rows contributing to that person),
na_rate (proportion of missing scale cells among those rows), and the
SSM parameters Elev, Xval, Yval, Ampl, Disp (degrees in
[0, 360], with the 0/360 pole reported as 360 per the package's
LM = 360 convention), and Fit. Use summary.circumplex_ssm_id() for
group-level summaries with circular statistics for displacement.
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
data("aw2009") ssm_parameters_id( aw2009, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") )data("aw2009") ssm_parameters_id( aw2009, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") )
Take in the results of a Structural Summary Method analysis and plot the point and interval estimate for each row (e.g., group or measure) in a circular space quantified by displacement and amplitude.
ssm_plot_circle( ssm_object, amax = NULL, legend_font_size = 12, scale_font_size = 12, drop_lowfit = FALSE, repel = FALSE, angle_labels = NULL, palette = "Set2", vary_shapes = FALSE, path = FALSE, ... )ssm_plot_circle( ssm_object, amax = NULL, legend_font_size = 12, scale_font_size = 12, drop_lowfit = FALSE, repel = FALSE, angle_labels = NULL, palette = "Set2", vary_shapes = FALSE, path = FALSE, ... )
ssm_object |
Required. The output of |
amax |
A positive real number corresponding to the radius of the circle. It is used to scale the amplitude values and will determine which amplitude labels are drawn. |
legend_font_size |
A positive real number corresponding to the size (in pt) of the text labels in the legend (default = 12). |
scale_font_size |
A positive real number corresponding to the size (in pt) of the text labels for the amplitude and displacement scales (default = 12). |
drop_lowfit |
A logical determining whether profiles with low model fit (<.70) should be omitted or plotted with dashed borders (default = FALSE). |
repel |
A logical determining whether each profile is labelled with a
repelled text label (placed on the circumplex canvas by
|
angle_labels |
A character vector specifying text labels to plot around
the circle for each scale. Can also specify NULL to default to numerical
angle labels or a vector of empty strings ("") to hide the labels. If not
NULL, must have the same length and ordering as the |
palette |
A string corresponding to the palette to be used from ColorBrewer for the color and fill aesthetics. If set to NULL, all points will appear blue and no legend will be there (useful for showing the coverage of a high number of variables). |
vary_shapes |
A logical determining whether profiles should each get their own shape or vary only by fill color. This only works when the number of profiles is five or less. (default = FALSE) |
path |
A logical determining whether each series' movement across
occasions is drawn as an arrowed path on the circle (default = |
... |
Not used. Supplying an unrecognized argument produces a warning. |
A ggplot variable containing a completed circular plot.
Other visualization functions:
plot.circumplex_ci_accuracy(),
ssm_plot_contrast(),
ssm_plot_curve(),
ssm_plot_trajectory()
data("jz2017") res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD") ) ssm_plot_circle(res)data("jz2017") res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD") ) ssm_plot_circle(res)
Take in the results of a Structural Summary Method analysis with pairwise contrasts and plot the point and interval estimates for each parameter's contrast (e.g., between groups or measures).
ssm_plot_contrast( ssm_object, drop_xy = FALSE, sig_color = "#fc8d62", ns_color = "white", linesize = 1.25, fontsize = 12, ... )ssm_plot_contrast( ssm_object, drop_xy = FALSE, sig_color = "#fc8d62", ns_color = "white", linesize = 1.25, fontsize = 12, ... )
ssm_object |
Required. The results output of |
drop_xy |
A logical determining whether the X-Value and Y-Value parameters should be removed from the plot (default = FALSE). |
sig_color |
Optional. A string corresponding to the color to use to denote significant contrasts (default = "#fc8d62"). |
ns_color |
Optional. A string corresponding to the color to use to denote non-significant contrasts (default = "white"). |
linesize |
Optional. A positive number corresponding to the size of the point range elements in mm (default = 1.5). |
fontsize |
Optional. A positive number corresponding to the size of the axis labels, numbers, and facet headings in pt (default = 12). |
... |
Not used. Supplying an unrecognized argument produces a warning. |
A ggplot variable containing difference point-ranges faceted by SSM parameter. An interval that does not contain the value of zero has p<.05.
Other visualization functions:
plot.circumplex_ci_accuracy(),
ssm_plot_circle(),
ssm_plot_curve(),
ssm_plot_trajectory()
data("jz2017") res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD"), contrast = TRUE ) ssm_plot_contrast(res)data("jz2017") res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD"), contrast = TRUE ) ssm_plot_contrast(res)
Take in the results of a Structural Summary Method analysis and plot the scores by angle and the estimated SSM curve.
ssm_plot_curve( ssm_object, angle_labels = NULL, base_size = 11, drop_lowfit = FALSE, ... )ssm_plot_curve( ssm_object, angle_labels = NULL, base_size = 11, drop_lowfit = FALSE, ... )
ssm_object |
Required. The results output of |
angle_labels |
Optional. Either NULL or a character vector that
determines the x-axis labels. If NULL, the labels will be the angle
numbers. If a character vector, must be the same length and in the same
order as the |
base_size |
Optional. A positive number corresponding to the base font size in pts (default = 11). |
drop_lowfit |
Optional. A logical indicating whether to omit profiles with low fit (<.70) or include them with dashed lines (default = FALSE). |
... |
Not used. Supplying an unrecognized argument produces a warning. |
A ggplot object depicting the SSM curve(s) of each profile.
Other visualization functions:
plot.circumplex_ci_accuracy(),
ssm_plot_circle(),
ssm_plot_contrast(),
ssm_plot_trajectory()
data("jz2017") res <- ssm_analyze( jz2017, scales = 2:9, measures = 10:13 ) ssm_plot_curve(res) ssm_plot_curve(res, angle_labels = PANO())data("jz2017") res <- ssm_analyze( jz2017, scales = 2:9, measures = 10:13 ) ssm_plot_curve(res) ssm_plot_curve(res, angle_labels = PANO())
Plot each Structural Summary Method parameter against time, one facet per parameter, with its confidence interval as a band. This is a Cartesian diagnostic plot, not a circumplex figure: the horizontal axis is time, not angle.
ssm_plot_trajectory(x, ...) ## Default S3 method: ssm_plot_trajectory(x, ...) ## S3 method for class 'circumplex_ssm' ssm_plot_trajectory(x, drop_xy = FALSE, base_size = 11, na.rm = TRUE, ...) ## S3 method for class 'data.frame' ssm_plot_trajectory( x, time, drop_xy = FALSE, base_size = 11, na.rm = TRUE, ... )ssm_plot_trajectory(x, ...) ## Default S3 method: ssm_plot_trajectory(x, ...) ## S3 method for class 'circumplex_ssm' ssm_plot_trajectory(x, drop_xy = FALSE, base_size = 11, na.rm = TRUE, ...) ## S3 method for class 'data.frame' ssm_plot_trajectory( x, time, drop_xy = FALSE, base_size = 11, na.rm = TRUE, ... )
x |
An SSM results object produced by |
... |
Not used. Supplying an unrecognized argument produces a warning. |
drop_xy |
A logical determining whether the X-value and Y-value panels
should be omitted (default = |
base_size |
A positive number determining the base font size of the plot (default = 11). |
na.rm |
A logical determining whether time points that cannot be plotted
(no defined displacement) are dropped silently (default = |
time |
A string naming the numeric time column of a trajectory table. Required for the data frame method; unused for SSM objects. |
Two kinds of input are accepted, and they differ only in their time axis:
An SSM results object with occasions, from ssm_analyze() with the
occasions argument or from ssm_analyze_long(). Occasions are discrete
and ordered, so the axis is discrete.
A trajectory table: a data frame with one row per time point, a numeric
time column named by time, and the columns a_est, a_lci, a_uci,
d_est, d_lci, and d_uci (optionally the e_*, x_*, and y_*
triples, and a logical certified column). This is the shape a
model-based workflow assembles by evaluating a fitted growth model at each
time point and passing the draws through ssm_draws(); see
vignette("growth-ssm-analysis"). The axis is continuous, so unequally
spaced time points are drawn at their actual spacing.
Both paths share one implementation of the displacement unwrap and the certification marking described below.
The displacement panel is drawn on an unwrapped branch, so a profile whose displacement crosses the 0/360 boundary renders as one continuous path rather than jumping a full turn. Values on that panel may therefore fall outside [0, 360); each confidence bound is placed at its signed angular distance from its own estimate. Unwrapping assumes the profile rotates less than a half-turn between consecutive time points at which its displacement is defined – no data can verify this, so time points that are far apart, or a series with a gap, should be read with that in mind.
Occasions appear in the order they were supplied to ssm_analyze() (or in
the occasion factor's level order for ssm_analyze_long()), never in
alphabetical order.
On the displacement panel, a time point whose amplitude confidence interval
is too close to zero for its displacement to be interpretable is drawn as a
hollow point; see ssm_analyze() for the certification rule. For an SSM
object the verdict is computed from the amplitude interval; for a trajectory
table it is read from the optional certified column, and when that column
is absent no interpretability claim is made or shown. A profile with no
defined displacement at all (a flat profile) leaves a gap in that panel.
A contrast row is never plotted as a time point – it is a difference, not a
time point. Use ssm_plot_contrast() for it.
A ggplot object depicting each SSM parameter's trajectory over time, with confidence bands.
geom_ssm_path() and ssm_plot_circle(path = TRUE), which draw the
same change across occasions as movement on the circumplex canvas rather
than as parameter-by-time panels.
Other visualization functions:
plot.circumplex_ci_accuracy(),
ssm_plot_circle(),
ssm_plot_contrast(),
ssm_plot_curve()
data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") t1 <- jz2017[, scales] t1$id <- seq_len(nrow(t1)) t1$occasion <- "T1" t2 <- t1 t2$occasion <- "T2" res <- ssm_analyze_long(rbind(t1, t2), scales = scales, id = "id", occasion = "occasion" ) ssm_plot_trajectory(res) ssm_plot_trajectory(res, drop_xy = TRUE) # A model-based trajectory table, plotted on a continuous time axis trajectory <- data.frame( wave = 0:4, a_est = c(0.60, 0.55, 0.52, 0.58, 0.63), a_lci = c(0.48, 0.43, 0.40, 0.46, 0.51), a_uci = c(0.72, 0.67, 0.64, 0.70, 0.75), d_est = c(350, 355, 2, 8, 12), d_lci = c(340, 345, 352, 358, 2), d_uci = c(0, 5, 12, 18, 22), certified = c(TRUE, TRUE, FALSE, TRUE, TRUE) ) ssm_plot_trajectory(trajectory, time = "wave")data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") t1 <- jz2017[, scales] t1$id <- seq_len(nrow(t1)) t1$occasion <- "T1" t2 <- t1 t2$occasion <- "T2" res <- ssm_analyze_long(rbind(t1, t2), scales = scales, id = "id", occasion = "occasion" ) ssm_plot_trajectory(res) ssm_plot_trajectory(res, drop_xy = TRUE) # A model-based trajectory table, plotted on a continuous time axis trajectory <- data.frame( wave = 0:4, a_est = c(0.60, 0.55, 0.52, 0.58, 0.63), a_lci = c(0.48, 0.43, 0.40, 0.46, 0.51), a_uci = c(0.72, 0.67, 0.64, 0.70, 0.75), d_est = c(350, 355, 2, 8, 12), d_lci = c(340, 345, 352, 358, 2), d_uci = c(0, 5, 12, 18, 22), certified = c(TRUE, TRUE, FALSE, TRUE, TRUE) ) ssm_plot_trajectory(trajectory, time = "wave")
Calculate the SSM parameters for each row of a data frame and add the results as additional columns. This can be useful when the SSM is being used for the description or visualization of individual data points rather than for statistical inference on groups of data points.
ssm_score(data, scales, angles = octants(), append = TRUE, ...)ssm_score(data, scales, angles = octants(), append = TRUE, ...)
data |
Required. A data frame or matrix containing at least circumplex scales. |
scales |
Required. The variable names or column numbers for the
variables in |
angles |
Required. A numeric vector containing the angular displacement
of each circumplex scale included in |
append |
Optional. A logical indicating whether to append the output to
|
... |
Optional. Additional named arguments passed to
|
A data frame containing .data plus six additional columns
containing the SSM parameters (calculated rowwise).
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
data("aw2009") ssm_score( aw2009, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") )data("aw2009") ssm_score( aw2009, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") )
Estimate the Structural Summary Method profile that one or more external
measures show against the latent circumplex content of a set of
scales – the disattenuated analog of the correlation-based
ssm_analyze() – from a structural equation model with the scale angles
held fixed at their theoretical values. The measurement model is generated
by ssm_sem_syntax() and fitted with lavaan on raw covariances;
confidence intervals for all SSM parameters are constructed in-package by
propagating draws of the model's free parameters through the profile and
SSM transforms and applying the same percentile/circular-quantile machinery
as ssm_analyze(). No lavaan delta-method or percentile interval is ever
used for amplitude or displacement (their intervals must respect the
angular branch cut, which lavaan's := machinery does not).
ssm_sem( data, scales, angles = octants(), measures = NULL, grouping = NULL, contrast = FALSE, model = c("scaled", "strict"), invariance = NULL, invariance_alpha = 0.05, ci_method = c("mvn", "boot"), boots = 2000, interval = 0.95, estimator = "MLR", se = "robust.huber.white", missing = c("listwise", "fiml"), parallel = "no", ncpus = 1, ... )ssm_sem( data, scales, angles = octants(), measures = NULL, grouping = NULL, contrast = FALSE, model = c("scaled", "strict"), invariance = NULL, invariance_alpha = 0.05, ci_method = c("mvn", "boot"), boots = 2000, interval = 0.95, estimator = "MLR", se = "robust.huber.white", missing = c("listwise", "fiml"), parallel = "no", ncpus = 1, ... )
data |
Required. A data frame or matrix containing at least the circumplex scales and measures. |
scales |
Required. A character vector of column names, or a numeric
vector of column indexes, from |
angles |
Optional. A numeric vector containing the angular displacement
of each circumplex scale included in |
measures |
Optional with |
grouping |
Optional. A string naming the column of |
contrast |
Optional. A logical (default = FALSE) requesting a
difference of latent SSM parameters, always second minus first with the
displacement contrast in |
model |
Optional. The measurement-model tier passed to
|
invariance |
Optional. The highest invariance rung to fit and REPORT
( |
invariance_alpha |
Optional. The alpha level for the invariance gating decision (default = 0.05). The gate is a modeling decision with a default test, not an oracle; the invariance table is always returned so other criteria can be applied. |
ci_method |
Optional. How to generate parameter replicates: |
boots |
Optional. A single positive whole number indicating how many draws or bootstrap refits to use (default = 2000). |
interval |
Optional. A single number between 0 and 1 (exclusive) indicating the confidence level (default = 0.95). |
estimator |
Optional. The lavaan estimator (default = "MLR": maximum
likelihood with robust "Huber-White" standard errors and a scaled test
statistic, the standard choice for the skewed distributions typical of
circumplex scale scores). The parameter estimates are identical to
|
se |
Optional. The lavaan standard-error method for the fitted model
(default = "robust.huber.white", the sandwich estimator). This does not
affect the parameter estimates, only the covariance the |
missing |
Optional. Either |
parallel, ncpus
|
Optional. Passed to |
... |
Optional. Additional arguments passed to |
The latent profile of a measure is its vector of model-implied
disattenuated correlations with each scale's common (circumplex)
content: the scale's error and unique parts are removed from the
denominator, and the covariance is restricted to common content in the
numerator. All latent quantities are conditional on the fixed-angle
measurement model being adequate: global fit is reported by print(), and
a poorly fitting measurement model makes the latent SSM parameters
uninterpretable, not merely imprecise. The fixed angles are theoretical
claims, not estimates (use cpm_fit() to examine an instrument's real
geometry). Latent displacement is the first-harmonic direction of the
saturation-modulated disattenuated profile – heterogeneous scale
saturations rotate it exactly as they rotate the observed displacement;
the latent layer removes the reliability modulation, nothing more.
Model-implied disattenuated correlations at or beyond 1 indicate
misspecification and are refused rather than summarized.
The point estimates and intervals are reported for elevation, x-value,
y-value, amplitude, and displacement (no standard errors are printed
anywhere, matching the package's estimate-plus-interval reporting surface).
Unlike ssm_analyze()'s closed-form estimator, the latent transform is the
ordinary-least-squares projection onto the cosine basis, so for unequally
spaced angles the two functionals genuinely differ (they coincide exactly
for equally spaced angles, and more generally under first- and
second-harmonic balance); under OLS the fit value is a bounded R-squared in
[0, 1] at any spacing.
With grouping, the latent contrast this function computes and the observed
contrast that ssm_analyze() computes answer different questions and are not
substitutes. The observed contrast (ssm_analyze() with grouping) asks
whether the groups' measured profiles differ: it is a difference of SSM
parameters computed from each group's observed scores or correlations. It
confounds structural difference, differential reliability, and measurement
non-invariance – that is a property of its estimand, documented rather than
a defect, and it requires no invariance assumption. The latent contrast
(ssm_sem() with grouping) asks whether the groups' constructs differ,
granted the instrument measures the same thing in both groups: it is a
contrast on latent SSM parameters computed under cross-group equality
constraints, disattenuated and conditional on measurement invariance. When
the required invariance rung is rejected the latent contrast is not "more
principled" – it is misspecified, and the function therefore returns an
explicit non-comparison (the verdict plus each group's separate configural
profile; no contrast is computed or rendered by any method). Neither estimand
replaces the other; they answer different questions and can legitimately
disagree.
The displacement contrast is reported as the second group level minus the
first, in (-180, 180] degrees, with branch-aligned circular intervals
(endpoints may legitimately exceed +/-180 degrees near the boundary). Under
the scaled tier the general-plane covariances are fixed to zero in all groups
at all rungs (a stationarity-type assumption): a cross-group difference in a
general factor's lean into the plane surfaces as misfit, and the strict tier
is the tier that can express it. Under the strict tier the metric rung is
vacuous (all loadings fixed) and is reported as such.
A circumplex_ssm_sem object (a subclass of circumplex_ssm, so
ssm_table() and the ssm_plot_* functions work on it), containing
results (estimates and intervals), scores (the latent profile
vectors), details, call, plus sem (the fitted lavaan model: the
gate rung's fit for grouped analyses, or the configural fit when the
gate was rejected), invariance (for grouped analyses: the ladder
table, the comparable flag, the verdict text, the gate rung, and the
alpha used; NULL for single-group analyses), and model (tier,
generated syntax for single-group fits, and the OLS projection
weights).
Inadmissible parameter draws (a nonpositive common-part or measure
variance, or a disattenuated correlation at or beyond 1) are dropped
whole with a warning naming the causes; if more than 5% of draws are
inadmissible the analysis stops with advice to use ci_method = "boot"
or revise the model. Degenerate profiles (flat or zero-amplitude) keep
the same per-parameter NA contract as ssm_analyze().
This function consumes R's random number stream for both ci_method
settings ("mvn" through the package's own draws; "boot" through a
seed handed to lavaan's bootstrap). Call set.seed() immediately before
ssm_sem() for reproducible confidence intervals.
ssm_analyze() for the observed-score SSM, ssm_sem_syntax() for
the generated measurement model, and ssm_sem_parameters() to reuse a
lavaan fit you have modified or fitted yourself.
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem_parameters(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
data("jz2017") set.seed(12345) res <- ssm_sem( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = "NARPD", boots = 500 ) res summary(res)data("jz2017") set.seed(12345) res <- ssm_sem( jz2017, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO"), measures = "NARPD", boots = 500 ) res summary(res)
The low-level adapter behind ssm_sem(): take an already fitted
lavaan model of a fixed-angle circumplex measurement structure (as
generated by ssm_sem_syntax(), possibly user-modified – e.g., a
partial-invariance respecification) and compute latent SSM parameter
estimates with in-package confidence intervals. Compatibility with the
expected parameter structure is checked structurally (the named loading,
factor-covariance, and measure-covariance parameters must be present), not
by provenance.
ssm_sem_parameters( fit, scales, angles = octants(), measures = NULL, ci_method = c("mvn", "boot"), boots = 2000, interval = 0.95, contrast = FALSE, parallel = "no", ncpus = 1 )ssm_sem_parameters( fit, scales, angles = octants(), measures = NULL, ci_method = c("mvn", "boot"), boots = 2000, interval = 0.95, contrast = FALSE, parallel = "no", ncpus = 1 )
fit |
Required. A fitted lavaan object whose model preserves the
|
scales |
Required. A character vector with the scale (indicator)
names, in the same order as |
angles |
Optional. A numeric vector of the scales' theoretical angles
in degrees (default = |
measures |
Optional for multi-group fits, required otherwise. A
character vector of the measure names; |
ci_method, boots, interval, contrast, parallel, ncpus
|
See |
Important: multi-group fits are supported here as the partial-invariance
escape hatch, and this path bypasses the invariance gating that
ssm_sem() applies. Where ssm_sem() fits a configural-metric-scalar
ladder and refuses a latent group contrast when the required rung is
rejected, ssm_sem_parameters() computes the contrast from whatever
multi-group fit you supply without testing invariance at all. You own the
comparability claim: the groups are compared on this instrument's latent
metric only to the extent the model you fitted makes them comparable.
A circumplex_ssm_sem object; see ssm_sem().
This function consumes R's random number stream for both ci_method
settings ("mvn" through the package's own draws; "boot" through a
seed handed to lavaan's bootstrap). Call set.seed() immediately before
ssm_sem() for reproducible confidence intervals.
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_table(),
summary.circumplex_ssm_id()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
summary.circumplex_ssm_id()
data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") syn <- ssm_sem_syntax(scales = scales, angles = octants(), measures = "NARPD") # Robust (sandwich) SEs so the mvn engine propagates a # misspecification-consistent covariance (ssm_sem()'s default) fit <- lavaan::cfa(syn, data = jz2017, se = "robust.huber.white") set.seed(12345) ssm_sem_parameters(fit, scales = scales, measures = "NARPD", boots = 500)data("jz2017") scales <- c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") syn <- ssm_sem_syntax(scales = scales, angles = octants(), measures = "NARPD") # Robust (sandwich) SEs so the mvn engine propagates a # misspecification-consistent covariance (ssm_sem()'s default) fit <- lavaan::cfa(syn, data = jz2017, se = "robust.huber.white") set.seed(12345) ssm_sem_parameters(fit, scales = scales, measures = "NARPD", boots = 500)
Emit lavaan model syntax for a structural-equation-model formulation of the Structural Summary Method, with the circumplex scale angles held fixed at their theoretical values. This is the syntax-generation layer of the SEM-based SSM (see the package's design notes); it is a pure function of its arguments and does not require lavaan to be installed (only fitting the emitted model does).
ssm_sem_syntax( instrument = NULL, scales = NULL, angles = NULL, measures = NULL, model = c("scaled", "strict"), n_groups = 1, invariance = c("configural", "metric", "scalar", "strict_residuals"), include_defined = NULL )ssm_sem_syntax( instrument = NULL, scales = NULL, angles = NULL, measures = NULL, model = c("scaled", "strict"), n_groups = 1, invariance = c("configural", "metric", "scalar", "strict_residuals"), include_defined = NULL )
instrument |
Optional. A |
scales |
Optional. A character vector of circumplex scale (column)
names. Ignored when |
angles |
Optional. A numeric vector of scale angles in degrees, the same
length as |
measures |
Optional. Either |
model |
Optional. The measurement-model tier: |
n_groups |
Optional. A single positive whole number: the number of
groups for a multi-group model. |
invariance |
Optional. The cross-group invariance rung to emit when
|
include_defined |
Optional. (Single-group models only: for
|
Two model tiers are available. The "scaled" tier frees a general saturation
and a circumplex saturation per scale while fixing each scale's angle; the
circumplex plane is held isotropic and orthogonal, and the general factor is
held orthogonal to the plane (freeing the general-plane covariances
alongside free saturations makes the model locally unidentified exactly at
zero covariance, so they cannot be estimated in this tier). The "strict"
tier fixes every loading to the unit cosine pattern
(1, cos(angle), sin(angle)) and frees the 3x3 factor covariance matrix –
including the general-plane covariances, making it the tier that can model
a general factor leaning into the plane. The angles enter only as evaluated
cosine and sine constants; no angle is ever a free parameter.
The returned string always carries a weights attribute: the
ordinary-least-squares projection matrix that maps a profile vector to the
structural summary coordinates (e, x, y). For equally spaced angles this
equals the conventional closed-form estimator; for unequally spaced angles it
is the least-squares projection and can differ. The emitted syntax never
contains := definitions for amplitude or displacement: those are nonlinear
functions whose confidence intervals must be constructed in-package, not by
lavaan's delta method (which ignores the angular branch cut).
A single character string of lavaan model syntax, with
attributes angles (a circumplex_degree vector), scales, model,
weights (the 3-by-p OLS projection matrix, rows e, x, y),
n_groups, and (when n_groups >= 2) invariance.
ssm_analyze() for the observed-data SSM.
# Octant instrument, default scaled tier syn <- ssm_sem_syntax(scales = paste0("s", 1:8), angles = octants()) attr(syn, "weights") cat(syn)# Octant instrument, default scaled tier syn <- ssm_sem_syntax(scales = paste0("s", 1:8), angles = octants()) attr(syn, "weights") cat(syn)
Take in the results of an SSM analysis and return an HTML table with the desired formatting.
ssm_table(ssm_object, caption = NULL, drop_xy = FALSE, render = TRUE)ssm_table(ssm_object, caption = NULL, drop_xy = FALSE, render = TRUE)
ssm_object |
Required. The results output of |
caption |
A string to be displayed above the table (default = NULL). |
drop_xy |
A logical indicating whether the x-value and y-value parameters should be omitted from the output (default = FALSE). |
render |
A logical indicating whether the table should be displayed in the RStudio viewer or web browser (default = TRUE). |
A data frame containing the information for the HTML table. As a side-effect, may also output the HTML table to the web viewer.
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
summary.circumplex_ssm_id()
Other table functions:
html_render()
# Load example data data("jz2017") # Create table of profile results res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD") ) ssm_table(res) # Create table of contrast results res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD"), contrast = TRUE ) ssm_table(res)# Load example data data("jz2017") # Create table of profile results res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD") ) ssm_table(res) # Create table of contrast results res <- ssm_analyze( jz2017, scales = 2:9, measures = c("NARPD", "ASPD"), contrast = TRUE ) ssm_table(res)
Fuller display of an axes_reliability() object: everything print() shows
plus the estimated variance components (with standard errors) and the global
fit indices.
## S3 method for class 'circumplex_axes_reliability' summary(object, digits = 3, ...)## S3 method for class 'circumplex_axes_reliability' summary(object, digits = 3, ...)
object |
A |
digits |
The number of decimal places to display (default = 3). |
... |
Not used. |
object, invisibly.
Print the full report of an ssm_ci_accuracy() run: the assessed
configuration, a structure note describing the simulated population (with
cautions when the structural model converged badly or fits poorly –
benchmarks per Browne & Cudeck, 1993, and Hu & Bentler, 1999), the
per-profile verdict blocks (coverage of elevation, amplitude, and
certification-conditional displacement classified against Bradley's
liberal band; the guardrail false-certification caution), and the
coverage and guardrail tables across the amplitude ladder.
## S3 method for class 'circumplex_ci_accuracy' summary(object, digits = 3, ...)## S3 method for class 'circumplex_ci_accuracy' summary(object, digits = 3, ...)
object |
A |
digits |
Number of digits to which table entries are rounded (default = 3). |
... |
Currently ignored. |
The object, invisibly.
Browne, M. W., & Cudeck, R. (1993). Alternative ways of assessing model fit. In K. A. Bollen & J. S. Long (Eds.), Testing structural equation models (pp. 136-162). Sage.
Hu, L., & Bentler, P. M. (1999). Cutoff criteria for fit indexes in covariance structure analysis: Conventional criteria versus new alternatives. Structural Equation Modeling, 6(1), 1-55.
Fuller display of a cpm_fit() object: adds the correlation-function weights,
the full set of fit indices, a residual summary (the largest absolute
residual and the pair it belongs to), and all boundary/identification
diagnostics in plain language. When the confidence intervals are analytic,
prints a coverage caution calibrated by simulation: unconditionally when the
sample size is modest (N < 2000, where Wald intervals mis-covered for every
configuration studied), and up to N = 50000 when the fitted solution shows a
boundary or weak-identification marker (Heywood communality, removed
harmonic, small correlation-function weight, ill-conditioning, or competing
near-tied optima), the regime where they mis-covered even at large N (see
cpm_fit()).
## S3 method for class 'circumplex_cpm' summary(object, digits = 3, ...)## S3 method for class 'circumplex_cpm' summary(object, digits = 3, ...)
object |
A |
digits |
The number of decimal places to display (default = 3). |
... |
Not used. |
object, invisibly.
Aggregate a per-person SSM parameter table (from ssm_parameters_id())
into group-level summaries, using circular statistics for displacement:
arithmetic means are meaningless for angles, so displacement is summarized
by its circular mean (the direction of the summed unit vectors) and the
mean resultant length (a 0 to 1 measure of directional concentration).
## S3 method for class 'circumplex_ssm_id' summary(object, ...)## S3 method for class 'circumplex_ssm_id' summary(object, ...)
object |
Required. An object of class |
... |
Ignored (S3 consistency). |
Persons with undefined (NA) displacement are stripped before the
circular aggregation – n_na_d reports how many – while the arithmetic
means of the other parameters use all persons with defined values. Two
aggregation caveats apply. (1) The circular mean of per-person
displacements weights every person's direction equally; it is a
different quantity from the displacement of the group mean profile
(e.g., from ssm_analyze()), which weights persons by amplitude – on
heterogeneous samples the two can differ substantially. (2) By the
triangle inequality, the amplitude of the group mean profile is at most
the mean per-person amplitude (a_mean), strictly smaller when
directions disperse; relatedly, the mean resultant length d_res falls
below 1 as directions disperse.
A one-row data frame with columns n (persons), n_na_d
(persons with undefined displacement, excluded from the circular
summaries), e_mean, x_mean, y_mean, a_mean (arithmetic means),
d_mean (circular mean of displacement, degrees in [0, 360], the
0/360 pole reported as 360), and
d_res (mean resultant length in [0, 1]; NA when no displacement
is defined, and undefined direction at zero resultant reports
d_mean = NA).
Other ssm functions:
plot.circumplex_ci_accuracy(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters(),
ssm_table()
Other analysis functions:
cpm_fit(),
cpm_simulate(),
ssm_analyze(),
ssm_analyze_long(),
ssm_ci_accuracy(),
ssm_draws(),
ssm_parameters(),
ssm_parameters_id(),
ssm_score(),
ssm_sem(),
ssm_sem_parameters()
data("aw2009") res <- ssm_parameters_id( aw2009, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") ) summary(res)data("aw2009") res <- ssm_parameters_id( aw2009, scales = c("PA", "BC", "DE", "FG", "HI", "JK", "LM", "NO") ) summary(res)
Fuller display of a fit_structure() object: adds the interpretive cutoffs
behind each classification, the estimated angle and communality of each
scale, and the analysis settings.
## S3 method for class 'circumplex_structure' summary(object, digits = 3, ...)## S3 method for class 'circumplex_structure' summary(object, digits = 3, ...)
object |
A |
digits |
The number of decimal places to display (default = 3). |
... |
Not used. |
object, invisibly.
The ggplot2 theme applied to the circumplex canvas built by
ggcircumplex(). It is built on ggplot2::theme_minimal() so that the
amplitude rings, displacement spokes, and labels drawn by coord_circumplex()
are themed panel furniture that respond to further theming. Apply it to a
custom circumplex plot, and add + theme_*() or + theme() on top to
restyle the canvas.
theme_circumplex(base_size = 12)theme_circumplex(base_size = 12)
base_size |
A single positive number giving the base font size (in pt) for the theme (default = 12). |
A ggplot2 theme object, to be added to a plot with +.
Other circumplex layers:
coord_circumplex(),
geom_ssm_arc(),
geom_ssm_path(),
geom_ssm_point(),
ggcircumplex(),
scale_x_circumplex()
# Restyle the canvas with a larger base font ggcircumplex(octants()) + theme_circumplex(base_size = 16)# Restyle the canvas with a larger base font ggcircumplex(octants()) + theme_circumplex(base_size = 16)