Skip to main content

Cell-Cell Communication Analysis

The AdvancedCommunicationPipeline analyzes cell-cell communication patterns using ligand-receptor interaction databases and co-expression analysis.

Overview

This pipeline identifies:
  • Ligand-receptor pairs between cell types
  • Communication hub cells (key signaling centers)
  • Pathway activity scores
  • Cell type-specific communication patterns
1
Prerequisites
2
You need annotated data with cell type labels (from BasicPipeline or your own clustering):
3
import scanpy as sc

# Load annotated data
adata = sc.read_h5ad('results/basic/annotated_data.h5ad')

# Verify cell type annotations exist
print("Cell type columns:", [col for col in adata.obs.columns 
                            if col in ['leiden', 'cell_type', 'cluster']])
4
Install Communication Features (Optional)
5
For enhanced ligand-receptor database support:
6
pip install heartmap[communication]
7
Configure the Pipeline
8
from heartmap import Config

# Load configuration
config = Config.default()

# Communication-specific settings
config.analysis.use_liana = True  # Use LIANA database
config.update_paths('./communication_analysis')
config.create_directories()
9
Run Communication Analysis
10
from heartmap.pipelines import AdvancedCommunicationPipeline

# Initialize pipeline
pipeline = AdvancedCommunicationPipeline(config)

# Run on annotated data
results = pipeline.run(
    data_path='results/basic/annotated_data.h5ad',
    output_dir='results/communication'
)

print("Communication analysis completed!")
11
Explore Communication Scores
12
Examine cell type-to-cell type communication patterns:
13
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Extract communication scores
comm_scores = results['results']['communication_scores']

print(f"Found {len(comm_scores)} communication interactions")
print("\nTop 10 strongest interactions:")
top_interactions = comm_scores.nlargest(10, 'communication_score')
for _, row in top_interactions.iterrows():
    if 'ligand' in row:
        print(f"{row['source']}{row['target']}: "
              f"{row['ligand']}-{row['receptor']} "
              f"(score: {row['communication_score']:.3f})")
    else:
        print(f"{row['source']}{row['target']}: "
              f"{row['communication_score']:.3f}")
14
Identify Communication Hubs
15
Find cell types that act as major signaling centers:
16
# Extract hub scores
hub_scores = results['results']['hub_scores']
adata = results['adata']

# Calculate mean hub score per cell type
cluster_col = 'leiden'  # or 'cell_type'
hub_by_type = adata.obs.groupby(cluster_col)['hub_score'].agg(['mean', 'std'])
hub_by_type = hub_by_type.sort_values('mean', ascending=False)

print("\nCommunication Hub Scores:")
for cell_type, scores in hub_by_type.head(10).iterrows():
    print(f"Cluster {cell_type}: {scores['mean']:.4f} ± {scores['std']:.4f}")
17
Visualize Communication Networks
18
Create heatmaps and network visualizations:
19
import scanpy as sc

# Load pre-generated heatmap
from pathlib import Path
from matplotlib.image import imread

fig_path = Path('results/communication/figures/communication_heatmap.png')
if fig_path.exists():
    img = imread(fig_path)
    plt.figure(figsize=(12, 10))
    plt.imshow(img)
    plt.axis('off')
    plt.title('Cell-Cell Communication Heatmap')
    plt.show()

# Visualize hub scores on UMAP
sc.pl.umap(adata, color='hub_score', 
           cmap='viridis',
           title='Communication Hub Scores',
           save='_hub_scores.png')
20
Analyze Specific Pathways
21
Examine communication in specific biological pathways:
22
# Filter for specific ligand-receptor pairs
if 'ligand' in comm_scores.columns:
    # Example: VEGF signaling
    vegf_comm = comm_scores[
        comm_scores['ligand'].str.contains('VEGF', na=False) |
        comm_scores['receptor'].str.contains('FLT|KDR', na=False)
    ]
    
    print("\nVEGF Signaling:")
    for _, row in vegf_comm.iterrows():
        print(f"  {row['source']}{row['target']}: "
              f"{row['ligand']}-{row['receptor']}")
    
    # Create pivot table for heatmap
    if not vegf_comm.empty:
        pivot = vegf_comm.pivot_table(
            values='communication_score',
            index='source',
            columns='target',
            aggfunc='sum',
            fill_value=0
        )
        
        plt.figure(figsize=(10, 8))
        sns.heatmap(pivot, annot=True, fmt='.2f', cmap='Reds')
        plt.title('VEGF Signaling Network')
        plt.tight_layout()
        plt.savefig('results/communication/vegf_network.png', dpi=300)
23
Export Communication Data
24
# Save communication scores
comm_scores.to_csv(
    'results/communication/communication_scores.csv',
    index=False
)

# Save hub scores
hub_by_type.to_csv(
    'results/communication/hub_scores_by_type.csv'
)

