Real-Data Trajectory Analysis
motco.analysis runs the measurement the simulation studies validated on your
own data: pooled per-feature standardization, a stage-supervised PLS-DA latent
space with the double-CV rank rule, delta / angle / shape between two
groups in that space with the net-displacement orientation estimator, and RRPP
p-values. analyze_trajectories is the Python entry point and motco analyze
the command-line one; both write the same analysis artifact.
Use this entry point rather than assembling motco plsr + motco de by hand.
Those commands are a different pipeline: they skip the M-value contract, choose
the rank without the parsimony tie-break, measure angle with PC1 by default,
and record neither the selected rank, the null summary nor the spectrum.
Input contract
- Blocks. One or more named omic blocks, each a samples × features table
with string feature names. Blocks are concatenated in the order you declare
them, and every joint feature is named
"{block}__{feature}". Rows must equal the metadata's sample ids in the same order; every block needs at least one feature and only finite values. - Units. Each block declares a unit transform:
identity(the default) orbeta_to_mvalue(the logit of methylation beta values; values must lie in the open interval (0, 1)). MOTCO does not normalize counts, filter features or impute values. Supply blocks in the continuous units you want measured, for example log-normalized pseudobulk expression. The record states each block's declared units. - Metadata. A sample-id column, a group column with exactly two labels and a stage column, all named by you. Every group × stage cell must be observed.
-
Stage order. Required and explicit. Net displacement runs from the first to the last declared stage, and
shape, the spectrum and every table follow this order. Stage order is never inferred by sorting labels, becauseHigh<Intermediate<Lowalphabetically. Group order is optional and defaults to the labels sorted as strings. -
Covariates (optional).
covariate_colsnames metadata columns, in model order; see Covariates.
Violations raise TrajectoryAnalysisError (a ValueError) naming the block,
labels or cell at fault.
What is measured and recorded
The latent space is fitted once on all samples, with the rank chosen by double
cross-validation (the modal rank across outer repeats, the smaller rank winning
ties) from the candidate ranks at or above the rank floor, min_components=2
by default (CLI --min-components), so angle and shape are measured in a
space of at least two dimensions. min_components=1 restores the unfloored
0.9.0 rule and reproduces every 0.9.0 record and table byte for byte; a floor
below 1 is rejected before anything is fitted. The CV defaults are the ones the
operating studies ran: cv2_splits=4, cv1_splits=3, n_repeats=5,
max_components=20, random_state=1203, each clamped to what the smallest
stage can support (max_components to at least the floor plus one; a sample
that cannot satisfy the floor is an error naming the counts). forced_components
fixes the rank and skips cross-validation for the dimensionality sensitivity
analysis, ignoring the floor; the record then says component_selection: "forced".
record (written as result.json) holds:
| Key | Contents |
|---|---|
statistics, p_values |
delta, angle, shape and their RRPP p-values (shape is null with two stages) |
null_summary |
per statistic: retained draws, mean, sd, 50/90/95/99 % quantiles of the permutation null |
config_spectrum |
eigenspectrum of the latent stage-mean configuration, pooled and per group, plus the permutation eigengap summary |
latent |
selected_lv, component_selection, CV settings (min_components beside them when the floor is above 1), cv_mean_auroc, feature counts, feature_order_signature |
design |
group and ordered stage levels, cell sizes per group × stage, contrast, analysed sample count |
covariates |
only when covariates are declared: names, kinds, factor levels and reference levels, design columns, the LS-mean reference row, missing policy, dropped samples, coefficients per latent component |
blocks |
each block's name, feature count, transform and units |
measurement |
orientation estimator, selected rank, permutations, seed, runtime |
params, software |
resolved parameters; MOTCO, numpy, scipy, scikit-learn, pandas and Python versions |
attribution |
the compact attribution record, or a not_requested marker |
The selected rank sits beside the angle result because orientation is only
interpretable relative to the space it was measured in. The null summary shows
how wide the observed statistic's own null was, and the relative eigengap in the
spectrum indicates whether a group's orientation is resolvable at all.
The floor guarantees two dimensions, not a second axis with signal. Under
the unfloored rule a weak stage signal makes every candidate rank tie near an
AUROC of 0.5 and parsimony selects rank 1, where the two groups' orientations
are parallel or antiparallel by construction, angle is 0° or 180°, its RRPP
null is a two-point distribution, and collinear stage means carry no bend for
shape; both SEA-AD cohorts selected rank 1. With the floor, when the stage
signal supports one component the second is the best of the remaining
candidates, and angle's null widens accordingly. Read the record's
config_spectrum relative eigengap and null_summary.angle together: they say
how resolvable orientation is in each analysis. The floor was validated on a
small-n construction calibrated to select rank 1 by scripts/rank_floor_check.py
(rank_floor_decision.json), with the floor-1 arm reported beside it: the
2026-10-23 run returned adopt_floor at both calibrated strengths
(report), with power at the null in both
arms, so the floor defines angle and shape without making them powerful.
Equivalence to the simulation harness
analyze_trajectories and evaluate_semisynthetic_trajectory(...,
integration_method="pls") call the same block-scaling cores and the same
fit_pls_latent_space. On identical data, stage order and settings, the rank
floor included, they return
the same latent matrix, statistics, p-values, selected rank, null summary and
spectrum. tests/test_analysis.py checks this for the default estimator, PC1
and a two-block layer selection.
Attribution
With attribution=AttributionDiagnosticSettings(enabled=True, ...) (CLI:
--attribution), frozen-model orientation attribution runs on the fitted
pooled estimator and the standardized joint matrix it was fitted to, with your
stage order and group labels. The latent space is not refitted. Real data carry
no generator truth, so the truth-recovery block is reported unavailable rather
than invented. The full tables are written under attribution/.
Analysis artifact
write_analysis_outputs(result, out_dir) writes:
result.json: the record above.latent_scores.csv: samples ×pls_*, indexed by sample id.pls_loadings.csv:block,feature,pls_*(the PLSx_rotations_, in joint order).stage_means.csv:group,stage,pls_*, the fitted latent LS-mean vectors in declared stage order. Pass these tomotco.viz.plot_trajectories.attribution/*.csv, when attribution ran.
It refuses to replace an existing result.json unless overwrite=True
(CLI: --overwrite). The fitted scikit-learn estimator is not pickled, because
pickles are version-fragile. The scores, loadings and recorded feature order
signature are enough to audit and re-project the fit.
Covariates
Donor covariates such as age at death, PMI or RIN enter the trajectory regression in the latent space, so the stage means, the RRPP reduced model and therefore what is permuted all account for them. Declare them on the dataset:
dataset = TrajectoryDataset(
...,
covariate_cols=["age_at_death", "pmi", "education_level"],
categorical_covariates=["education_level"], # optional; non-numeric columns are categorical anyway
missing_covariates="complete_case", # default "error"
)
CLI: --covariate age_at_death --covariate pmi --categorical-covariate
education_level --missing-covariates complete_case.
- Coding. A numeric (non-boolean) column enters as one design column holding
its values. Any other column, or one listed in
categorical_covariates(for numeric-coded factors), enters as drop-first indicatorsname[level], with levels ordered as strings (numerically when every label is an integer); the first level is the reference. - Model. The full model is
group × stage + covariatesand the reduced modelgroup + stage + covariates. Covariates are additive: no interaction with group or stage. RRPP permutes the reduced model's residuals as before, so every permuted dataset keeps the fitted covariate effects. - LS-means. Every group × stage mean is evaluated at the pooled mean of each
covariate design column (for a factor, its observed level proportions). The
covariate term then adds the same vector to every stage mean, and
delta,angleandshapeare translation-invariant, so the statistics do not depend on the reference. Onlystage_means.csvdoes, and the record states the reference row. - Missing values.
missing_covariates="error"(the default) rejects any missing covariate value, naming the column and up to ten samples."complete_case"drops those samples from the metadata and every block before standardization, the latent fit and the design, and records the dropped ids. A deletion that empties a group × stage cell is an error. Covariates are never imputed; blocks must still be complete. - Guards. A covariate that is also the sample, group or stage column, a constant numeric covariate, a factor with one observed level, a non-finite numeric value, and a model with covariates that is not of full column rank (for example a covariate collinear with group × stage) are rejected with an error naming the covariate(s).
By default the latent space is covariate-blind, and the adjustment is still exact.
PLS-DA is fitted on the standardized features against stage alone, exactly as
without covariates, so the latent scores, loadings and selected rank do not
change. OLS commutes with a fixed linear map: regressing the scores T = XW on
[design, covariates] gives the coefficients of regressing X on the same
design, projected by W. The stage means are therefore adjusted exactly as in
feature space; only the basis W was chosen without the covariates. If a
covariate effect is large and aligned with stage, PLS may spend a component on
it; latent adjustment chooses the basis with the
covariates instead.
Attribution is not available with covariates. Frozen-model attribution works from unadjusted cell means, so a request for both raises an error before any fitting.
Keep the covariate set parsimonious. Small cells (the SEA-AD MTG design
has 9–28 donors per cell) and many covariate columns can make the model
near-singular or the null unstable. The record's design_columns states the
degrees of freedom used.
Type I validation. scripts/covariate_type_i_check.py measures size at the
Phase 6 design with covariates confounded with group, stage and their
interaction (adjusted vs unadjusted arms on a shared latent fit); see
the report. Report covariate-adjusted
results only under its covariates_validated decision.
Without covariates the record, the artifact and every output are identical to
MOTCO 0.7.0 (except the runtime); the covariates key is absent and the schema
version is unchanged (tests/test_analysis_identity.py).
Latent adjustment
With covariates declared, the PLS-DA basis is still fitted on the features
alone. A large technical axis aligned with stage (library quality, for example)
can then take a whole component, and at a selected rank of 1 or 2 that leaves
little room for the biology. covariate_latent_adjustment (CLI:
--latent-adjustment) fits the basis on features residualized on the declared
covariates instead:
params = TrajectoryAnalysisParams(permutations=999, seed=1, covariate_latent_adjustment="stage")
motco analyze ... --covariate age_at_death --covariate pmi --latent-adjustment stage
- Conditional residualization. Every pooled-standardized joint feature is
regressed on
[1, D, C], whereCholds the declared covariate design columns andDthe conditioning design, and only the fitted covariate partC γis subtracted. Understage,Dis the drop-first stage indicators; undergroup_stage, the group, stage and group × stage indicators. By Frisch–Waugh–Lovell,γis the covariates' within-design effect, so stage signal that is merely correlated with a covariate stays in the features. Residualizing on the covariates alone would remove it: label-blind residualization upstream of MOTCO dropped the case study's held-out CV AUROC from 0.63 to 0.41.stagekeeps the group label out of the basis; undergroup_stagethe group enters only through the pooled within-cell slope. Usestage: it is the conditioning the Type I check admitted (see below). - Leak-free cross-validation. Inside the double CV, every outer rest set and
inner training set estimates its own
γand residualizes its held-out samples asX_held_out − C_held_out γ, so held-out labels never enter the residualization. Both CV levels stratify their folds on the conditioning cells (stages understage, group × stage cells undergroup_stage), so every training set can estimate the conditioning design. Understagethe folds equal those of the unadjusted analysis. The final basis usesγestimated on all samples. - The pooled scale is kept. The residualized features are not
re-standardized: every PLS fit on this path uses
scale=False. A feature whose variance was mostly covariate is down-weighted, not inflated back to unit variance, and when the covariate effects are weak the basis approaches the unadjusted one. - The raw features are measured in the new basis. The latent scores are the
pooled-standardized features (not the residuals), centered at the residuals'
mean and projected onto the basis. The trajectory model, the LS-means, the
RRPP reduced model and the permutations are exactly those of the
covariate-adjusted analysis above. With the covariates in both RRPP models,
projecting the raw or the residualized features gives identical statistics,
p-values and null draws, because the difference
(C − C̄) γ Wlies in the models' column space. So only the choice of basis (and of CV rank) changes. Measuring the raw features keeps thecovariatesblock's coefficients andstage_means.csvon the same footing as without the setting. - The same covariates in both places. The residualization covariates are
exactly
covariate_cols, which also enter the trajectory model; that equality is what makes the projection choice immaterial. To residualize on technical variables, declare them as covariates. - Guards. The setting without covariates is an error before any fitting.
The full-sample residualization design must have full column rank, otherwise
the error names the covariates and the conditioning. Every CV training design
must too, otherwise the error names the repeat and fold; this happens when a
rare factor level drops out of a training set, and depends on
random_state. Merge rare levels upstream rather than relying on a minimum-norm fit, whose held-out shift would be arbitrary. Attribution stays unavailable with covariates. - Record.
result.jsongains alatent_adjustmentblock aftercovariates, andlatent.integration_params.latent_adjustmentnames the conditioning. The block holdsconditioning,covariates,design_columns(conditioning then covariate columns, beyond the intercept),n_samples,residual_df(n − 1 − k − q),cv_min_training_df(the smallest training-set residual df seen in CV;nullwithforced_components),feature_scale(pooled_standardized) andfeature_r2. That last field summarizes each feature's partial R² of the covariates given the intercept and conditioning (5/25/50/75/95 % quantiles, mean, fraction above 0.5), the share of variance the residualization removes.params.covariate_latent_adjustmentis recorded only when set.
Mediator limitation. Residualizing a variable that mediates the stage effect removes real signal, and no simulation can tell a confounder from a mediator. Choosing and justifying the covariate set is the analysis's job, not MOTCO's: a technical variable that is itself downstream of disease stage (a cell-quality metric that worsens with pathology, say) is a mediator candidate.
Validation. scripts/latent_adjustment_type_i_check.py measures size at
the Phase 6 design under a covariate-aligned nuisance axis calibrated so that
the unadjusted basis spends its first component on it (median |Spearman| ≥ 0.8).
It runs three arms per replicate (unadjusted basis, stage, group_stage) at
8 declared covariates, and its decision file names the admissible
conditionings (adopt_stage | adopt_group_stage | diagnose_latent_excess).
The 2026-10-20 run returned adopt_stage
(report). stage held
delta 0.031, angle 0.067 and shape 0.058 against 0.0706. group_stage
exceeded the bound on angle (0.082) and is not admissible. About 10 % of
replicates lost an arm to a rare factor level.
scripts/latent_adjustment_power_comparison.py compares power with and without
such an axis against the unadjusted basis. Its 2026-10-20 run
(report) returned
candidate_fails for both conditionings. stage raised orientation power
(angle 0.92–0.93 against 0.64–0.78 at the top effect) but lost shape power
when the nuisance axis was present, and small-magnitude power without it.
group_stage lost most orientation and shape power. Residualizing on
covariates confounded with the design removes signal even when they have no
effect. Report latent-adjusted results only with stage conditioning, as a
sensitivity analysis beside the covariate-adjusted analysis rather than as a
replacement, under the conditions of both reports.
Validation at the case study's configuration. scripts/case_study_type_i_check.py
measures size where the SEA-AD case study is actually run: the rank floor of 2,
six numeric covariate design columns (one confounded with group × stage and
injected into the features, five pure noise), a stage signal weakened to a
held-out CV AUROC of 0.69–0.70 and a nuisance the covariate-blind basis follows
(median |Spearman| 0.92), with three arms per unit on the same data and
permutation draws: covariates in the trajectory model only (adjusted, the
primary analysis), none (unadjusted, descriptive) and the stage latent
adjustment (latent_stage, the fallback). Its decision names
primary_validated | adopt_latent_stage | diagnose_configuration_excess
over the anchor and the translation control. The 2026-10-29 run (500 × 999 at
δ = 0.1 and 0.05, conjunction) returned diagnose_configuration_excess
(report): the adjusted model held
every statistic at δ = 0.05 and exceeded the 0.0695 bound on translation
delta at δ = 0.1 (0.072; delta 0.060–0.072 in every reading, 0.066 pooled),
and the stage adjustment exceeded at the anchor on angle (0.084–0.090) and
shape (0.078–0.092) at both strengths. At that configuration, read
covariate-adjusted delta p-values against a realized size of about 0.066, and
do not interpret stage-adjusted angle or shape rejections, until the
diagnosis the report names is done.
Diagnosis of that excess. scripts/case_study_diagnosis.py reran the same
units, with the committed adjusted and latent_stage p-values reproduced
exactly (0 mismatches over 6,000 per strength), under arms that separate the
candidate causes:
- on the covariate-blind basis, the confounded covariate estimated or its injection removed exactly, crossed with 0, 2 or 5 noise covariates;
- each of those rerun with the Freedman–Lane residuals rescaled by √(n / (n − p_red));
- the
stageadjustment at a forced rank of 2.
The 2026-10-30 run (report) returned two verdicts:
residual_df_shrinkagefor the adjusteddelta. RRPP's permuted residuals shrink with the reduced model's column count, so pooleddeltarises from 0.0545 to 0.066 between one and six covariate columns at n = 80. The corrected permutation holds every reading.residualized_basisfor thestageadjustment. It still exceeds on anchorangleat a fixed rank of 2 (0.084 / 0.082).
With many covariates at small n, read covariate-adjusted delta p-values against
that realized size until the corrected permutation is offered and validated
(roadmap, Next changes item 8).
Without the setting, every output is identical to MOTCO 0.8.0 except the
runtime, record["params"] included (tests/test_analysis_identity.py).
Example: SEA-AD-style design
Two blocks (RNA and ATAC donor pseudobulks), sex as the group, three ADNC stages:
motco analyze \
--block rna=rna_logcpm.csv --block atac=atac_logcpm.csv \
--metadata donors.csv --sample-col donor_id --group-col Sex --stage-col ADNC \
--stage-order "Not AD + Low,Intermediate,High" \
--permutations 999 --seed 20261015 \
--out-dir results/motco_mtg_astro
For the dimensionality sensitivity analysis, re-run with --forced-components 2,
3, … into separate output directories.
from motco.analysis import (
OmicsBlock, TrajectoryAnalysisParams, TrajectoryDataset,
analyze_trajectories, write_analysis_outputs,
)
dataset = TrajectoryDataset(
blocks=[OmicsBlock("rna", rna), OmicsBlock("atac", atac)],
metadata=donors,
sample_col="donor_id", group_col="Sex", stage_col="ADNC",
stage_order=["Not AD + Low", "Intermediate", "High"],
)
result = analyze_trajectories(dataset, TrajectoryAnalysisParams(permutations=999, seed=20261015))
write_analysis_outputs(result, "results/motco_mtg_astro")
API
motco.analysis
Real-data trajectory analysis: the validated MOTCO measurement on your own data.
:func:analyze_trajectories runs the production pipeline the simulation harness
characterizes — pooled per-feature standardization, a stage-supervised PLS-DA
latent space whose rank is chosen by double cross-validation, delta /
angle / shape between two groups in that space, and RRPP p-values — on
caller-supplied omic blocks and sample metadata. It calls the same cores as
:func:motco.simulations.evaluate_semisynthetic_trajectory (block scaling in
:mod:motco.simulations.preprocessing, :func:~motco.simulations.evaluation.fit_pls_latent_space,
the trajectory design and the record helpers), so the measurement exists once.
Two inputs are load-bearing and therefore explicit:
- Stage order. Net displacement runs from the first to the last declared
stage, and
shapeand the spectrum follow that order. It is never inferred by sorting labels. - Units. Each block declares its unit transform (
identityorbeta_to_mvalue). MOTCO does not normalize counts, filter features or impute values; blocks are analysed in the units supplied.
Declared covariates enter the trajectory model. By default the latent space is
built without them; TrajectoryAnalysisParams.covariate_latent_adjustment
("stage" or "group_stage") instead fits the basis on features
residualized on the covariates conditional on that design, and measures the
raw features in it.
:func:write_analysis_outputs writes the result as plain JSON/CSV (record,
latent scores, PLS loadings, latent stage means and, when requested, the
attribution tables) — the fitted estimator is never pickled.
TrajectoryAnalysisError
Bases: ValueError
Raised when real-data analysis inputs or parameters are invalid.
Source code in src/motco/analysis.py
101 102 | |
OmicsBlock
dataclass
One named omic block: a samples × features table and its unit transform.
Source code in src/motco/analysis.py
105 106 107 108 109 110 111 | |
TrajectoryDataset
dataclass
Aligned omic blocks plus sample metadata, validated on construction.
Every block's rows must equal metadata[sample_col] in order. The group
column must hold exactly two labels; stage_order must list every
observed stage label exactly once (labels are compared as strings), and
every group × stage cell must be observed.
covariate_cols names metadata columns that enter the trajectory model
additively, in declared order. A covariate is categorical when listed in
categorical_covariates or when its dtype is not numeric (booleans are
categorical); otherwise numeric. missing_covariates decides what a
missing covariate value does: "error" rejects it, "complete_case"
drops the sample from the metadata and every block before anything else is
validated or fitted (dropped_sample_ids lists them). Covariates are
never imputed.
Source code in src/motco/analysis.py
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |
groups
property
Group labels in analysis order (declared, else sorted as strings).
dropped_sample_ids
property
Samples removed by complete-case deletion (empty under "error").
covariate_design
property
The covariate design columns on the retained samples, or None without covariates.
TrajectoryAnalysisParams
dataclass
Measurement settings; the defaults are the simulation harness's.
forced_components fixes the latent rank (dimensionality sensitivity) and
skips cross-validation; None selects it by double CV. seed seeds
RRPP exactly as the harness does.
covariate_latent_adjustment (None, "stage" or
"group_stage") opts into covariate-aware latent construction: the
basis is fitted on features residualized on the declared covariates,
conditional on the stage or the group × stage indicators. It requires
declared covariates and is omitted from :meth:to_dict while None.
min_components is the rank floor of the cross-validated latent space
(default 2, so angle and shape are measured in at least two
dimensions). 1 restores the unfloored 0.9.0 rule and normalizes to
None, which is omitted from :meth:to_dict and from the record's
latent block, so a floor-1 analysis reproduces every 0.9.0 artifact.
A floor below 1 is rejected before any fitting. The floor guarantees two
dimensions, not a second axis with signal.
Source code in src/motco/analysis.py
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | |
resolved_min_components
property
The rank floor the cross-validation runs with (1 when omitted).
TrajectoryAnalysisResult
dataclass
The analysis record plus the fitted representation.
record is JSON-safe. latent_scores are the per-sample PLS scores,
pls_loadings the joint-feature rotations (block/feature columns
first), stage_means the fitted latent LS-mean vector per group × stage
in declared stage order, and attribution the full attribution result
when it was requested.
Source code in src/motco/analysis.py
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | |
analyze_trajectories(dataset, params=None)
Measure two groups' trajectories across ordered stages on real data.
Standardizes every block with pooled per-feature scalers (after its unit
transform), concatenates the blocks in declared order as
f"{block}__{feature}", builds the stage-supervised PLS-DA latent space
(double-CV rank, or params.forced_components), estimates delta,
angle (net displacement by default) and shape between the groups
in that space and, when params.permutations > 0, their RRPP p-values.
Records the selected rank, null summary, stage-mean spectrum, cell sizes,
block units and software versions beside the statistics. Optionally runs
frozen-model orientation attribution on the fitted estimator.
Declared covariates (dataset.covariate_cols) are appended additively to
the full (group × stage) and reduced (group + stage) trajectory models, so
RRPP permutes residuals of the reduced model with covariates. Every LS-mean
is evaluated at the pooled covariate mean; delta, angle and
shape do not depend on that reference. The latent space is fitted
without the covariates unless params.covariate_latent_adjustment is
set: then the pooled-standardized features are residualized on the
covariates conditional on the stage ("stage") or group × stage
("group_stage") indicators before the basis is fitted (per training set
inside the cross-validation, at the pooled scale), the raw features are
projected onto that basis, and the trajectory model, LS-means and RRPP are
unchanged. Attribution is not available with covariates.
Source code in src/motco/analysis.py
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | |
write_analysis_outputs(result, out_dir, *, overwrite=False)
Write the analysis artifact to out_dir and return the written paths.
Writes result.json, latent_scores.csv, pls_loadings.csv,
stage_means.csv and, when attribution ran, its tables under
attribution/. Refuses to touch a directory that already holds
result.json unless overwrite is set.
Source code in src/motco/analysis.py
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | |