Integration Module

Integration Module for DRIADA

This module provides components that integrate different parts of DRIADA, bridging single-neuron analysis (INTENSE) with population-level analysis.

Bridge between single-neuron selectivity analysis (INTENSE) and population-level dimensionality reduction, enabling integrated analysis of neural data.

Main Functions

driada.integration.manifold_analysis.get_functional_organization(experiment, method_name, data_type='calcium', intense_results=None)[source]

Analyze functional organization in the manifold.

Examines how neurons contribute to different embedding components and identifies functional clusters based on selectivity patterns.

Parameters:
  • experiment (Experiment) – Experiment object with stored embeddings.

  • method_name (str) – Name of the embedding method to analyze.

  • data_type (str, optional) – Data type used for embedding (‘calcium’ or ‘spikes’). Default is ‘calcium’.

  • intense_results (IntenseResults, optional) – IntenseResults object from compute_embedding_selectivity for this specific embedding method. Must be an instance of driada.intense.intense_base.IntenseResults. If not provided, only basic statistics (component importance) will be returned.

Returns:

Dictionary containing: - ‘component_importance’: Variance explained by each component - ‘n_components’: Number of embedding components - ‘n_neurons_used’: Number of neurons in the embedding - ‘neuron_indices’: Indices of neurons used

If intense_results provided, also includes: - ‘neuron_participation’: How many components each neuron contributes to - ‘component_specialization’: How selective each component is - ‘functional_clusters’: Groups of neurons with similar embedding selectivity - ‘n_participating_neurons’: Number of neurons with selectivity - ‘mean_components_per_neuron’: Average participation per neuron

Return type:

dict

Raises:
  • KeyError – If the specified embedding method is not found.

  • ValueError – If component variances sum to zero.

  • TypeError – If intense_results is not an IntenseResults object when provided.

  • ValueError – If intense_results lacks the required ‘significance’ attribute.

Notes

This function reads embedding data from the experiment’s stored embeddings. When intense_results is provided, it performs detailed selectivity analysis to identify functional clusters and neuron participation patterns.

Examples

Basic usage without selectivity analysis:

>>> # Create a simple synthetic experiment with circular manifold
>>> import numpy as np
>>> from driada.experiment.synthetic import generate_circular_manifold_exp
>>> np.random.seed(42)
>>>
>>> # Generate experiment with head direction cells
>>> exp = generate_circular_manifold_exp(
...     n_neurons=20,
...     duration=30,  # Short duration for example
...     fps=10.0,
...     kappa=4.0,  # Moderate tuning width
...     verbose=False
... )
>>>
>>> # Create PCA embedding (automatically stores it)
>>> embedding = exp.create_embedding('pca', n_components=5, verbose=False)
>>>
>>> # Basic analysis without selectivity (just component importance)
>>> org_basic = get_functional_organization(exp, 'pca')
>>> print(f"Number of components: {org_basic['n_components']}")
Number of components: 5
>>> print(f"Component importance shape: {org_basic['component_importance'].shape}")
Component importance shape: (5,)
>>> print(f"Neurons used: {org_basic['n_neurons_used']}")
Neurons used: 20

Advanced usage with selectivity analysis (intensive computation):

>>> # The following example shows how to use with selectivity analysis
>>> # Note: This requires intensive computation and is skipped in doctests
>>> from driada.intense import compute_embedding_selectivity  
>>>
>>> # For real analysis, use longer experiments:
>>> exp_long = generate_circular_manifold_exp(  
...     n_neurons=50, duration=300, verbose=False)
>>>
>>> # Compute PCA embedding
>>> exp_long.create_embedding('pca', n_components=5, verbose=False)  
>>>
>>> # Compute selectivity with full parameters
>>> results = compute_embedding_selectivity(  
...     exp_long,
...     embedding_methods='pca',
...     n_shuffles_stage1=100,
...     n_shuffles_stage2=500,
...     mode='two_stage',
...     verbose=False
... )
>>>
>>> # Extract the IntenseResults object
>>> intense_res = results['pca']['intense_results']  
>>>
>>> # Full functional organization analysis with selectivity
>>> org_full = get_functional_organization(  
...     exp_long, 'pca', intense_results=intense_res)
>>>
>>> # Access detailed selectivity information
>>> print(f"Participating neurons: {org_full['n_participating_neurons']}")  
>>> print(f"Mean components per neuron: {org_full['mean_components_per_neuron']:.2f}")  
>>> print(f"Number of functional clusters: {len(org_full['functional_clusters'])}")  

See also

compare_embeddings

Compare multiple embedding methods

compute_embedding_selectivity

Compute selectivity for embeddings

driada.integration.manifold_analysis.compare_embeddings(experiment, method_names, data_type='calcium', intense_results_dict=None)[source]

Compare functional organization across different embedding methods.

Analyzes and compares how different dimensionality reduction methods organize the neural population, including neuron participation overlap and clustering patterns.

Parameters:
  • experiment (Experiment) – Experiment object with stored embeddings.

  • method_names (list of str) – List of embedding method names to compare.

  • data_type (str, optional) – Data type used for embeddings (‘calcium’ or ‘spikes’). Default is ‘calcium’.

  • intense_results_dict (dict, optional) – Dict mapping method names to IntenseResults objects (not the full compute_embedding_selectivity output). Each value must be an instance of driada.intense.intense_base.IntenseResults. If not provided, only basic comparison metrics will be returned.