print("Communication data exported!")

Complete Working Example

from heartmap import Config
from heartmap.pipelines import AdvancedCommunicationPipeline
import pandas as pd
import scanpy as sc
import seaborn as sns
import matplotlib.pyplot as plt

# Configure
config = Config.default()
config.analysis.use_liana = True
config.update_paths('./analysis')
config.create_directories()

# Run pipeline
print("=== Running Communication Analysis ===")
pipeline = AdvancedCommunicationPipeline(config)
results = pipeline.run(
    'results/basic/annotated_data.h5ad',
    'results/communication'
)

# Extract results
comm_scores = results['results']['communication_scores']
hub_scores = results['results']['hub_scores']
adata = results['adata']

# Analyze communication patterns
print(f"\nIdentified {len(comm_scores)} interactions")

if 'ligand' in comm_scores.columns:
    # Count unique L-R pairs
    n_pairs = comm_scores[['ligand', 'receptor']].drop_duplicates().shape[0]
    print(f"Using {n_pairs} unique ligand-receptor pairs")
    
    # Top communicating cell type pairs
    top_pairs = comm_scores.groupby(['source', 'target'])['communication_score'].sum()
    top_pairs = top_pairs.sort_values(ascending=False).head(10)
    
    print("\nTop 10 communicating cell type pairs:")
    for (source, target), score in top_pairs.items():
        print(f"  {source}{target}: {score:.3f}")

# Hub analysis
adata.obs['hub_score'] = hub_scores
hub_by_cluster = adata.obs.groupby('leiden')['hub_score'].mean().sort_values(ascending=False)

print("\nTop 5 Communication Hubs:")
for cluster, score in hub_by_cluster.head(5).items():
    n_cells = (adata.obs['leiden'] == cluster).sum()
    print(f"  Cluster {cluster}: score={score:.4f} ({n_cells} cells)")

# Visualize
sc.pl.umap(adata, color=['leiden', 'hub_score'], 
           ncols=2, save='_communication_overview.png')

print("\nAnalysis complete! Check results/communication/")

Understanding Communication Scores

The communication score is calculated based on ligand-receptor co-expression:
# Pseudocode for communication score calculation
# (actual implementation in AdvancedCommunicationPipeline)

for ligand, receptor in ligand_receptor_pairs:
    for source_type in cell_types:
        ligand_expr = mean_expression[source_type][ligand]
        
        if ligand_expr > threshold:
            for target_type in cell_types:
                receptor_expr = mean_expression[target_type][receptor]
                
                if receptor_expr > threshold:
                    # Geometric mean of expression levels
                    score = sqrt(ligand_expr * receptor_expr)
                    communication_scores.append({
                        'source': source_type,
                        'target': target_type,
                        'ligand': ligand,
                        'receptor': receptor,
                        'communication_score': score
                    })

Ligand-Receptor Database

The pipeline uses a curated database of ligand-receptor pairs:
from heartmap.data import get_ligand_receptor_pairs

# Get L-R pairs for your data
lr_pairs = get_ligand_receptor_pairs(
    adata,
    resource='consensus',  # or 'omnipath', 'cellphonedb'
    confidence_threshold=0.7  # Filter by confidence
)

print(f"Loaded {len(lr_pairs)} ligand-receptor pairs")
print("\nExample pairs:")
for ligand, receptor in lr_pairs[:5]:
    print(f"  {ligand}{receptor}")

Output Structure

results/communication/
├── figures/
│   ├── communication_heatmap.png    # Cell type communication matrix
│   ├── hub_scores.png               # Hub scores on UMAP
│   └── pathway_scores.png           # Pathway activity (if computed)
└── tables/
    ├── communication_scores.csv     # All L-R interactions
    └── hub_scores_by_type.csv       # Hub scores per cell type

Advanced Options

resource
str
default:"consensus"
Ligand-receptor database: consensus, omnipath, cellphonedb, cellchatdb
confidence_threshold
float
default:"0.7"
Minimum confidence score for L-R pairs (0.0-1.0)
expression_threshold
float
default:"0.1"
Minimum mean expression to consider a gene as “expressed”

Best Practices

Input Data Quality

  • Use well-annotated data with clear cell type labels
  • Ensure sufficient cells per type (>50 recommended)
  • Normalize data before analysis

Interpretation

  • High hub scores indicate cells central to communication
  • Focus on biologically relevant L-R pairs for your tissue
  • Validate top interactions with literature

Performance

  • Analysis scales with number of L-R pairs tested
  • Use confidence_threshold to reduce computation
  • Consider filtering for tissue-specific interactions

Next Steps

Multi-Chamber

Chamber-specific communication

Visualization

Advanced plotting options

API Reference

Full API documentation

Build docs developers (and LLMs) love