---
title: "Getting started with bayesqm"
output:
  rmarkdown::html_vignette:
    toc: true
    toc_depth: 2
vignette: >
  %\VignetteIndexEntry{Getting started with bayesqm}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
bibliography: REFERENCES.bib
csl: apa.csl
link-citations: true
---

```{r, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>",
                      fig.width = 7, fig.height = 5)
library(bayesqm)
```

You have a stack of completed Q sorts and a practical question. How
many viewpoints does the panel hold, who holds each one, and which
statements set them apart? `bayesqm` answers from a model of the
sorting event itself. Each participant placed every statement into a
fixed grid, the quotas make that placement an ordered partition of the
statement set, and the package computes the probability of the
observed partition exactly. The tables that come back are the ones a
Q study reports, with the uncertainty of every entry.

This vignette walks one analysis end to end on a small demonstration
fit, so it knits in seconds. On real data, replace `demo_fit()` with
`fit_bayesian()`. A fit at typical panel sizes takes a minute or two.

## The sorts

`read_qsort()` reads the common formats. CSV and Excel grids, PQMethod
`.DAT`, Ken-Q JSON and multi-sheet Excel, KADE ZIP exports, and
Easy-HTMLQ Firebase JSON.

```{r, eval = FALSE}
qdata <- read_qsort("mystudy.dat")        # PQMethod file, for example
qdata <- qsort_data(Y, distribution = c(2, 3, 4, 5, 4, 3, 2))
```

One scope note up front. The exact likelihood is a statement about the
forced sorting event, so `fit_bayesian()` requires every sort to match
the design grid and names any participant who does not.
Free-distribution studies, which Ken-Q, HTMLQ, and KADE permit, are
outside this model's scope. The import functions still read them for
inspection.

Before any model runs, look at what the participants actually did.
`plot(qdata)` draws every completed sort as its own pyramid, one tile
per statement, the color giving the column it was placed in. Here on
`obesity_sorts`, the childhood obesity panel of @AkhtarDanesh2023 that
ships with the package. 33 participants, 42 statements, a nine-column
grid.

```{r, fig.height = 6}
data(obesity_sorts)
plot(obesity_sorts, participants = 1:6)
```

A reversed sorter, a pattern shared by nobody, a data-entry slip, all
of it shows up here first, while it is still a data question rather
than a modeling one.

## The fit

```{r}
fit <- demo_fit(seed = 1)
fit
```

The header carries what a fit is. The likelihood, the panel, the
draws, the convergence check, and the alignment. Convergence is judged
on summaries that do not depend on rotation, and a chain that misses
the bar is extended at successive doublings up to a cap. If it still
misses, the fit warns, and `extend(fit)` continues exactly where it
stopped, draw for draw identical to one longer run. Rotational, sign,
and label ambiguity is resolved by the MatchAlign procedure of
@PoworoznekEtAl2025 with a polarity rule, so defining sorts load
positively and every summary comes from one common orientation.

## Who holds each viewpoint

Loadings on a bounded correlation scale, with credible intervals.

```{r}
head(compute_loadings(fit))
```

A flag probability is the posterior share of draws in which a
participant defines the factor, and the unclassified state keeps
cross-loading and abstention visible instead of forcing a yes or no.

```{r}
compute_flags(fit)
```

## What each viewpoint says

The factor array is the viewpoint written as a completed sort,
quota-exact by construction.

```{r}
head(compute_factor_array(fit))
```

```{r}
plot_factor_array(fit)
```

Darker tiles are placements the posterior is more certain of.

## Where they differ and where they agree

The critical difference is computed from the posterior spread of each
score contrast, and consensus is a positive finding, the event that
every factor places a statement within one grid column of the others.
A statement can be distinguishing, consensus, or neither.

```{r}
qdc <- compute_qdc(fit)
table(qdc$verdict)
```

```{r}
plot_contrasts(fit)
```

## What gets reported

One rule decides. `claims()` keeps the most probable flags,
distinguishing statements, consensus statements, and pairwise stars,
and stops adding claims when the expected share of false ones passes
the level you set.

```{r}
claims(fit, q = 0.05)
```

## The per-factor block

`factor_characteristics()` is the summary a results section quotes.
How many sorts define each factor, with an interval, how spread the
factor's statement scores are, and how reliable its defining sorts
are.

```{r}
factor_characteristics(fit)
```

## Checking the model

```{r}
check_fit(fit, draws = 30)
```

The person check separates sorts the model spans from shared
viewpoints it does not.

```{r}
check_persons(fit, draws = 15, mixes = 30)
```

## How many viewpoints

`fit_ladder()` fits a ladder of candidate K and `select_k()` applies
two checks together. Adequacy asks whether K factors account for the
shared structure in the panel. Support asks whether every factor earns
its place, meaning at least two selected flags and one selected
distinguishing statement. Expect one fit's runtime per rung.

```{r, eval = FALSE}
ladder <- fit_ladder(qdata)
select_k(ladder)
plot_choice_k(select_k(ladder))
```

`loo_ladder()` adds PSIS-LOO [@VehtariEtAl2017] as directional
corroboration only. At typical Q panel sizes its standard errors
cannot certify adjacent K.

## Coming from PQMethod or qmethod

The outputs you know have direct counterparts. Flagging, automatic or
by hand, becomes `compute_flags()`, and `claims()` selects the flags
at your false-discovery level. The loadings table is
`compute_loadings()`, the factor arrays and z-scores are
`compute_factor_array()` and `compute_zscores()`, and the
distinguishing and consensus statements are the three-way verdicts of
`compute_qdc()`. In place of eigenvalue rules and parallel analysis,
the number of factors comes from `fit_ladder()` and `select_k()`.
Explained variance alone has no counterpart in a generative model.
Report the defining-sort counts from `factor_characteristics()` and
the extra-factor check from `check_fit()` instead.

## Reproducibility

Fits are exactly reproducible given a seed, and `extend()` preserves
that. It restores the sampler's saved random-number state, so
continuing a chain after any amount of unrelated R work gives the same
draws as one uninterrupted run.

## Where next

The remaining views are `plot_zscores()` for the whole statement
panel, `plot_statement()` for one statement in depth,
`plot_loading_posterior()`, `plot_flags()`, `plot_person_check()`,
`plot_convergence()`, and `plot_ppc()`, with `ggplot2::autoplot()`
methods for loadings, flags, contrasts, and the array. The reference
index at <https://rdazadda.github.io/bayesqm/> groups every function
by task.

## References
