Modules
LymphoSeq: Python toolkit for analyzing high-throughput T and B cell receptor sequencing data.
This package provides tools for importing, manipulating, and visualizing Adaptive Immune Receptor Repertoire Sequencing (AIRR-seq) data.
Calculate pairwise similarity between repertoires.
Computes similarity metrics between all pairs of repertoires to measure clonal relatedness. Uses Morisita-Horn index by default, which accounts for both presence/absence and relative abundance of sequences.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences
repertoire_ids – List of repertoire IDs to compare. If None, uses all repertoires (default: None)
by_column – Column containing sequences to compare (default: “junction_aa”)
method – Similarity metric to use: - “morisita”: Morisita-Horn index (default, recommended) - “jaccard”: Jaccard index (presence/absence only) - “cosine”: Cosine similarity
- Returns:
repertoire1, repertoire2: Pair of repertoire IDs
similarity: Similarity score (0-1, where 1 = identical)
n_shared: Number of shared sequences
n_total: Total unique sequences across both repertoires
- Return type:
DataFrame with pairwise similarity scores. Contains columns
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Calculate Morisita-Horn index for all pairs >>> similarity = ls.clonal_relatedness(data) >>> print(similarity)
>>> # Compare specific samples >>> similarity = ls.clonal_relatedness( ... data, ... repertoire_ids=["S1", "S2", "S3"] ... )
>>> # Use Jaccard index instead >>> jaccard = ls.clonal_relatedness(data, method="jaccard")
Notes
Morisita-Horn index: Recommended for abundance-weighted similarity
Jaccard index: Simple overlap coefficient (0-1)
Cosine similarity: Angle between frequency vectors
All metrics return values between 0 (no similarity) and 1 (identical)
References
Morisita M. (1959) Measuring of the dispersion and analysis of distribution patterns. Memoires of the Faculty of Science, Kyushu University, Series E. Biology, 2, 215-235.
See also
common_seqs(): Find shared sequences
differential_abundance(): Test for differential abundance
- lymphoseq.clonality(data: DataFrame | DataFrame, rarefy: bool = False, min_count: int | None = None, iterations: int = 100, group_by: str = 'repertoire_id') DataFrame | DataFrame[source]
Calculate clonality and diversity metrics for each repertoire.
This function calculates standard repertoire diversity metrics including clonality, Gini coefficient, convergence, and unique productive sequences.
Clonality is calculated as 1 - (normalized Shannon entropy), where Shannon entropy is normalized by dividing by log2(n_unique_sequences). This ensures clonality is in the range [0, 1], where: - 0 indicates maximum diversity (all clones equally abundant) - 1 indicates minimum diversity (single dominant clone)
- Parameters:
data – Input data frame with AIRR-formatted sequences
rarefy – Whether to perform rarefaction analysis
min_count – Minimum sequence count for rarefaction
iterations – Number of rarefaction iterations
group_by – Column to group by (default: repertoire_id)
- Returns:
clonality: 1 - normalized Shannon entropy (0-1)
gini_coefficient: Measure of inequality (0-1)
unique_productive_sequences: Number of unique sequences
total_count: Total sequence reads
top_productive_sequence: Frequency of most abundant clone
convergence: Ratio of total sequences to unique sequences
- Return type:
Data frame with diversity metrics for each repertoire
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/") >>> diversity = ls.clonality(data) >>> print(diversity)
- lymphoseq.clone_track(data: DataFrame | DataFrame, by_column: str = 'junction_aa', include_frequency: bool = True) DataFrame | DataFrame[source]
Track clones across multiple repertoires/time points.
Creates a matrix showing the presence and frequency of each unique sequence across all repertoires. This is essential for longitudinal analysis and tracking clonal dynamics over time or across conditions.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences. Must contain ‘repertoire_id’ and the column specified in by_column.
by_column – Column containing sequences to track (default: “junction_aa”)
include_frequency – If True, returns frequencies; if False, returns presence/absence (1/0) (default: True)
- Returns:
DataFrame in wide format with sequences as rows and repertoires as columns. - First column: sequence (junction_aa or junction) - Remaining columns: one per repertoire - Values: frequencies (if include_frequency=True) or binary presence (0/1)
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Track clones with frequencies >>> tracking = ls.clone_track(data) >>> print(tracking.head())
>>> # Track presence/absence only >>> presence = ls.clone_track(data, include_frequency=False)
>>> # Filter for sequences seen in multiple samples >>> # Count non-zero values per row >>> if isinstance(tracking, pl.DataFrame): ... tracking = tracking.with_columns( ... pl.sum_horizontal(pl.all().exclude(by_column) > 0).alias("n_samples") ... ) ... shared = tracking.filter(pl.col("n_samples") > 1)
Notes
Missing sequences in a repertoire are represented as 0
This function is memory-intensive for large datasets
Output is in wide format (sequences × repertoires matrix)
See also
common_seqs(): Find sequences present in multiple repertoires
clonal_relatedness(): Calculate repertoire similarity
- lymphoseq.common_seqs(data: DataFrame | DataFrame, repertoire_ids: List[str] | None = None, by_column: str = 'junction_aa', min_repertoires: int = 2) DataFrame | DataFrame[source]
Find sequences shared across multiple repertoires.
Identifies sequences that appear in two or more repertoires and returns their frequencies across all repertoires where they appear.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences. Must contain ‘repertoire_id’ column and the column specified in by_column.
repertoire_ids – List of repertoire IDs to compare. If None, uses all repertoires in the data (default: None)
by_column – Column name containing sequences to compare (default: “junction_aa”)
min_repertoires – Minimum number of repertoires a sequence must appear in to be included (default: 2)
- Returns:
DataFrame with common sequences and their frequencies across repertoires. Contains columns: sequence column, repertoire_id, duplicate_count, duplicate_frequency, and n_repertoires (count of repertoires sharing this sequence).
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Find sequences common to 2+ samples >>> common = ls.common_seqs(data) >>> print(f"Found {len(common)} common sequence occurrences")
>>> # Find sequences in specific repertoires >>> common = ls.common_seqs( ... data, ... repertoire_ids=["S1", "S2", "S3"] ... )
>>> # Find highly shared sequences (3+ repertoires) >>> highly_shared = ls.common_seqs(data, min_repertoires=3)
See also
clonal_relatedness(): Calculate similarity between repertoires
differential_abundance(): Test for differential sequence abundance
- lymphoseq.common_seqs_venn(data: DataFrame | DataFrame, repertoire_ids: List[str], by_column: str = 'junction_aa', title: str | None = None, width: int = 700, height: int = 700) Figure[source]
Create a Venn diagram showing shared sequences between 2-3 repertoires.
Visualizes the overlap of unique sequences between repertoires, showing which sequences are shared and which are unique to each repertoire.
- Parameters:
data – DataFrame with sequence data
repertoire_ids – List of 2-3 repertoire IDs to compare
by_column – Column to use for comparison (default: junction_aa)
title – Plot title (auto-generated if None)
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly Figure with Venn diagram
- Raises:
ValueError – If number of repertoire_ids is not 2 or 3
Examples
>>> # Compare 2 repertoires >>> fig = common_seqs_venn(df, ["Sample1", "Sample2"]) >>> fig.show()
>>> # Compare 3 repertoires >>> fig = common_seqs_venn(df, ["S1", "S2", "S3"], by_column="junction")
- lymphoseq.common_sequences(data: DataFrame | DataFrame, group_by: str = 'repertoire_id', min_samples: int = 2) DataFrame | DataFrame[source]
Find sequences that are common across multiple repertoires.
- Parameters:
data – Input data frame with AIRR-formatted sequences
group_by – Column to group by
min_samples – Minimum number of samples a sequence must appear in
- Returns:
Data frame with common sequences
- lymphoseq.differential_abundance(data: DataFrame | DataFrame, group1: List[str], group2: List[str], by_column: str = 'junction_aa', min_count: int = 5, method: str = 'fisher') DataFrame | DataFrame[source]
Test for differential abundance of sequences between two groups.
Performs statistical testing (Fisher’s exact test or Chi-square) to identify sequences with significantly different abundances between two groups of repertoires.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences
group1 – List of repertoire IDs in first group
group2 – List of repertoire IDs in second group
by_column – Column containing sequences to compare (default: “junction_aa”)
min_count – Minimum total count across both groups for testing (default: 5)
method – Statistical test method: “fisher” or “chi-square” (default: “fisher”)
- Returns:
sequence column (junction_aa or junction)
count_group1, count_group2: Total counts in each group
freq_group1, freq_group2: Frequencies in each group
p_value: Statistical significance
log2_fold_change: log2(freq_group2 / freq_group1)
significant: Boolean indicating p < 0.05
- Return type:
DataFrame with sequences and test statistics including
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Compare two groups of samples >>> diff = ls.differential_abundance( ... data, ... group1=["Patient1_Pre", "Patient2_Pre"], ... group2=["Patient1_Post", "Patient2_Post"] ... )
>>> # Filter for significant sequences >>> sig = diff.filter(pl.col("significant")) if isinstance(diff, pl.DataFrame) else diff[diff["significant"]] >>> print(f"Found {len(sig)} differentially abundant sequences")
Notes
Fisher’s exact test recommended for small counts
Chi-square test faster for large datasets
P-values are not corrected for multiple testing
See also
common_seqs(): Find shared sequences
clonal_relatedness(): Measure repertoire similarity
- lymphoseq.diversity_metrics(data: DataFrame | DataFrame, group_by: str = 'repertoire_id') DataFrame | DataFrame[source]
Calculate comprehensive diversity metrics for repertoires.
- Parameters:
data – Input data frame with AIRR-formatted sequences
group_by – Column to group by
- Returns:
Data frame with diversity metrics
- lymphoseq.gene_freq(data: DataFrame | DataFrame, gene: Literal['v', 'd', 'j'] = 'v', repertoire_ids: List[str] | None = None, top_n: int | None = None, normalize: bool = True) DataFrame | DataFrame[source]
Calculate V, D, or J gene usage frequencies.
Computes the frequency of each V, D, or J gene across repertoires. Results can be used for repertoire characterization and comparison of gene usage patterns.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences. Must contain v_call, d_call, or j_call columns.
gene – Gene segment to analyze: “v”, “d”, or “j” (default: “v”)
repertoire_ids – List of repertoire IDs to analyze. If None, uses all repertoires (default: None)
top_n – Return only the top N most frequent genes. If None, returns all genes (default: None)
normalize – If True, returns frequencies (0-1); if False, returns raw counts (default: True)
- Returns:
gene_name: Gene identifier (e.g., TRBV1-1)
repertoire_id: Repertoire identifier
count: Number of sequences using this gene
frequency: Proportion of sequences (if normalize=True)
- Return type:
DataFrame with gene usage statistics. Contains columns
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Calculate V gene usage >>> v_usage = ls.gene_freq(data, gene="v") >>> print(v_usage.head())
>>> # Get top 10 J genes >>> j_top10 = ls.gene_freq(data, gene="j", top_n=10)
>>> # Compare D gene usage in specific samples >>> d_usage = ls.gene_freq( ... data, ... gene="d", ... repertoire_ids=["S1", "S2", "S3"] ... )
>>> # Get raw counts instead of frequencies >>> v_counts = ls.gene_freq(data, gene="v", normalize=False)
Notes
Gene calls may contain allele information (e.g., TRBV1-1*01)
Alleles are typically grouped by removing the *01 suffix
Missing or unassigned genes are excluded from calculations
See also
top_seqs(): Get most abundant sequences
clonal_relatedness(): Compare repertoire similarity
- lymphoseq.gene_pair_freq(data: DataFrame | DataFrame, gene_pair: Literal['vj', 'vd', 'dj'] = 'vj', repertoire_ids: List[str] | None = None, top_n: int | None = None, normalize: bool = True) DataFrame | DataFrame[source]
Calculate V-J, V-D, or D-J gene pair usage frequencies.
Analyzes the co-occurrence of gene pairs to understand recombination patterns and biases in repertoires.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences
gene_pair – Gene pair to analyze: “vj”, “vd”, or “dj” (default: “vj”)
repertoire_ids – List of repertoire IDs to analyze. If None, uses all repertoires (default: None)
top_n – Return only the top N most frequent pairs. If None, returns all pairs (default: None)
normalize – If True, returns frequencies; if False, returns counts (default: True)
- Returns:
gene1: First gene in pair (e.g., V gene)
gene2: Second gene in pair (e.g., J gene)
repertoire_id: Repertoire identifier
count: Number of sequences with this pair
frequency: Proportion of sequences (if normalize=True)
- Return type:
DataFrame with gene pair usage statistics. Contains columns
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Calculate V-J pairing >>> vj_pairs = ls.gene_pair_freq(data, gene_pair="vj") >>> print(vj_pairs.head())
>>> # Get top 20 V-J pairs >>> vj_top20 = ls.gene_pair_freq(data, gene_pair="vj", top_n=20)
See also
gene_freq(): Single gene usage analysis
- lymphoseq.get_vdjdb_stats(cache_dir: str | None = None) dict[source]
Get statistics about the VDJdb database.
- Returns:
Dictionary with database statistics
Examples
>>> stats = get_vdjdb_stats() >>> print(f"VDJdb contains {stats['total_entries']} entries")
- lymphoseq.mergeSeqs(data: DataFrame | DataFrame, merge_column: str = 'repertoire_id', new_name: str = 'merged', repertoire_ids: List[str] | None = None) DataFrame | DataFrame[source]
Merge multiple repertoires into a single combined repertoire.
Combines sequences from multiple repertoires, aggregating counts and recalculating frequencies. Useful for creating grouped/pooled samples or combining technical replicates.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences
merge_column – Column to use for grouping (default: “repertoire_id”)
new_name – Name for the merged repertoire (default: “merged”)
repertoire_ids – List of repertoire IDs to merge. If None, merges all repertoires (default: None)
- Returns:
DataFrame with merged repertoire. Sequences are aggregated by junction_aa, counts are summed, and frequencies are recalculated.
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Merge all repertoires >>> merged_all = ls.mergeSeqs(data, new_name="combined")
>>> # Merge specific samples (e.g., technical replicates) >>> merged = ls.mergeSeqs( ... data, ... repertoire_ids=["Sample1_rep1", "Sample1_rep2"], ... new_name="Sample1_merged" ... )
>>> # Merge by treatment group >>> treatment_group = data[data["treatment"] == "drug_A"] >>> merged_treatment = ls.mergeSeqs( ... treatment_group, ... new_name="drug_A_pooled" ... )
Notes
Duplicate counts are summed across merged repertoires
Frequencies are recalculated after merging
Metadata from first occurrence is kept
See also
productive_seq(): Aggregate sequences within repertoires
- lymphoseq.merge_chains(data: DataFrame | DataFrame, repertoire_id: str | None = None, separator: str = ':', keep_chain_columns: bool = False, aggregate: bool = True) DataFrame | DataFrame[source]
Merge alpha and beta chains from 10X data into combined sequences.
This function takes 10X single-cell data with separate TRA and TRB chain information and creates merged junction and junction_aa sequences that can be used with bulk repertoire analysis functions.
The function looks for columns like tra_junction_aa, trb_junction_aa, tra_junction, trb_junction and combines them into junction_aa and junction columns that are compatible with the rest of the package functions.
- Parameters:
data – DataFrame containing 10X data with separate TRA and TRB columns. Expected columns include: tra_junction_aa, trb_junction_aa, tra_junction, trb_junction, and optionally tra_v_call, trb_v_call, etc.
repertoire_id – Optional repertoire ID to filter. If None, processes all repertoires.
separator – String to use for joining alpha and beta sequences (default: “:”)
keep_chain_columns – If True, keep the original tra_* and trb_* columns
aggregate – If True, aggregate identical merged sequences and count them
- Returns:
DataFrame with merged junction and junction_aa columns, compatible with bulk analysis functions like clonality(), diversity_metrics(), etc.
Examples
>>> # Read 10X data >>> data_10x = read_10x("path/to/10x_data/") >>> >>> # Merge chains for bulk-style analysis >>> merged = merge_chains(data_10x) >>> >>> # Now use with any bulk analysis function >>> clonality_scores = clonality(merged) >>> diversity = diversity_metrics(merged) >>> >>> # Keep original chain columns >>> merged_full = merge_chains(data_10x, keep_chain_columns=True) >>> >>> # Custom separator >>> merged_custom = merge_chains(data_10x, separator=";")
- lymphoseq.plot_clonality(data: DataFrame | DataFrame, x_col: str = 'repertoire_id', y_col: str = 'clonality', color_col: str | None = None, title: str = 'Clonality Analysis', width: int = 800, height: int = 600) Figure[source]
Create an interactive clonality plot.
- Parameters:
data – Data frame with clonality results
x_col – Column for x-axis (usually repertoire_id)
y_col – Column for y-axis (clonality values)
color_col – Optional column for color coding
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/") >>> diversity = ls.clonality(data) >>> fig = ls.plot_clonality(diversity) >>> fig.show()
- lymphoseq.plot_common_seqs(data: DataFrame | DataFrame, top_n: int = 20, color_by: str = 'n_repertoires', title: str = 'Sequences Shared Across Repertoires', width: int = 900, height: int = 600) Figure[source]
Plot sequences found in multiple repertoires.
Creates a horizontal bar plot showing shared sequences colored by the number of repertoires they appear in.
- Parameters:
data – DataFrame from common_seqs() function. Must contain ‘junction_aa’, ‘n_repertoires’, and frequency information.
top_n – Number of top sequences to show (default: 20)
color_by – Column to color bars by (default: “n_repertoires”)
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object with shared sequence bars
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> common = ls.common_seqs(data, min_repertoires=2) >>> fig = ls.plot_common_seqs(common, top_n=30) >>> fig.show()
- lymphoseq.plot_differential(data: DataFrame | DataFrame, p_threshold: float = 0.05, fc_threshold: float = 1.0, label_top: int = 10, title: str = 'Differential Abundance (Volcano Plot)', width: int = 900, height: int = 700) Figure[source]
Create a volcano plot for differential abundance analysis.
Plots log2 fold change vs -log10(p-value) to visualize significantly different sequences between groups.
- Parameters:
data – DataFrame from differential_abundance() function. Must contain ‘log2_fold_change’, ‘p_value’, and sequence columns.
p_threshold – P-value threshold for significance (default: 0.05)
fc_threshold – Absolute log2 fold change threshold (default: 1.0)
label_top – Number of top significant sequences to label (default: 10)
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object with volcano plot
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> diff = ls.differential_abundance( ... data, ... group1=["Pre1", "Pre2"], ... group2=["Post1", "Post2"] ... ) >>> fig = ls.plot_differential(diff, label_top=15) >>> fig.show()
- lymphoseq.plot_diversity(data: DataFrame | DataFrame, metrics: List[str] = ['clonality', 'gini_coefficient', 'unique_productive_sequences'], title: str = 'Diversity Metrics Comparison', width: int = 1000, height: int = 600) Figure[source]
Create a multi-metric diversity comparison plot.
- Parameters:
data – Data frame with diversity results
metrics – List of metrics to plot
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object with subplots
Examples
>>> fig = ls.plot_diversity(diversity_results) >>> fig.show()
- lymphoseq.plot_gene_usage(data: DataFrame | DataFrame, top_n: int = 15, facet_by: str | None = None, title: str = 'Gene Usage Frequencies', width: int = 900, height: int = 600) Figure[source]
Plot V, D, or J gene usage frequencies.
Creates horizontal bar plots showing the most frequent genes, optionally faceted by repertoire or condition.
- Parameters:
data – DataFrame from gene_freq() function. Must contain ‘gene_name’, ‘frequency’, and ‘repertoire_id’ columns.
top_n – Number of top genes to show per group (default: 15)
facet_by – Column to create separate subplots (default: None)
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object with gene usage bars
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> v_usage = ls.gene_freq(data, gene="v") >>> fig = ls.plot_gene_usage(v_usage, top_n=20) >>> fig.show()
>>> # Facet by repertoire >>> fig = ls.plot_gene_usage(v_usage, facet_by="repertoire_id")
- lymphoseq.plot_lorenz_curve(data: DataFrame | DataFrame, repertoire_ids: List[str] | None = None, title: str = 'Lorenz Curve - Clonal Inequality', width: int = 800, height: int = 600) Figure[source]
Plot Lorenz curves to visualize clonal inequality.
The Lorenz curve shows cumulative frequency distribution, helping visualize how evenly sequences are distributed. A more diagonal line indicates higher diversity, while a curve closer to the bottom-right indicates clonal dominance (high inequality).
- Parameters:
data – DataFrame with sequence frequencies. Must contain ‘repertoire_id’ and ‘duplicate_frequency’ columns.
repertoire_ids – Optional list of specific repertoires to plot
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object with Lorenz curves
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> fig = ls.plot_lorenz_curve(data) >>> fig.show()
>>> # Compare specific samples >>> fig = ls.plot_lorenz_curve( ... data, ... repertoire_ids=["Pre_treatment", "Post_treatment"] ... )
Notes
Diagonal line represents perfect equality
Area between curve and diagonal is the Gini coefficient
Steeper curves = more clonal (less diverse)
More diagonal = more diverse (even distribution)
See also
clonality(): Calculate diversity metrics including Gini
plot_clonality(): Visualize clonality scores
- lymphoseq.plot_rarefaction(data: DataFrame | DataFrame, color_by: str = 'repertoire_id', show_ci: bool = True, title: str = 'Rarefaction Curves', width: int = 900, height: int = 600) Figure[source]
Plot rarefaction curves showing diversity vs sampling depth.
Creates line plots showing how unique sequences increase with sequencing depth, with optional confidence intervals. Helps assess sampling completeness and compare diversity across samples.
- Parameters:
data – DataFrame from rarefaction_curve() function. Must contain: ‘sample_size’, ‘unique_sequences’, ‘repertoire_id’ columns.
color_by – Column to color lines by (default: “repertoire_id”)
show_ci – Whether to show confidence intervals (default: True)
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object with rarefaction curves
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> rarefaction = ls.rarefaction_curve(data, iterations=100) >>> fig = ls.plot_rarefaction(rarefaction) >>> fig.show()
>>> # Customize appearance >>> fig = ls.plot_rarefaction( ... rarefaction, ... show_ci=False, ... title="Sample Diversity Rarefaction" ... )
- lymphoseq.plot_similarity(data: DataFrame | DataFrame, metric: str = 'similarity', title: str = 'Repertoire Similarity Heatmap', width: int = 700, height: int = 600, colorscale: str = 'RdBu') Figure[source]
Plot repertoire similarity as a heatmap.
Creates a heatmap showing pairwise similarity scores between repertoires from clonal_relatedness() analysis.
- Parameters:
data – DataFrame from clonal_relatedness() function. Must contain ‘repertoire1’, ‘repertoire2’, and similarity metric column.
metric – Column name containing similarity values (default: “similarity”)
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
colorscale – Plotly colorscale name (default: “RdBu”)
- Returns:
Plotly figure object with similarity heatmap
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> similarity = ls.clonal_relatedness(data, method="morisita") >>> fig = ls.plot_similarity(similarity) >>> fig.show()
>>> # Use different colorscale >>> fig = ls.plot_similarity(similarity, colorscale="Viridis")
- lymphoseq.plot_top_seqs(data: DataFrame | DataFrame, top: int = 10, repertoire_ids: List[str] | None = None, title: str = 'Top Sequence Frequencies', width: int = 900, height: int = 600) Figure[source]
1 Create stacked bar plot showing cumulative frequency of top sequences.
Shows the top N most abundant sequences per repertoire as colored bands, with all remaining sequences grouped as “Other”. Useful for visualizing clonal dominance and repertoire diversity at a glance.
- Parameters:
data – DataFrame with sequence data. Must contain ‘repertoire_id’, ‘junction_aa’, and ‘duplicate_frequency’ columns.
top – Number of top sequences to show individually (default: 10)
repertoire_ids – Optional list of specific repertoires to plot
title – Plot title
width – Plot width in pixels
height – Plot height in pixels
- Returns:
Plotly figure object with stacked bar chart
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> # Show top 15 sequences per sample >>> fig = ls.plot_top_seqs(data, top=15) >>> fig.show()
>>> # Compare specific samples >>> fig = ls.plot_top_seqs( ... data, ... top=10, ... repertoire_ids=["S1", "S2", "S3"] ... )
Notes
Sequences are ranked within each repertoire
“Other” category includes all sequences beyond top N
Colors cycle through a spectral palette
Repertoires ordered by diversity (most diverse first)
See also
top_seqs(): Get the top N sequences
plot_clonality(): Visualize clonality metrics
- lymphoseq.productive_seq(data: DataFrame | DataFrame, aggregate: str = 'junction_aa', productive_only: bool = True) DataFrame | DataFrame[source]
Filter productive sequences and optionally aggregate by amino acid or nucleotide.
Filters the data for productive sequences (no stop codons, in-frame) and aggregates counts by the specified sequence column. This is typically used to prepare data for diversity analysis and visualization.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences. Must contain ‘productive’ column and the column specified in aggregate parameter.
aggregate – Column to aggregate by. Options: - “junction_aa”: CDR3 amino acid sequences (default) - “junction”: CDR3 nucleotide sequences - None: No aggregation, just filter productive sequences
productive_only – Whether to filter for productive sequences only (default: True). If False, returns all sequences.
- Returns:
DataFrame with filtered and aggregated sequences, maintaining the same type (Polars or Pandas) as the input.
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Get productive amino acid sequences (most common use case) >>> amino_table = ls.productive_seq(data, aggregate="junction_aa") >>> print(f"Unique amino acid sequences: {len(amino_table)}")
>>> # Get productive nucleotide sequences >>> nucl_table = ls.productive_seq(data, aggregate="junction")
>>> # Just filter productive, no aggregation >>> productive = ls.productive_seq(data, aggregate=None)
Notes
Aggregation sums duplicate_count and recalculates duplicate_frequency
When aggregating, the first occurrence’s metadata is kept
Productive sequences are those where productive=True (no stop codons, in-frame)
See also
top_seqs(): Get top sequences by frequency
unique_seqs(): Get unique sequences without aggregation
- lymphoseq.rarefaction_curve(data: DataFrame | DataFrame, repertoire_ids: List[str] | None = None, step_size: int | None = None, iterations: int = 100, group_by: str = 'repertoire_id') DataFrame | DataFrame[source]
Generate rarefaction curves for diversity analysis.
Creates rarefaction curves by subsampling at multiple depths and calculating diversity metrics. This helps compare repertoires with different sequencing depths and assess sampling completeness.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences. Must contain ‘duplicate_count’, ‘junction_aa’, and group_by columns.
repertoire_ids – List of repertoire IDs to analyze. If None, uses all repertoires (default: None)
step_size – Number of reads between sampling points. If None, uses 10 steps across the range (default: None)
iterations – Number of iterations for each sampling depth (default: 100)
group_by – Column to group by (default: “repertoire_id”)
- Returns:
repertoire_id: Repertoire identifier
sample_size: Number of reads sampled
unique_sequences: Mean number of unique sequences
unique_sequences_sd: Standard deviation across iterations
clonality: Mean clonality at this depth
clonality_sd: Standard deviation of clonality
- Return type:
DataFrame with rarefaction curve data containing
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Generate rarefaction curves for all samples >>> rarefaction = ls.rarefaction_curve(data, iterations=100) >>> print(rarefaction.head())
>>> # Generate curves for specific samples >>> rarefaction = ls.rarefaction_curve( ... data, ... repertoire_ids=["S1", "S2"], ... step_size=1000 ... )
>>> # Plot rarefaction curves (if using pandas) >>> import matplotlib.pyplot as plt >>> for rep in rarefaction["repertoire_id"].unique(): ... subset = rarefaction[rarefaction["repertoire_id"] == rep] ... plt.plot(subset["sample_size"], subset["unique_sequences"], label=rep) >>> plt.xlabel("Sample size") >>> plt.ylabel("Unique sequences") >>> plt.legend() >>> plt.show()
Notes
Rarefaction helps compare diversity across samples with different depths
Sampling is done with replacement, weighted by sequence abundance
Curves that haven’t plateaued suggest undersampling
Standard deviations indicate sampling variance
See also
clonality(): Calculate diversity metrics with optional rarefaction
diversity_metrics(): Comprehensive diversity analysis
- lymphoseq.read_10x(path: str | Path | List[str], recursive: bool = False, collapse_chains: bool = True, parallel: bool = True, threads: int | None = None, return_type: str = 'polars', validate_airr: bool = True, enhanced_mappings: bool = True) DataFrame | DataFrame[source]
Read 10X Genomics VDJ sequencing files.
This function imports files from 10X Genomics Cell Ranger VDJ analysis and standardizes them to AIRR format. Can handle both TSV and JSON formats.
- Parameters:
path – Path to directory containing files, single file, or list of files
recursive – Search recursively for files in subdirectories
collapse_chains – Combine alpha and beta chains for T-cell data
parallel – Process files in parallel
threads – Number of threads to use
return_type – Return format (“polars”, “pandas”)
validate_airr – Enable AIRR schema validation
enhanced_mappings – Use comprehensive column mappings
- Returns:
Parsed and standardized data frame
Examples
>>> # Read 10X VDJ data directory >>> data = read_10x("data/10x_vdj/")
>>> # Read specific file >>> data = read_10x("filtered_contig_annotations.csv")
>>> # Read without chain collapsing >>> data = read_10x("data/", collapse_chains=False)
- lymphoseq.read_immunoseq(path: str | Path | List[str], recursive: bool = False, parallel: bool = True, threads: int | None = None, chunk_size: int | None = None, max_memory_gb: float = 8.0, streaming_mode: bool = False, temp_dir: str | Path | None = None, progress_detail: str = 'basic', return_type: str = 'polars', use_arrow: str | bool = 'auto', validate_airr: bool = True, enhanced_mappings: bool = True, verbose: bool = False) DataFrame | DataFrame | LazyFrame[source]
Read Adaptive ImmunoSEQ files.
This function imports tab-separated value (.tsv) files exported by the Adaptive Biotechnologies ImmunoSEQ analyzer and standardizes them to AIRR format.
- Parameters:
path – Path to directory containing TSV files, single file, or list of files
recursive – Search recursively for files in subdirectories
parallel – Process files in parallel
threads – Number of threads to use (default: auto-detect)
chunk_size – Number of files to process in each chunk for memory efficiency
max_memory_gb – Maximum memory to use in GB
streaming_mode – Process extremely large files in streaming chunks. IMPORTANT: When True, returns a Polars LazyFrame instead of DataFrame to avoid loading the entire dataset into memory. Use .collect() to materialize, or work with lazy operations.
temp_dir – Temporary directory for cache files (default: system temp)
progress_detail – Level of progress reporting (“none”, “basic”, “detailed”)
return_type – Return format (“polars”, “pandas”)
use_arrow – Use Apache Arrow for large datasets (“auto”, “always”, “never”)
validate_airr – Enable AIRR schema validation
enhanced_mappings – Use comprehensive column mappings
verbose – Show detailed progress messages (default: False)
- Returns:
DataFrame (polars or pandas) if streaming_mode=False
LazyFrame (polars) if streaming_mode=True (use .collect() to load)
Examples
>>> # Read all TSV files in a directory >>> data = read_immunoseq("data/immunoseq/")
>>> # Read specific files >>> data = read_immunoseq(["sample1.tsv", "sample2.tsv"])
>>> # Read with custom settings >>> data = read_immunoseq( ... "data/", ... parallel=True, ... threads=4, ... return_type="pandas" ... )
>>> # For very large datasets (100+ GB), use streaming mode >>> # This returns a LazyFrame to avoid loading into memory >>> lazy_data = read_immunoseq( ... "data/large_dataset/", ... streaming_mode=True, ... chunk_size=3, ... parallel=False, ... verbose=False ... ) >>> # Work with lazy operations - only loads what you need >>> result = lazy_data.filter(pl.col("duplicate_count") > 10).collect() >>> # Or collect specific columns only >>> counts = lazy_data.select(["repertoire_id", "duplicate_count"]).collect()
>>> # The Arrow file is saved in temp directory and shown in output >>> # You can also scan it directly later: >>> lazy_data = pl.scan_ipc("/tmp/lymphoseq_output_abc12345.arrow")
- lymphoseq.read_mixcr(path: str | Path | List[str], recursive: bool = False, parallel: bool = True, threads: int | None = None, return_type: str = 'polars', validate_airr: bool = True, enhanced_mappings: bool = True) DataFrame | DataFrame[source]
Read MiXCR pipeline output files.
This function imports tab-separated value (.tsv) files generated by MiXCR and standardizes them to AIRR format.
- Parameters:
path – Path to directory containing TSV files, single file, or list of files
recursive – Search recursively for files in subdirectories
parallel – Process files in parallel
threads – Number of threads to use
return_type – Return format (“polars”, “pandas”)
validate_airr – Enable AIRR schema validation
enhanced_mappings – Use comprehensive column mappings
- Returns:
Parsed and standardized data frame
Examples
>>> # Read MiXCR output directory >>> data = read_mixcr("data/mixcr_output/")
>>> # Read specific file >>> data = read_mixcr("clones.tsv")
>>> # Read with pandas backend >>> data = read_mixcr("data/", return_type="pandas")
- lymphoseq.remove_seq(data: DataFrame | DataFrame, sequences: str | List[str], column: str = 'junction_aa', invert: bool = False) DataFrame | DataFrame[source]
Remove (or keep only) specific sequences from the data.
Removes sequences matching the specified criteria, or keeps only those sequences if invert=True.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences
sequences – Single sequence or list of sequences to remove/keep
column – Column name containing sequences to match (default: “junction_aa”)
invert – If True, keep only matching sequences instead of removing them (default: False)
- Returns:
DataFrame with sequences removed (or kept if invert=True), maintaining the same type (Polars or Pandas) as the input.
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Remove a specific sequence >>> filtered = ls.remove_seq(data, sequences="CASSLKPNTEAFF")
>>> # Remove multiple sequences >>> to_remove = ["CASSLKPNTEAFF", "CASSXXXXTEAFF"] >>> filtered = ls.remove_seq(data, sequences=to_remove)
>>> # Keep only specific sequences >>> keep_these = ["CASSLKPNTEAFF", "CASSXXXXTEAFF"] >>> subset = ls.remove_seq(data, sequences=keep_these, invert=True)
Notes
Case-sensitive matching
Uses exact string matching
See also
productive_seq(): Filter productive sequences
top_seqs(): Select top sequences
- lymphoseq.searchSeq(data: DataFrame | DataFrame, sequence: str, by_column: str = 'junction_aa', exact: bool = True) DataFrame | DataFrame[source]
Search for specific sequences or patterns in the data.
Finds all occurrences of a sequence (exact match) or sequences containing a pattern (substring match) across all repertoires.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences
sequence – Sequence string to search for
by_column – Column to search in (default: “junction_aa”)
exact – If True, exact match; if False, substring match (default: True)
- Returns:
DataFrame containing all matching sequences with their frequencies and repertoire information.
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Find exact sequence >>> matches = ls.searchSeq(data, "CASSLKPNTEAFF") >>> print(f"Found in {matches['repertoire_id'].n_unique()} repertoires")
>>> # Find sequences containing motif >>> motif_matches = ls.searchSeq(data, "LKPN", exact=False) >>> print(f"Found {len(motif_matches)} sequences with LKPN motif")
See also
remove_seq(): Remove specific sequences
common_seqs(): Find shared sequences
- lymphoseq.search_db(data: DataFrame | DataFrame, databases: Literal['all'] | List[str] = 'all', chain: Literal['tra', 'trb', 'igh', 'igk', 'igl'] = 'trb', by_column: str = 'junction_aa', include_similarity: bool = False, cache_dir: str | None = None) DataFrame | DataFrame[source]
Search public databases for TCR/BCR sequences with known antigen specificity.
Searches VDJdb, McPAS-TCR, and IEDB databases to find if your sequences match known antigen-specific receptors. Returns annotated data with epitope, antigen, MHC allele, and reference information.
- Parameters:
data – DataFrame with sequence data
databases – List of databases to search or “all” for all databases Options: [“VDJdb”, “McPAS-TCR”, “IEDB”]
chain – Receptor chain type - “tra”, “trb”, “igh”, “igk”, or “igl”
by_column – Column to search (default: junction_aa)
include_similarity – Include similar (not exact) matches (requires online API)
cache_dir – Directory to cache database files
- Returns:
DataFrame annotated with antigen specificity information
Examples
>>> # Search VDJdb for TRB sequences >>> annotated = search_db(df, databases=["VDJdb"], chain="trb") >>> # Find sequences with known epitopes >>> matches = annotated[annotated["epitope"].notna()] >>> print(matches[["junction_aa", "epitope", "antigen", "mhc_allele"]])
Notes
Requires internet connection for first download
Database files are cached locally for faster subsequent searches
VDJdb: https://vdjdb.cdr3.net/
McPAS-TCR: http://friedmanlab.weizmann.ac.il/McPAS-TCR/
IEDB: https://www.iedb.org/
- lymphoseq.search_published(data: DataFrame | DataFrame, by_column: str = 'junction_aa') DataFrame | DataFrame[source]
Search for sequences in published TCR literature.
Annotates your sequences with information from published studies if they match known TCR sequences in the literature.
- Parameters:
data – DataFrame with sequence data
by_column – Column to search (default: junction_aa)
- Returns:
DataFrame annotated with published sequence information
Examples
>>> # Find published sequences in your data >>> annotated = search_published(df) >>> published_seqs = annotated[annotated["published"].notna()]
Notes
This is a wrapper around search_db that searches all available databases. For more control, use search_db() directly.
- lymphoseq.split_chains(data: DataFrame | DataFrame, separator: str = ':') DataFrame | DataFrame[source]
Split merged junction sequences back into separate alpha and beta chains.
This is the reverse operation of merge_chains(), taking merged sequences and splitting them back into tra_junction_aa and trb_junction_aa columns.
- Parameters:
data – DataFrame with merged junction_aa column
separator – String that was used to join sequences (default: “:”)
- Returns:
DataFrame with separated tra_junction_aa and trb_junction_aa columns
Examples
>>> # Merge chains >>> merged = merge_chains(data_10x) >>> >>> # Split them back >>> split = split_chains(merged) >>> >>> # Check the split columns >>> print(split[["tra_junction_aa", "trb_junction_aa"]].head())
- lymphoseq.top_seqs(data: DataFrame | DataFrame, top: int = 1, group_by: str = 'repertoire_id', order_by: str = 'duplicate_frequency') DataFrame | DataFrame[source]
Select top N sequences from each repertoire by frequency.
Creates a DataFrame containing the top productive sequences from each repertoire, ordered by their frequencies.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences. Must contain columns specified in group_by and order_by parameters.
top – Number of top sequences to select from each repertoire (default: 1)
group_by – Column name to group by (default: “repertoire_id”)
order_by – Column name to order by (default: “duplicate_frequency”)
- Returns:
DataFrame containing top N sequences from each repertoire, maintaining the same type (Polars or Pandas) as the input.
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/") >>> # Get top 10 sequences from each repertoire >>> top_10 = ls.top_seqs(data, top=10) >>> print(f"Selected {len(top_10)} sequences")
>>> # Get most abundant clone from each sample >>> top_clone = ls.top_seqs(data, top=1) >>> print(top_clone[["repertoire_id", "junction_aa", "duplicate_frequency"]])
See also
productive_seq(): Filter for productive sequences
unique_seqs(): Get unique sequences
- lymphoseq.unique_seqs(data: DataFrame | DataFrame, by_column: str = 'junction_aa', keep: str = 'first') DataFrame | DataFrame[source]
Get unique sequences based on specified column.
Returns unique sequences based on the specified column, keeping either the first or last occurrence of duplicates.
- Parameters:
data – Input DataFrame with AIRR-formatted sequences
by_column – Column name to determine uniqueness (default: “junction_aa”)
keep – Which occurrence to keep for duplicates: - “first”: Keep first occurrence (default) - “last”: Keep last occurrence
- Returns:
DataFrame with unique sequences, maintaining the same type (Polars or Pandas) as the input.
Examples
>>> import lymphoseq as ls >>> data = ls.read_immunoseq("data/immunoseq/")
>>> # Get unique amino acid sequences >>> unique_aa = ls.unique_seqs(data, by_column="junction_aa") >>> print(f"Unique sequences: {len(unique_aa)}")
>>> # Get unique nucleotide sequences >>> unique_nt = ls.unique_seqs(data, by_column="junction")
Notes
This function does not aggregate counts like productive_seq()
Use productive_seq() with aggregate parameter for count aggregation
See also
productive_seq(): Filter and aggregate sequences
top_seqs(): Get top sequences by frequency