Returns:

Comparison metrics including: - ‘methods’: List of valid methods analyzed - ‘n_components’: Number of components per method - ‘n_participating_neurons’: Neurons with selectivity per method - ‘mean_components_per_neuron’: Average participation per method - ‘n_functional_clusters’: Number of clusters per method - ‘participation_overlap’: Pairwise overlap between methods

Return type:

dict

Raises:
  • ValueError – If no valid embeddings found to compare or method_names is empty.

  • TypeError – If method_names is not a list or intense_results_dict contains non-IntenseResults values.

Notes

This function logs warnings when embeddings are not found for requested methods. When only one valid embedding is found, it returns statistics for that single embedding without computing overlaps.

Examples

Basic comparison without selectivity:

>>> # Create a simple synthetic experiment for comparison
>>> import numpy as np
>>> from driada.experiment.synthetic import generate_circular_manifold_exp
>>> np.random.seed(42)
>>>
>>> # Generate experiment with 20 neurons, 500 frames
>>> exp = generate_circular_manifold_exp(
...     n_neurons=20,
...     duration=50,  # 50 seconds at 10 fps = 500 frames
...     fps=10.0,
...     kappa=4.0,  # Moderate tuning width
...     verbose=False
... )
>>>
>>> # Create PCA embedding
>>> pca_embedding = exp.create_embedding('pca', n_components=3, verbose=False)
>>>
>>> # Create t-SNE embedding
>>> tsne_embedding = exp.create_embedding('tsne', n_components=3,
...                                       perplexity=10, random_state=42)
>>>
>>> # Basic comparison without selectivity
>>> comparison_basic = compare_embeddings(exp, ['pca', 'tsne'])
>>> print(f"Methods compared: {sorted(comparison_basic['methods'])}")
Methods compared: ['pca', 'tsne']
>>> print(f"Components: PCA={comparison_basic['n_components']['pca']}, "
...       f"t-SNE={comparison_basic['n_components']['tsne']}")
Components: PCA=3, t-SNE=3
>>> print(f"Mean components per neuron (no selectivity): "
...       f"PCA={comparison_basic['mean_components_per_neuron']['pca']}, "
...       f"t-SNE={comparison_basic['mean_components_per_neuron']['tsne']}")
Mean components per neuron (no selectivity): PCA=0, t-SNE=0

Advanced comparison with selectivity analysis:

>>> # The following example shows comparison with selectivity analysis
>>> # Note: This requires intensive computation and is skipped in doctests
>>> from driada.intense import compute_embedding_selectivity  
>>>
>>> # Compute selectivity for both methods
>>> results = compute_embedding_selectivity(  
...     exp,
...     embedding_methods=['pca', 'tsne'],
...     n_shuffles_stage1=100,
...     n_shuffles_stage2=500,
...     mode='two_stage',
...     verbose=False
... )
>>>
>>> # Extract IntenseResults objects (not the full dict)
>>> intense_dict = {  
...     method: results[method]['intense_results']
...     for method in ['pca', 'tsne']
... }
>>>
>>> # Full comparison with selectivity
>>> comparison_full = compare_embeddings(  
...     exp, ['pca', 'tsne'],
...     intense_results_dict=intense_dict
... )
>>>
>>> # Access detailed comparison metrics
>>> print(f"Participating neurons: PCA={comparison_full['n_participating_neurons']['pca']}, "  
...       f"t-SNE={comparison_full['n_participating_neurons']['tsne']}")
>>> print(f"Participation overlap: {comparison_full['participation_overlap']['pca_vs_tsne']:.2f}")  

Error handling:

>>> # Test error handling
>>> try:
...     compare_embeddings(exp, [])  # Empty list
... except ValueError as e:
...     print(f"Error: {str(e)}")
Error: method_names cannot be empty
>>>
>>> # Test with non-existent embedding (requesting a method not computed)
>>> comparison_missing = compare_embeddings(exp, ['pca', 'umap'])  # umap not computed
>>> print(f"Valid methods found: {sorted(comparison_missing['methods'])}")
Valid methods found: ['pca']

See also

get_functional_organization

Analyze individual embeddings

compute_embedding_selectivity

Compute selectivity for embeddings

Usage Example

from driada.integration import get_functional_organization, compare_embeddings
from driada.intense import compute_cell_feat_significance
from driada.experiment import load_demo_experiment

# Load sample experiment
exp = load_demo_experiment()

# First, run INTENSE analysis
stats, sig, info, intense_results = compute_cell_feat_significance(
    exp,
    find_optimal_delays=False  # Skip temporal alignment for demo
)

# Then create and store embeddings
pca_array = exp.create_embedding('pca', n_components=3)
umap_array = exp.create_embedding('umap', n_components=2)

# Analyze functional organization in PCA space
pca_org = get_functional_organization(
    exp,
    'pca',
    intense_results=intense_results
)

# Compare multiple embeddings
comparison = compare_embeddings(
    exp,
    ['pca', 'umap'],
    intense_results_dict={
        'pca': intense_results,
        'umap': intense_results
    }
)

print(f"Component importance: {pca_org['component_importance']}")
print(f"PCA vs UMAP overlap: {comparison['participation_overlap']['pca_vs_umap']:.3f}")