An R package for characterising brain state dynamics from functional connectivity time series β computing fractional occupancy, dwell time, and Markov-chain transition probabilities across states.
stateR provides a tidy, tidyverse-compatible toolkit for quantifying how the brain moves through discrete functional states over time. Given a data frame of state labels at each time point β typically derived from k-means or HMM clustering of dynamic functional connectivity matrices β the package computes three core brain-state metrics:
- Fractional occupancy β how often each state is visited
- Dwell time β how long each state is continuously occupied
- Markov transition probabilities β the likelihood of moving from one state to another
All functions return nested tibbles that slot naturally into grouped purrr::map pipelines, making stateR especially well suited for multi-subject neuroimaging studies.
The package was developed for and is used in:
FranΓ§a LGS, Ciarrusta J, Gale-Grant O, Fenn-Moltu S, Fitzgibbon S, Chew A, Falconer S, Dimitrova R, Cordero-Grande L, Price AN, Hughes E, O'Muircheartaigh J, Duff E, Tuulari JJ, Deco G, Counsell SJ, Hajnal JV, Nosarti C, Arichi T, Edwards AD, McAlonan G, Batalle D (2024). Neonatal brain dynamic functional connectivity in term and preterm infants and its association with early childhood neurodevelopment. Nature Communications, 15, 16. https://doi.org/10.1038/s41467-023-44050-z
In that study, nest_fo, nest_dwell, and clusters_markov were applied to resting-state fMRI brain state sequences derived from k-means clustering of dynamic functional connectivity in 390 term- and preterm-born neonates from the developing Human Connectome Project (dHCP), to characterise how state occupancy and transitions relate to postmenstrual age, preterm birth, and 18-month neurodevelopmental outcomes (Bayley-III, Q-CHAT).
- π Fractional occupancy β proportion of total time spent in each state per subject/group (
nest_fo) - β±οΈ Dwell time β mean continuous occupancy duration per state, excluding single time-point visits (
nest_dwell) - π Markov transition matrix β pairwise transition counts and normalised probabilities, with optional removal of self-transitions (
clusters_markov) - π¦ Tidy outputs β all functions return nested tibbles, ready for
unnest()and downstream statistical testing withptestR - π§© Grouped pipeline-friendly β designed for
dplyr::group_by+purrr::mapworkflows across subjects, sessions, or conditions
stateR/
βββ R/
β βββ clusters_markov.R # Markov transition probability computation
β βββ dwellCount.R # Internal helper: run-length encoding of state sequences
β βββ nest_dwell.R # Mean dwell time per state, nested by state
β βββ nest_fo.R # Fractional occupancy per state, nested by state
βββ man/ # Roxygen2-generated documentation
βββ DESCRIPTION
βββ NAMESPACE
βββ stateR.Rproj
- R β₯ 4.0
- The following packages (installed automatically as dependencies):
| Package | Role |
|---|---|
dplyr |
Data manipulation |
tidyr |
Reshaping and nesting outputs |
purrr |
Functional iteration over state sequences |
janitor |
Tabulation for fractional occupancy (tabyl) |
glue |
String interpolation for transition tags |
stateR is not on CRAN. Install directly from GitHub:
# install.packages("remotes") # if needed
remotes::install_github("CoDe-Neuro/stateR")library(stateR)
library(dplyr)
library(tidyr)
# Example: 3 subjects, 20 time points each, 4 possible states (0β3)
set.seed(42)
tbl <- tibble::tibble(
subject = rep(c("sub-01", "sub-02", "sub-03"), each = 20),
session = rep("ses-01", 60),
time = rep(1:20, 3),
state = sample(0:3, 60, replace = TRUE)
)
# Fractional occupancy
fo <- nest_fo(tbl,
vars = c("subject", "session"),
foVar = "state")
# Dwell time
dwell <- nest_dwell(tbl,
vars = c("subject", "session"),
foVar = "state",
sortBy = "time")
# Markov transitions
trans <- clusters_markov(tbl,
vars = c("subject", "session"),
cVar = "state",
sortBy = "time",
groupBy = "subject",
remIntra = FALSE)Estimates the fractional occupancy β the proportion of total time points that a subject/group spends in each state.
nest_fo(tbl, vars, foVar)| Argument | Type | Description |
|---|---|---|
tbl |
tibble / data frame | Long-format data with one row per subject per time point |
vars |
character vector | Grouping variables (e.g. c("subject", "session", "group")) |
foVar |
character | Column name containing the state label at each time point |
Returns a nested tibble with one row per state. Each row contains a data list-column holding a tibble of fractional occupancy (perc) per grouping combination.
Example output structure:
# A tibble: 4 Γ 2
cluster data
<chr> <list>
1 0 <tibble [90 Γ 3]>
2 1 <tibble [90 Γ 3]>
3 2 <tibble [90 Γ 3]>
4 3 <tibble [90 Γ 3]>
Typical pipeline:
nest_fo(tbl, vars = c("subject", "group"), foVar = "state") %>%
tidyr::unnest(data) %>%
dplyr::filter(cluster == "2") %>%
ptestR::grouped_perm_glm(perc ~ group, "perc")Estimates the mean dwell time β the average number of consecutive time points a subject/group spends in an uninterrupted visit to each state. Single time-point visits (dwell = 1) are excluded from the mean.
nest_dwell(tbl, vars, foVar, sortBy)| Argument | Type | Description |
|---|---|---|
tbl |
tibble / data frame | Long-format data with one row per subject per time point |
vars |
character vector | Grouping variables (e.g. c("subject", "session")) |
foVar |
character | Column name containing the state label at each time point |
sortBy |
character | Column name of the time index used to order observations before run-length encoding |
Returns a nested tibble with one row per state. Each data list-column holds a tibble of mean dwell time (mean_dwell) per grouping combination.
Note: The internal helper dwellCount() performs run-length encoding on the ordered state sequence. Only transitions that persist for more than a single time point contribute to mean_dwell.
Example:
nest_dwell(tbl,
vars = c("subject", "session"),
foVar = "state",
sortBy = "time") %>%
tidyr::unnest(data) %>%
dplyr::filter(cluster == "1")Computes Markov transition probabilities between states. For each source state, the function counts all observed transitions to each target state and normalises by the total number of transitions out of that source state. The analysis is memoryless (first-order Markov), treating all transitions equally regardless of history.
clusters_markov(tbl, vars, cVar, sortBy, groupBy, remIntra = FALSE)| Argument | Type | Description |
|---|---|---|
tbl |
tibble / data frame | Long-format data with one row per subject per time point |
vars |
character vector | Variables to carry through to the output (typically grouping + covariate columns) |
cVar |
character | Column name containing the state label at each time point |
sortBy |
character | Column name of the time index used to order observations before computing transitions |
groupBy |
character | Grouping variable for computing transitions (e.g. "subject") |
remIntra |
logical | If TRUE, self-transitions (state β same state) are removed before computing probabilities (default: FALSE) |
Returns a nested tibble with one row per unique sourceβtarget transition tag (e.g. "0_2"). Each data list-column contains normalised transition probabilities (nCount) and raw counts (n) per grouping combination.
Transition tag format: "<source>_<target>" β for example, "2_0" denotes a transition from state 2 to state 0.
Example:
clusters_markov(tbl,
vars = c("subject", "group"),
cVar = "state",
sortBy = "time",
groupBy = "subject",
remIntra = TRUE) %>%
tidyr::unnest(data) %>%
dplyr::filter(tag == "0_2") %>%
ptestR::grouped_perm_glm(nCount ~ group, "nCount")All three exported functions return state-nested tibbles β one row per state (or per transition pair for clusters_markov), with a data list-column for downstream analysis:
| Function | Nesting key | Key output column | Unit |
|---|---|---|---|
nest_fo() |
cluster |
perc |
Proportion (0β1) |
nest_dwell() |
cluster |
mean_dwell |
Time points |
clusters_markov() |
tag (e.g. "0_2") |
nCount |
Probability (0β1) |
This nesting structure is intentional: it mirrors the output of ptestR functions and makes it straightforward to apply statistical tests per state or per transition using purrr::map.
If you use stateR in your research, please cite the paper it was developed for:
@article{franca2024neonatal,
title = {Neonatal brain dynamic functional connectivity in term and preterm infants
and its association with early childhood neurodevelopment},
author = {Fran{\c{c}}a, Lucas G. S. and Ciarrusta, Judit and Gale-Grant, Oliver and
Fenn-Moltu, Sunniva and Fitzgibbon, Sean and Chew, Andrew and
Falconer, Shona and Dimitrova, Ralica and Cordero-Grande, Lucilio and
Price, Anthony N. and Hughes, Emer and O'Muircheartaigh, Jonathan and
Duff, Eugene and Tuulari, Jetro J. and Deco, Gustavo and
Counsell, Serena J. and Hajnal, Joseph V. and Nosarti, Chiara and
Arichi, Tomoki and Edwards, A. David and McAlonan, Grainne and
Batalle, Dafnis},
journal = {Nature Communications},
volume = {15},
pages = {16},
year = {2024},
doi = {10.1038/s41467-023-44050-z}
}| Role | Name | Affiliation |
|---|---|---|
| Author, maintainer | Lucas G. S. FranΓ§a | King's College London |
| Author | Dafnis BatallΓ© | King's College London |
Part of the CoDe-Neuro Lab at King's College London.
- π§ͺ ptestR β Permutation-based significance testing for GLMs, LMMs, and logistic regression; designed to work directly with
stateRoutputs
Released under the MIT License.
Copyright Β© Lucas G. S. FranΓ§a and Dafnis BatallΓ©, 2024