brain_deer.plugins.laminosaurus.analysis¶
Core layer-fMRI analysis helpers for Laminosaurus.
Classes¶
Whole-volume Fisher z(r_vs_sup) − z(r_vs_deep) using ROI superficial/deep layer-mean references. |
|
Pearson r between each layer mean TS in ROI A and each layer mean TS in ROI B (4-D data). |
|
Two condition-specific inter-ROI laminar FC maps plus aligned delta_r (e.g. left vs right tapping blocks). |
|
Huber-style orthogonal superficial/deep composites per ROI, then cross-ROI correlations and depth profiles. |
|
2×2 block means over laminar pairs: rows = ROI A bin, columns = ROI B bin. |
|
Correlations of ROI superficial vs deep laminar reference time series with each column mean TS. |
|
Pairwise Pearson correlation between column-based time series with multiple-testing control. |
Functions¶
|
Map layer label to 0 = L1–split (upper), 1 = split+1–10 (lower). Labels outside 1–10 are excluded. |
Mean value in each quadrant: A-upper×B-upper, A-upper×B-lower, … using only finite matrix cells. |
|
|
Keep only one slice from a 3-D ROI mask. |
|
Union mask of all voxels whose column label is in |
|
Create a mask from the column label under the current voxel. |
|
Compute a layer profile inside an ROI. |
|
Summarize per-column layer measurements inside the ROI. |
|
Build a layer-by-column matrix inside an ROI. |
Pairwise Pearson correlations between column (or sup/deep) mean time series with MC correction. |
|
Voxelwise Fisher z(r(voxel, T_sup)) − z(r(voxel, T_deep)) over the 4-D volume. |
|
|
Map BIDS |
One numpy array of volume indices per events row (block), in onset order. |
|
|
Split-half reliability: odd vs even event blocks (same condition), correlate upper triangles of r. |
Randomly reassign whole event blocks to pseudo conditions; null for mean(abs(delta_r)) laminar matrix. |
|
|
Dual regression residuals (Huber-style unique laminar components). |
|
Mean BOLD time course per cortical layer label inside |
Like two |
|
Full within-ROI layer × layer correlation matrix (Huber et al. 2017 Fig. 5 style). |
|
|
Symmetric Pearson r matrix between rows (each row = one layer time series). |
|
Split sorted layer IDs into (superficial, deep) groups. |
ROI-mean superficial vs deep composite TS, then mutual orthogonalization. |
|
Same as |
|
Pearson r between layer-mean time series in ROI A vs ROI B (4-D data). |
|
Inter-ROI laminar FC from precomputed layer-mean time series (rows = layers, cols = TRs). |
|
Orthogonal sup/deep composites in each ROI, then 4×4 cross-correlations and laminar profiles. |
|
Two inter-ROI laminar FC maps on disjoint TR subsets plus aligned delta_r matrix. |
|
Two ROI reference time series (superficial vs deep layer thirds) vs each column mean TS. |
|
|
Compute layer-by-layer timeseries correlations inside the ROI. |
|
Compute time-resolved laminar dynamics inside the ROI. |
Compute a whole-volume seed connectivity map and an ROI-restricted laminar summary. |
|
|
Compare two functional volumes over the same layered ROI. |
|
Generate QC metrics for an ROI-based laminar analysis. |
|
Subject-level control / QC metrics from layer + functional data (no external motion file). |
Module Contents¶
- class brain_deer.plugins.laminosaurus.analysis.LaminarVoxelPreferenceResult¶
Whole-volume Fisher z(r_vs_sup) − z(r_vs_deep) using ROI superficial/deep layer-mean references.
- class brain_deer.plugins.laminosaurus.analysis.InterRoiLayerConnectivityResult¶
Pearson r between each layer mean TS in ROI A and each layer mean TS in ROI B (4-D data).
- class brain_deer.plugins.laminosaurus.analysis.InterRoiTaskComparisonResult¶
Two condition-specific inter-ROI laminar FC maps plus aligned delta_r (e.g. left vs right tapping blocks).
- class brain_deer.plugins.laminosaurus.analysis.OrthogonalSupDeepCrossRoiResult¶
Huber-style orthogonal superficial/deep composites per ROI, then cross-ROI correlations and depth profiles.
Composites are ROI-mean BOLD over superficial vs deep layer bins, then
mutual_orthogonalize_timeseries()within each ROI. Cross-correlations use the four orthogonalized time series. Depth profiles correlate each layer-mean time series in the target ROI with the partner’s orthogonalized superficial and deep composites (Huber et al. 2017-style laminar FC readout).
- class brain_deer.plugins.laminosaurus.analysis.InterRoiDepthBinSummary¶
2×2 block means over laminar pairs: rows = ROI A bin, columns = ROI B bin.
- brain_deer.plugins.laminosaurus.analysis.depth_bin_index(layer_label: int, *, split_layer: int = INTER_ROI_DEPTH_SPLIT_LAYER) int | None¶
Map layer label to 0 = L1–split (upper), 1 = split+1–10 (lower). Labels outside 1–10 are excluded.
- brain_deer.plugins.laminosaurus.analysis.aggregate_inter_roi_depth_bins(matrix: numpy.ndarray, layer_labels_a: list[int], layer_labels_b: list[int], *, split_layer: int = INTER_ROI_DEPTH_SPLIT_LAYER, value_name: str = 'r') InterRoiDepthBinSummary | None¶
Mean value in each quadrant: A-upper×B-upper, A-upper×B-lower, … using only finite matrix cells.
- class brain_deer.plugins.laminosaurus.analysis.LaminarSeedTargetResult¶
Correlations of ROI superficial vs deep laminar reference time series with each column mean TS.
- class brain_deer.plugins.laminosaurus.analysis.ColumnColumnConnectivityResult¶
Pairwise Pearson correlation between column-based time series with multiple-testing control.
- brain_deer.plugins.laminosaurus.analysis.slice_mask(mask: numpy.ndarray, axis: int, index: int) numpy.ndarray¶
Keep only one slice from a 3-D ROI mask.
- brain_deer.plugins.laminosaurus.analysis.mask_from_column_labels(column_volume: numpy.ndarray, labels: Iterable[int], *, restrict_to_layer_positive: numpy.ndarray | None = None) numpy.ndarray¶
Union mask of all voxels whose column label is in
labels.If
restrict_to_layer_positiveis set (same 3-D shape ascolumn_volume), only voxels with layer value > 0 are included (typical cortical mask).
- brain_deer.plugins.laminosaurus.analysis.build_column_mask(column_data: numpy.ndarray, voxel: tuple[int, int, int]) tuple[numpy.ndarray, int | None]¶
Create a mask from the column label under the current voxel.
- brain_deer.plugins.laminosaurus.analysis.compute_layer_profile(functional_volume: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, reduction: str = 'mean', normalize: str = 'none', positive_only: bool = False, reverse_order: bool = False, column_volume: numpy.ndarray | None = None, upsample_factor: int = 1, smoothing_radius: int = 0, anchor_zero_endpoints: bool = True) LayerProfileResult¶
Compute a layer profile inside an ROI.
- brain_deer.plugins.laminosaurus.analysis.compute_column_summary(functional_volume: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, column_volume: numpy.ndarray | None, reduction: str, positive_only: bool, reverse_order: bool, anchor_zero_endpoints: bool = True) dict[str, Any]¶
Summarize per-column layer measurements inside the ROI.
- brain_deer.plugins.laminosaurus.analysis.compute_column_profiles(functional_volume: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, column_volume: numpy.ndarray | None, reduction: str = 'mean', normalize: str = 'minmax', positive_only: bool = False, reverse_order: bool = False, max_columns: int = 96, anchor_zero_endpoints: bool = True) ColumnExplorerResult | None¶
Build a layer-by-column matrix inside an ROI.
- brain_deer.plugins.laminosaurus.analysis.compute_column_column_connectivity(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, column_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, node_mode: str = 'sup_deep', reverse_order: bool = False, correction: str = 'fdr_bh', alpha: float = 0.05) ColumnColumnConnectivityResult | None¶
Pairwise Pearson correlations between column (or sup/deep) mean time series with MC correction.
node_modeis eithercolumn_mean(one node per column) orsup_deep(two nodes per column: superficial third vs deep third of layer labels).Off-diagonal p-values are adjusted with
correction(fdr_bh,bonferroni,holm, ornone). Significance usesalphaon adjusted p-values (two-sided Pearson tests, df = T-2).
- brain_deer.plugins.laminosaurus.analysis.compute_laminar_voxel_preference_map(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, reverse_order: bool = False, chunk_size: int = 50000, target_mask: numpy.ndarray | None = None) LaminarVoxelPreferenceResult | None¶
Voxelwise Fisher z(r(voxel, T_sup)) − z(r(voxel, T_deep)) over the 4-D volume.
T_supandT_deepare ROI mean time series over the upper / lower third of layer labels inroi_mask. Each voxel’s time series is correlated with both references (Pearson on centered data). Iftarget_maskis set (same 3-D shape), only those voxels are computed and written; elsewhere stays NaN — the UI passeslayer_volume > 0so work scales with cortical coverage, not full grid size. UseNoneto fill the entire grid (slow on large volumes).
- brain_deer.plugins.laminosaurus.analysis.volume_indices_from_bids_events(events_path: str | pathlib.Path, *, tr: float, n_volumes: int, trial_type_label_1: str, trial_type_label_2: str) tuple[numpy.ndarray, numpy.ndarray] | None¶
Map BIDS
*_events.tsvrows to volume indices for twotrial_typevalues.Uses TR-sliced volumes [k·TR, (k+1)·TR) overlapping each event [onset, onset+duration). Matching is case-insensitive on
trial_type/stimulus_type/trial_type.
- brain_deer.plugins.laminosaurus.analysis.volume_block_lists_from_bids_events(events_path: str | pathlib.Path, *, tr: float, n_volumes: int, trial_type_label_1: str, trial_type_label_2: str) tuple[list[numpy.ndarray], list[numpy.ndarray]] | None¶
One numpy array of volume indices per events row (block), in onset order.
Pausen zwischen Blöcken entstehen automatisch, weil nur Volumina gezählt werden, die mit der jeweiligen Event-Zeile überlappen — nicht aufeinanderfolgende TRs werden nicht in denselben Block gezwungen.
- brain_deer.plugins.laminosaurus.analysis.inter_roi_fc_split_half_block_reliability(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask_a: numpy.ndarray, roi_mask_b: numpy.ndarray, blocks: list[numpy.ndarray], *, name_a: str = 'ROI A', name_b: str = 'ROI B', reverse_order: bool = False, exclude_overlap: bool = True, partial_correlation: bool = False, extra_nuisance: numpy.ndarray | None = None) dict[str, Any]¶
Split-half reliability: odd vs even event blocks (same condition), correlate upper triangles of r.
- brain_deer.plugins.laminosaurus.analysis.inter_roi_task_block_permutation_mean_abs_delta_r(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask_a: numpy.ndarray, roi_mask_b: numpy.ndarray, blocks_1: list[numpy.ndarray], blocks_2: list[numpy.ndarray], n_perm: int, *, label_1: str, label_2: str, name_a: str = 'ROI A', name_b: str = 'ROI B', reverse_order: bool = False, exclude_overlap: bool = True, partial_correlation: bool = False, extra_nuisance: numpy.ndarray | None = None, seed: int | None = None) dict[str, Any]¶
Randomly reassign whole event blocks to pseudo conditions; null for mean(abs(delta_r)) laminar matrix.
- brain_deer.plugins.laminosaurus.analysis.mutual_orthogonalize_timeseries(ts_a: numpy.ndarray, ts_b: numpy.ndarray) tuple[numpy.ndarray, numpy.ndarray]¶
Dual regression residuals (Huber-style unique laminar components).
ts_a_orthists_aafter removing linear fit tots_b(+ intercept);ts_b_orthsymmetrically. Matches the common laminar-fMRI practice cited in Huber et al. (2017) Neuron (superficial vs deep seeds sharing variance).
- brain_deer.plugins.laminosaurus.analysis.layerwise_mean_timeseries(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, layer_labels: Iterable[int], *, time_indices: numpy.ndarray | None = None) tuple[numpy.ndarray, list[int]]¶
Mean BOLD time course per cortical layer label inside
roi_mask.Returns
(matrix, labels)withmatrixshape(len(labels), n_time)— each row is one layer’s ROI-mean over voxels with that label (only voxels inroi_mask).
- brain_deer.plugins.laminosaurus.analysis.layerwise_mean_timeseries_two_rois(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask_a: numpy.ndarray, layer_labels_a: Iterable[int], roi_mask_b: numpy.ndarray, layer_labels_b: Iterable[int], *, time_indices: numpy.ndarray | None = None) tuple[numpy.ndarray, list[int], numpy.ndarray, list[int]]¶
Like two
layerwise_mean_timeseries()calls, but one 3-D crop and one TR loop.
- brain_deer.plugins.laminosaurus.analysis.within_roi_layer_correlation_matrix(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, time_indices: numpy.ndarray | None = None, layer_labels: Iterable[int] | None = None) tuple[numpy.ndarray, list[int]]¶
Full within-ROI layer × layer correlation matrix (Huber et al. 2017 Fig. 5 style).
Each matrix entry is Pearson r between ROI-mean layer time series. Rows/columns follow increasing
layer_labels(defaults to positive integers present underroi_mask).
- brain_deer.plugins.laminosaurus.analysis.layer_correlation_matrix_from_timeseries(ts_matrix: numpy.ndarray) numpy.ndarray¶
Symmetric Pearson r matrix between rows (each row = one layer time series).
- brain_deer.plugins.laminosaurus.analysis.split_layer_labels_superficial_deep(layer_labels: Iterable[int], *, superficial: str = 'upper_numeric') tuple[list[int], list[int]]¶
Split sorted layer IDs into (superficial, deep) groups.
superficial='upper_numeric'(default): higher label IDs → superficial (pial), lower IDs → deep (white-matter–proximate), for equidistant laminar bins 1…N.lower_numericinverts that mapping (use only if your atlas encodes pial with lower numbers). The choice swaps composite time courses and the entire Huber-style 4×4.
- brain_deer.plugins.laminosaurus.analysis.huber_style_orthogonalized_sup_deep_composites(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, superficial_labels: Iterable[int], deep_labels: Iterable[int], time_indices: numpy.ndarray | None = None) tuple[numpy.ndarray, numpy.ndarray, dict[str, Any]]¶
ROI-mean superficial vs deep composite TS, then mutual orthogonalization.
Returns
(ts_sup_orth, ts_deep_orth, metrics)with scalarr_raw/r_orth_between_composites.
- brain_deer.plugins.laminosaurus.analysis.huber_style_orthogonalized_sup_deep_from_ts_matrix(ts_matrix: numpy.ndarray, layer_labels_order: list[int], *, superficial_labels: Iterable[int], deep_labels: Iterable[int]) tuple[numpy.ndarray, numpy.ndarray, dict[str, Any]]¶
Same as
huber_style_orthogonalized_sup_deep_composites()but from a precomputed TS matrix.ts_matrixrows align withlayer_labels_order(one row per layer mean time course).
- brain_deer.plugins.laminosaurus.analysis.compute_inter_roi_layer_connectivity(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask_a: numpy.ndarray, roi_mask_b: numpy.ndarray, *, name_a: str = 'ROI A', name_b: str = 'ROI B', reverse_order: bool = False, exclude_overlap: bool = True, time_indices: numpy.ndarray | None = None, partial_correlation: bool = False, extra_nuisance: numpy.ndarray | None = None) InterRoiLayerConnectivityResult | None¶
Pearson r between layer-mean time series in ROI A vs ROI B (4-D data).
For each distinct layer label in A (and B), the mean 4-D time course over voxels with that label in the ROI is correlated with every layer mean in the other ROI. If
exclude_overlapis True, voxels belonging to both masks are removed from both sides so the same tissue does not drive both time series.If
time_indicesis set (1-D int, subset of0..T-1), correlations use only those TRs (e.g. task blocks from a BIDS events file).If
partial_correlationis True, each pair is computed on residuals after regressing both time series on [intercept, cortical mean BOLD] (mean overlayer_volume > 0per TR inside a tight 3-D crop of cortex ∪ ROI A ∪ ROI B; plusextra_nuisancecolumns if given). This reduces shared variance from widespread fluctuations without reading the entire FOV each TR.extra_nuisancemust have shape(n_TR_full, K)along the full functional run; it is subset withtime_indiceswhen those are used.
- brain_deer.plugins.laminosaurus.analysis.inter_roi_layer_connectivity_from_timeseries(ts_rows_a: numpy.ndarray, ts_rows_b: numpy.ndarray, layer_labels_a: list[int], layer_labels_b: list[int], *, name_a: str = 'ROI A', name_b: str = 'ROI B') InterRoiLayerConnectivityResult | None¶
Inter-ROI laminar FC from precomputed layer-mean time series (rows = layers, cols = TRs).
- brain_deer.plugins.laminosaurus.analysis.compute_orthogonal_sup_deep_cross_roi(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask_a: numpy.ndarray, roi_mask_b: numpy.ndarray, *, name_a: str = 'ROI A', name_b: str = 'ROI B', view_label: str = 'full', exclude_overlap: bool = True, time_indices: numpy.ndarray | None = None, partial_correlation: bool = False, superficial_mode: str = 'upper_numeric') OrthogonalSupDeepCrossRoiResult | None¶
Orthogonal sup/deep composites in each ROI, then 4×4 cross-correlations and laminar profiles.
superficial_modeis passed tosplit_layer_labels_superficial_deep()(upper_numericvslower_numeric). Ifpartial_correlationis True, each layer-mean time series is residualized w.r.t. [intercept, cortical mean BOLD] (layer_volume > 0, tight crop per TR) before composites, matching the fast partial regressor used for inter-ROI FC.
- brain_deer.plugins.laminosaurus.analysis.compute_inter_roi_task_comparison(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask_a: numpy.ndarray, roi_mask_b: numpy.ndarray, indices_1: numpy.ndarray, indices_2: numpy.ndarray, *, label_1: str, label_2: str, name_a: str = 'ROI A', name_b: str = 'ROI B', reverse_order: bool = False, exclude_overlap: bool = True, partial_correlation: bool = False, extra_nuisance: numpy.ndarray | None = None) InterRoiTaskComparisonResult | None¶
Two inter-ROI laminar FC maps on disjoint TR subsets plus aligned delta_r matrix.
- brain_deer.plugins.laminosaurus.analysis.compute_laminar_seed_target_preference(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, column_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, reverse_order: bool = False, max_columns: int = 96) LaminarSeedTargetResult | None¶
Two ROI reference time series (superficial vs deep layer thirds) vs each column mean TS.
For each cortical column overlapping the ROI, the target time series is the mean 4-D signal over voxels with that column label and positive layer (same convention as column-mean nodes). Reference
T_sup/T_deepare ROI-wide means over the upper / lower third of layer labels (matchingcompute_column_column_connectivitysup_deepsplit).z_diffis Fisher z(r_sup) − Fisher z(r_deep); positive values favour coupling to the superficial laminar reference.
- brain_deer.plugins.laminosaurus.analysis.compute_layer_connectivity(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, reverse_order: bool = False) ConnectivityResult | None¶
Compute layer-by-layer timeseries correlations inside the ROI.
- brain_deer.plugins.laminosaurus.analysis.compute_layer_dynamics(functional_4d: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, reverse_order: bool = False, positive_only: bool = False) DynamicsResult | None¶
Compute time-resolved laminar dynamics inside the ROI.
- brain_deer.plugins.laminosaurus.analysis.compute_seed_connectivity_map(functional_4d: numpy.ndarray, seed_mask: numpy.ndarray, layer_volume: numpy.ndarray, *, column_volume: numpy.ndarray | None = None, reverse_order: bool = False, chunk_size: int = 50000, anchor_zero_endpoints: bool = True) SeedConnectivityResult | None¶
Compute a whole-volume seed connectivity map and an ROI-restricted laminar summary.
- brain_deer.plugins.laminosaurus.analysis.compute_profile_comparison(primary_volume: numpy.ndarray, secondary_volume: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, primary_name: str, secondary_name: str, reduction: str = 'mean', positive_only: bool = False, reverse_order: bool = False, anchor_zero_endpoints: bool = True) ProfileComparisonResult¶
Compare two functional volumes over the same layered ROI.
- brain_deer.plugins.laminosaurus.analysis.compute_qc_dashboard(functional_volume: numpy.ndarray, layer_volume: numpy.ndarray, roi_mask: numpy.ndarray, *, column_volume: numpy.ndarray | None = None, profile_result: LayerProfileResult | None = None) dict[str, Any]¶
Generate QC metrics for an ROI-based laminar analysis.
- brain_deer.plugins.laminosaurus.analysis.compute_control_metrics(layer_volume: numpy.ndarray, *, functional_3d: numpy.ndarray | None = None, functional_4d: numpy.ndarray | None = None, roi_mask: numpy.ndarray | None = None, column_volume: numpy.ndarray | None = None, max_voxels_tsnr_sample: int = 25000) dict[str, Any]¶
Subject-level control / QC metrics from layer + functional data (no external motion file).
Intended for PoC documentation per participant: cortical coverage, global temporal stability, optional ROI overlap, optional column map coverage. Motion (FD, DVARS from confounds.tsv) should still be taken from the preprocessing pipeline when available.