Single-cell TCR-seq Analysis
Joint gene expression and TCR clonotype analysis for metastatic samples
What it does
This workflow links single-cell gene expression data with T-cell receptor sequencing annotations to study clonal expansion and repertoire structure across primary tumor and lymph node metastasis samples. The committed materials combine a short README with a Python notebook built around scanpy, muon, and scirpy.
When to use it
Use this workflow when gene expression and 10x VDJ outputs need to be analyzed together at the cell level, especially for questions about clonotype structure, receptor pairing, and clonal expansion across conditions. It is a downstream immune-repertoire branch rather than a full preprocessing pipeline.
Prerequisites
- Source folder:
scTCRseq_analysis - Main files:
- Required tools listed in the README:
scanpyanndatamuonscirpyscipypandasmatplotlib
- Expected inputs:
- 10x VDJ
filtered_contig_annotations.csvfiles - processed gene-expression matrix files for the matched scRNA-seq data
- 10x VDJ
Steps
Load the paired TCR and gene-expression inputs
The notebook begins with a Python analysis stack for single-cell and immune-repertoire analysis, then defines file paths for multiple patients and matched tumor versus lymph node metastasis samples.
import scanpy as sc
import muon as mu
import scirpy as ir
import pandas as pd
from scipy.io import mmreadtcr_paths = [
"/fs/ess/PAS1475/Maoteng/Metastasis_new/GSE167036/TCR/PT_1_tumor_VDJ/SRR13737401_vdj/outs/filtered_contig_annotations.csv",
"/fs/ess/PAS1475/Maoteng/Metastasis_new/GSE167036/TCR/PT_1_LNM_VDJ/SRR13737409_vdj/outs/filtered_contig_annotations.csv",
...
]The README frames the output as a MuData object with a gene-expression component (gex) and an immune-repertoire component (airr).
Summarize sample composition and prepare clonotype metadata
One committed notebook section tallies tumor and LNM cell counts per patient and calculates proportions for each sample pair. This makes the cohort balance explicit before repertoire-level interpretation begins.
counts = Counter(mdata.obs["label"])
patients = ['PT_1', 'PT_3', 'PT_5', 'PT_6', 'PT_7', 'PT_8']
counts_df = pd.DataFrame(data, columns=['Patient', 'Tumor_Count', 'LNM_Count'])
counts_df['Tumor_Proportion'] = (counts_df['Tumor_Count'] / (counts_df['Tumor_Count'] + counts_df['LNM_Count'])).round(3)Run immune-receptor QC, distance calculation, and clonotype definition
The main repertoire-analysis block derives patient and location metadata, computes a gene-expression UMAP, indexes receptor chains, and then uses scirpy to calculate receptor distances and define clonotype clusters.
mdata.obs["patient_id"] = mdata.obs["label"].str.replace('_', '', n=1).str.split('_').str[0]
mdata.obs["location"] = mdata.obs["label"].str.replace('_', '', n=1).str.split('_').str[1].str.replace('t', 'T', n=1)
sc.pp.log1p(mdata["gex"])
sc.pp.pca(mdata["gex"], svd_solver="arpack")
sc.pp.neighbors(mdata["gex"])
sc.tl.umap(mdata["gex"])
ir.pp.index_chains(mdata)
ir.tl.chain_qc(mdata)
ir.pp.ir_dist(mdata, metric="alignment", sequence="aa", cutoff=5)
ir.tl.define_clonotype_clusters(
mdata,
metric="alignment",
sequence="aa",
receptor_arms="any",
dual_ir="primary_only",
)This is the clearest analytic center of the committed notebook: the workflow is built around repertoire-aware clustering and distance calculations, not only around generic scRNA-seq embedding.
Visualize clonotype networks, marker expression, and clonal expansion
The downstream sections use scirpy and muon plotting helpers to inspect clonotype networks, immune-marker expression on the UMAP, receptor chain-pair abundance, and clone expansion across labels.
ir.tl.clonotype_network(mdata, size_aware=False, metric="alignment", sequence="aa")
ax = ir.pl.clonotype_network(
mdata,
color="location",
base_size=10,
label_fontsize=5,
panel_size=(15, 15),
palette={"LNM": "#EBCAD8", "Tumor": "#6DCADE"}
)mu.pl.embedding(
mdata,
basis="gex:umap",
color=["CD8A", "CD4", "FOXP3"],
ncols=3,
wspace=0.7,
)
ir.pl.clonal_expansion(mdata, target_col="clone_id", groupby="label")Gotchas / notes
- The notebook uses OSC-style absolute paths for both TCR annotations and expression matrices; those inputs are not committed in the repo.
- No committed figure assets or rendered notebook outputs are included in this folder, so this page is necessarily lighter than the richer RNA/ATAC workflows.
- The committed markdown headings in the notebook are brief and partly in Chinese, but the code clearly shows the intended analysis sequence.
- This workflow is Python-based and depends on the
muon/scirpyecosystem rather than the Seurat-based R stack used in most other site pages.