Skip to content

DeRIP Class

DeRIP

DeRIP(alignment_input, max_snp_noise: float = 0.5, min_rip_like: float = 0.1, reaminate: bool = False, fill_index: Optional[int] = None, fill_max_gc: bool = False, max_gaps: float = 0.7)

A class to detect and correct RIP (Repeat-Induced Point) mutations in DNA alignments.

This class encapsulates the functionality to analyze DNA sequence alignments for RIP-like mutations, correct them, and generate deRIPed consensus sequences.

PARAMETER DESCRIPTION
alignment_input

Path to the alignment file in FASTA format or a pre-loaded MultipleSeqAlignment object.

TYPE: str or MultipleSeqAlignment

max_snp_noise

Maximum proportion of conflicting SNPs permitted before excluding column from RIP/deamination assessment (default: 0.5).

TYPE: float DEFAULT: 0.5

min_rip_like

Minimum proportion of deamination events in RIP context required for column to be deRIP'd in final sequence (default: 0.1).

TYPE: float DEFAULT: 0.1

reaminate

Whether to correct all deamination events independent of RIP context (default: False).

TYPE: bool DEFAULT: False

fill_index

Index of row to use for filling uncorrected positions (default: None).

TYPE: int DEFAULT: None

fill_max_gc

Whether to use sequence with highest GC content for filling if no row index is specified (default: False).

TYPE: bool DEFAULT: False

max_gaps

Maximum proportion of gaps in a column before considering it a gap in consensus (default: 0.7).

TYPE: float DEFAULT: 0.7

ATTRIBUTE DESCRIPTION
alignment

The loaded DNA sequence alignment.

TYPE: MultipleSeqAlignment

masked_alignment

The alignment with RIP-corrected positions masked with IUPAC codes.

TYPE: MultipleSeqAlignment

consensus

The deRIPed consensus sequence.

TYPE: SeqRecord

gapped_consensus

The deRIPed consensus sequence with gaps.

TYPE: SeqRecord

rip_counts

Dictionary tracking RIP mutation counts for each sequence.

TYPE: Dict

corrected_positions

Dictionary of corrected positions {col_idx: {row_idx: {observed_base, corrected_base}}}.

TYPE: Dict

colored_consensus

Consensus sequence with corrected positions highlighted in green.

TYPE: str

colored_alignment

Alignment with corrected positions highlighted in green.

TYPE: str

colored_masked_alignment

Masked alignment with RIP positions highlighted in color.

TYPE: str

markupdict

Dictionary of markup codes for masked positions.

TYPE: Dict

Initialize DeRIP with an alignment file or MultipleSeqAlignment object and parameters.

PARAMETER DESCRIPTION
alignment_input

Path to the alignment file in FASTA format or a pre-loaded MultipleSeqAlignment object. If a MultipleSeqAlignment is provided, it must contain at least 2 sequences.

TYPE: str or MultipleSeqAlignment

max_snp_noise

Maximum proportion of conflicting SNPs permitted before excluding column from RIP/deamination assessment (default: 0.5).

TYPE: float DEFAULT: 0.5

min_rip_like

Minimum proportion of deamination events in RIP context required for column to be deRIP'd in final sequence (default: 0.1).

TYPE: float DEFAULT: 0.1

reaminate

Whether to correct all deamination events independent of RIP context (default: False).

TYPE: bool DEFAULT: False

fill_index

Index of row to use for filling uncorrected positions (default: None).

TYPE: int DEFAULT: None

fill_max_gc

Whether to use sequence with highest GC content for filling if no row index is specified (default: False).

TYPE: bool DEFAULT: False

max_gaps

Maximum proportion of gaps in a column before considering it a gap in consensus (default: 0.7).

TYPE: float DEFAULT: 0.7

calculate_rip

calculate_rip(label: str = 'deRIPseq') -> None

Calculate RIP locations and corrections in the alignment.

This method performs RIP detection and correction, fills in the consensus sequence, and populates the class attributes.

PARAMETER DESCRIPTION
label

ID for the generated deRIPed sequence (default: "deRIPseq").

TYPE: str DEFAULT: 'deRIPseq'

RETURNS DESCRIPTION
None

Updates class attributes with results.

calculate_cri

calculate_cri(sequence)

Calculate the Composite RIP Index (CRI) for a DNA sequence.

PARAMETER DESCRIPTION
sequence

The DNA sequence to analyze.

TYPE: str

RETURNS DESCRIPTION
tuple

(cri, pi, si) - Composite RIP Index, Product Index, and Substrate Index.

calculate_cri_for_all

calculate_cri_for_all()

Calculate the Composite RIP Index (CRI) for each sequence in the alignment and assign CRI values as annotations to each sequence record.

RETURNS DESCRIPTION
MultipleSeqAlignment

The alignment with CRI metadata added to each record.

Notes

This method calculates: - Product Index (PI) = TpA / ApT - Substrate Index (SI) = (CpA + TpG) / (ApC + GpT) - Composite RIP Index (CRI) = PI - SI

High CRI values indicate strong RIP activity.

calculate_dinucleotide_frequency

calculate_dinucleotide_frequency(sequence)

Calculate the frequency of specific dinucleotides in a sequence.

PARAMETER DESCRIPTION
sequence

The DNA sequence to analyze.

TYPE: str

RETURNS DESCRIPTION
dict

A dictionary with dinucleotide counts.

calculate_rsi

calculate_rsi(ambiguous: str = 'split', substrate_scope: str = 'all')

Calculate the RIP Strandedness Imbalance (RSI) for every sequence.

RSI is p_fwd - p_rev, the difference between the proportion of forward-strand substrate (CpA) and reverse-strand substrate (TpG) that RIP has converted to TpA. It lies in [-1, 1]: positive means RIP acted mainly on the forward strand, negative mainly on the reverse.

Because a single round of meiotic RIP acts on one strand of a duplex, a strongly imbalanced sequence is the signature of one round of RIP, while a balanced one has either escaped RIP or been RIP'd repeatedly on both strands. p_fwd and p_rev separate those two cases.

PARAMETER DESCRIPTION
ambiguous

How to attribute TpA dinucleotides that could have arisen from RIP on either strand (default: 'split', half to each).

TYPE: (split, exclude, weight, both) DEFAULT: 'split'

substrate_scope

Which unmutated substrate dinucleotides enter the denominators (default: 'all').

TYPE: (all, assessable, rip_like_columns) DEFAULT: 'all'

RETURNS DESCRIPTION
RSIResult

Per-sequence RSI, its components, ambiguity counts and significance.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first.

See Also

derip2.stats.strand_bias.compute_rsi : The underlying calculation.

Examples:

>>> d = DeRIP('alignment.fa')
>>> d.calculate_rip()
>>> d.calculate_rsi().rsi
array([ 0.9, -0.8,  0.0])

rip_summary

rip_summary() -> None

Return a summary of RIP mutations found in each sequence as str.

RETURNS DESCRIPTION
str

Summary of RIP mutations by sequence.

RAISES DESCRIPTION
ValueError

If calculate_rip has not been called first.

summarize_cri

summarize_cri()

Generate a formatted table summarizing CRI values for all sequences.

RETURNS DESCRIPTION
str

A formatted string containing the CRI summary table.

summarize_stats

summarize_stats(ambiguous: str = 'split')

Build a per-sequence table of every RIP statistic deRIP2 computes.

Combines the RIP event counts from the alignment scan, the classical composite RIP index (CRI) and its components, GC content, and the strandedness imbalance (RSI) with its components and significance.

PARAMETER DESCRIPTION
ambiguous

Ambiguity policy for RSI (default: 'split'). RSI is recomputed whenever this differs from the cached result's policy.

TYPE: (split, exclude, weight, both) DEFAULT: 'split'

RETURNS DESCRIPTION
DataFrame

One row per sequence, in alignment order.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first.

stats_summary

stats_summary(ambiguous: str = 'split') -> str

Format :meth:summarize_stats as a table for terminal output.

PARAMETER DESCRIPTION
ambiguous

Ambiguity policy (default: 'split').

TYPE: str DEFAULT: 'split'

RETURNS DESCRIPTION
str

The stats table, ready to print.

calculate_spectra

calculate_spectra(partition_by: str = 'none', ancestor=None, samples=None, context: str = 'trinucleotide')

Compute the SBS-96 and SBS-192 trinucleotide mutation spectra.

Every alignment cell whose base differs from the ancestral reference at that column is counted as one substitution event, with its trinucleotide context read from the ancestor using nearest non-gap bases. Events are folded to the pyrimidine strand for the SBS-96 matrix and kept strand-resolved for the SBS-192 matrix.

This is the tree-free baseline spectrum: the ancestor is deRIP2's reconstructed consensus (or a user-supplied sequence), so recurrence is reported only as a multi-hit-column proxy. Correct independent-event counting requires the phylogenetic path.

PARAMETER DESCRIPTION
partition_by

How to split the spectra into samples. 'none' (default) pools every sequence into one AllSequences sample; 'row' gives one sample column per input sequence. Ignored when samples is given.

TYPE: (none, row) DEFAULT: 'none'

ancestor

Ancestral reference sequence, one base per alignment column. Defaults to deRIP2's gapped consensus (:attr:gapped_consensus).

TYPE: str or SeqRecord DEFAULT: None

samples

An explicit per-row sample label (length equal to the number of sequences), e.g. species or group names. Overrides partition_by when provided.

TYPE: sequence of str DEFAULT: None

context

Which sequence context to classify substitutions by (default: 'trinucleotide'). 'downstream' builds the pyrimidine-folded downstream-triplet matrix (CHG-aware) with no strand-resolved form.

TYPE: (trinucleotide, downstream) DEFAULT: 'trinucleotide'

RETURNS DESCRIPTION
SpectraResult

The assembled spectra, per-event detail and homoplasy proxy.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first, or if partition_by is not recognised.

See Also

derip2.stats.mutation_spectra.compute_spectra : The underlying calculation.

write_spectra_matrix

write_spectra_matrix(output_file: str, kind: str = '96', **kwargs) -> str

Write a SigProfiler-compliant SBS matrix, computing spectra if needed.

PARAMETER DESCRIPTION
output_file

Destination path for the tab-separated matrix file.

TYPE: str

kind

Which spectrum matrix to write (default: '96').

TYPE: (96, 192) DEFAULT: '96'

**kwargs

Passed to :meth:calculate_spectra when spectra have not yet been computed.

DEFAULT: {}

RETURNS DESCRIPTION
str

The path written.

plot_spectra

plot_spectra(output_file: Optional[str] = None, kind: str = '96', **kwargs)

Draw an SBS mutation-spectrum figure, computing spectra if needed.

PARAMETER DESCRIPTION
output_file

Path to write the figure to. Use .svg or .pdf for publication output.

TYPE: str DEFAULT: None

kind

Which figure to draw: the SBS-96 spectrum (default), the SBS-192 strand-resolved spectrum, the pyrimidine-folded downstream-triplet spectrum, the strand-asymmetry panel, or the homoplasy (recurrence) plot.

TYPE: (96, 192, downstream, strand, homoplasy) DEFAULT: '96'

**kwargs

Forwarded to the underlying plotting function (e.g. title, percentage, min_hits), except any that :meth:calculate_spectra consumes when spectra are first computed.

DEFAULT: {}

RETURNS DESCRIPTION
Figure

The figure.

RAISES DESCRIPTION
ValueError

If kind is not recognised.

calculate_flank_spectra

calculate_flank_spectra(flank_length: int = 1)

Compute the flanking-context spectra of RIP-like sites.

Classifies every RIP-like dinucleotide by the flank_length bases upstream and downstream (a 2 + 2 * flank_length bp motif; a 4 bp motif for the default 1 bp flank). Surviving substrate sites (CpA/TpG anywhere in each sequence) and RIP product sites (TpA in RIP-informative columns) are counted separately, one sample column per input sequence, folded onto CA/TA-equivalent channels. The result is cached on :attr:flank_spectra_result and recomputed if a different flank_length is requested.

PARAMETER DESCRIPTION
flank_length

Number of flanking bases resolved on each side of the centre dinucleotide (default 1), giving 4 ** (2 * flank_length) channels.

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
FlankSpectraResult

The four (4 ** (2 * flank_length), n_rows) count matrices and per-state skipped counts.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first.

See Also

derip2.stats.flank_spectra.compute_flank_spectra : The calculation.

write_flank_spectra_matrix

write_flank_spectra_matrix(output_file: str) -> str

Write the flank-context spectra as a tidy TSV, computing them if needed.

PARAMETER DESCRIPTION
output_file

Destination path for the tab-separated matrix file.

TYPE: str

RETURNS DESCRIPTION
str

The path written.

write_flank_spectra_comparisons

write_flank_spectra_comparisons(output_file: str, *, min_sites: int = 20) -> str

Write the per-sequence flank-context comparison stats, computing if needed.

PARAMETER DESCRIPTION
output_file

Destination path for the tab-separated comparison file.

TYPE: str

min_sites

Minimum site count on both sides for the chi-squared reliability flag (default: 20).

TYPE: int DEFAULT: 20

RETURNS DESCRIPTION
str

The path written.

plot_flank_spectra

plot_flank_spectra(output_file: Optional[str] = None, *, percentage: bool = False, **kwargs)

Draw the pooled flank-context bihistograms, computing spectra if needed.

PARAMETER DESCRIPTION
output_file

Path to write the figure to. Use .svg or .pdf for publication output.

TYPE: str DEFAULT: None

percentage

When True, plot count-normalised proportions instead of raw counts: each state (substrate, product) is rescaled to sum to 100 across the 16 motifs, so the two spectra are compared on equal footing regardless of how many substrate vs product sites there are (default: False, raw counts).

TYPE: bool DEFAULT: False

**kwargs

Forwarded to :func:derip2.plotting.flank_spectra.plot_flank_bihistograms_pooled (e.g. title, strands, width).

DEFAULT: {}

RETURNS DESCRIPTION
Figure

The figure.

plot_flank_conversion_heatmap

plot_flank_conversion_heatmap(output_file: Optional[str] = None, *, flank_length: int = 1, **kwargs)

Draw the pooled flank-context RIP-conversion heatmap, computing if needed.

Each cell of the 4 ** flank_length x 4 ** flank_length grid shows the percentage of a RIP target CpA converted to TpA (the product share) as a joint function of the upstream (rows) and downstream (columns) flank bases.

PARAMETER DESCRIPTION
output_file

Path to write the figure to (.svg/.png/.pdf).

TYPE: str DEFAULT: None

flank_length

Flank width; recomputes the spectra if it differs from the cached result (default 1).

TYPE: int DEFAULT: 1

**kwargs

Forwarded to :func:derip2.plotting.flank_spectra.plot_flank_conversion_heatmap (e.g. title, bare, flank_sort). Notably cmap restyles the colour scale: pass a matplotlib colormap name such as 'magma_r' or 'viridis', a :class:~matplotlib.colors.Colormap, or a list of colours to interpolate between.

DEFAULT: {}

RETURNS DESCRIPTION
Figure

The heatmap figure.

calculate_max_rip

calculate_max_rip(variant: str = 'all')

Build a maximally RIP-mutated variant of the deRIP'd consensus.

The counterfactual complement of :meth:calculate_rip: instead of restoring the bases RIP removed, it mutates every RIP target the corrected sequence still carries. Results are cached per variant on :attr:max_rip_results.

PARAMETER DESCRIPTION
variant

Which sites to convert (default 'all', every substrate site in the consensus). See :mod:derip2.maxrip for the full definitions.

TYPE: (all, observed, all_plus_nonrip) DEFAULT: 'all'

RETURNS DESCRIPTION
MaxRIPResult

The mutated sequence and the positions that were changed.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first, or variant is not one of :data:derip2.maxrip.MAX_RIP_VARIANTS.

See Also

derip2.maxrip.compute_max_rip : The calculation.

get_max_rip_string

get_max_rip_string(variant: str = 'all', gapped: bool = False) -> str

Return a maximum-RIP sequence as a string, computing it if needed.

PARAMETER DESCRIPTION
variant

Which sites to convert (default 'all').

TYPE: (all, observed, all_plus_nonrip) DEFAULT: 'all'

gapped

Return the column-aligned sequence rather than the ungapped one (default False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
str

The maximally RIP-mutated sequence.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first, or variant is unknown.

get_max_rip_positions

get_max_rip_positions(variant: str = 'all', gapped: bool = False) -> List[int]

Return the positions converted by a maximum-RIP variant.

PARAMETER DESCRIPTION
variant

Which sites to convert (default 'all').

TYPE: (all, observed, all_plus_nonrip) DEFAULT: 'all'

gapped

Return alignment column indices rather than offsets into the ungapped sequence (default False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
list of int

Ascending zero-based positions of the converted sites.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first, or variant is unknown.

write_max_rip

write_max_rip(output_file: str, variants=None, seq_id: str = 'maxRIPseq', gapped: bool = False) -> str

Write maximum-RIP sequences to a FASTA file, computing them if needed.

PARAMETER DESCRIPTION
output_file

Destination path.

TYPE: str

variants

Which variants to write, in order; defaults to every variant in :data:derip2.maxrip.MAX_RIP_VARIANTS.

TYPE: iterable of str DEFAULT: None

seq_id

Base record id; each record is suffixed with its variant name (default 'maxRIPseq').

TYPE: str DEFAULT: 'maxRIPseq'

gapped

Write column-aligned sequences rather than ungapped ones (default False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
str

output_file, for chaining.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first, or a requested variant is unknown.

write_alignment

write_alignment(output_file: str, append_consensus: bool = True, mask_rip: bool = True, consensus_id: str = 'deRIPseq', format: str = 'fasta') -> None

Write alignment to file with options to append consensus and mask RIP positions.

PARAMETER DESCRIPTION
output_file

Path to the output alignment file.

TYPE: str

append_consensus

Whether to append the consensus sequence to the alignment (default: True).

TYPE: bool DEFAULT: True

mask_rip

Whether to mask RIP positions in the output alignment (default: True).

TYPE: bool DEFAULT: True

consensus_id

ID for the consensus sequence if appended (default: "deRIPseq").

TYPE: str DEFAULT: 'deRIPseq'

format

Format for the output alignment file (default: "fasta").

TYPE: str DEFAULT: 'fasta'

RETURNS DESCRIPTION
None

Writes alignment to file.

RAISES DESCRIPTION
ValueError

If calculate_rip has not been called first.

write_consensus

write_consensus(output_file: str, consensus_id: str = 'deRIPseq') -> None

Write the deRIPed consensus sequence to a FASTA file.

PARAMETER DESCRIPTION
output_file

Path to the output FASTA file.

TYPE: str

consensus_id

ID for the consensus sequence (default: "deRIPseq").

TYPE: str DEFAULT: 'deRIPseq'

RETURNS DESCRIPTION
None

Writes consensus sequence to file.

RAISES DESCRIPTION
ValueError

If calculate_rip has not been called first.

write_stats

write_stats(output_file: str, ambiguous: str = 'split') -> str

Write the per-sequence statistics table to a TSV file.

PARAMETER DESCRIPTION
output_file

Destination path.

TYPE: str

ambiguous

Ambiguity policy (default: 'split').

TYPE: str DEFAULT: 'split'

RETURNS DESCRIPTION
str

The path written.

write_html_report

write_html_report(output_file: str, title: Optional[str] = None, ambiguous: str = 'split', **kwargs) -> str

Write a self-contained HTML report of the strand-bias analysis.

The report embeds three strand-bias figures (RIP-like mutations, non-RIP deamination, and all deamination) as inline SVG, alongside the per-sequence statistics table. It has no external assets, so it can be emailed or archived as a single file.

PARAMETER DESCRIPTION
output_file

Destination path for the HTML file.

TYPE: str

title

Report heading.

TYPE: str DEFAULT: None

ambiguous

Ambiguity policy for RSI (default: 'split').

TYPE: str DEFAULT: 'split'

**kwargs

Forwarded to each figure, e.g. scale, xaxis, columns.

DEFAULT: {}

RETURNS DESCRIPTION
str

The path written.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first.

write_per_sequence_report

write_per_sequence_report(output_file: str, title: Optional[str] = None, ambiguous: str = 'split', max_seqs: Optional[int] = None, **kwargs) -> str

Write a single-file, interactive per-sequence HTML report.

The report renders one panel per input sequence — the alignment row with RIP sites highlighted, a fixed-height per-sequence strand-bias strip, a per-sequence SBS-96 spectrum against the reconstructed ancestor, and that sequence's summary statistics — and lets the reader step between sequences with the arrow keys. Every figure is inline SVG, so the file is self-contained.

PARAMETER DESCRIPTION
output_file

Destination path for the HTML file.

TYPE: str

title

Report heading.

TYPE: str DEFAULT: None

ambiguous

Ambiguity policy for the per-sequence RSI statistics (default: 'split').

TYPE: str DEFAULT: 'split'

max_seqs

Cap the number of sequence panels, keeping the first max_seqs rows in alignment order. Sort or filter the alignment first (e.g. :meth:sort_by_rsi) to change which sequences that is. None (default) renders every sequence.

TYPE: int DEFAULT: None

**kwargs

Forwarded to :func:derip2.persequence_report.write_per_sequence_report.

DEFAULT: {}

RETURNS DESCRIPTION
str

The path written.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first.

plot_alignment

plot_alignment(output_file: Optional[str] = None, dpi: int = 300, title: Optional[str] = None, width: int = 20, height: int = 15, palette: str = 'derip2', column_ranges: Optional[List[Tuple[int, int, str, str]]] = None, show_chars: bool = False, draw_boxes: bool = False, show_rip: str = 'both', highlight_corrected: bool = True, flag_corrected: bool = False, **kwargs) -> str

Generate a visualization of the alignment with RIP mutations highlighted.

This method creates a PNG image showing the aligned sequences with color-coded highlighting of RIP mutations and corrections. It displays the consensus sequence below the alignment with asterisks marking corrected positions.

PARAMETER DESCRIPTION
output_file

Path to save the output image file.

TYPE: str DEFAULT: None

dpi

Resolution of the output image in dots per inch (default: 300).

TYPE: int DEFAULT: 300

title

Title to display on the image (default: None).

TYPE: str DEFAULT: None

width

Width of the output image in inches (default: 20).

TYPE: int DEFAULT: 20

height

Height of the output image in inches (default: 15).

TYPE: int DEFAULT: 15

palette

Color palette to use: 'colorblind', 'bright', 'tetrimmer', 'basegrey', or 'derip2' (default: 'basegrey').

TYPE: str DEFAULT: 'derip2'

column_ranges

List of column ranges to mark, each as (start_col, end_col, color, label) (default: None).

TYPE: List[Tuple[int, int, str, str]] DEFAULT: None

show_chars

Whether to display sequence characters inside the colored cells (default: False).

TYPE: bool DEFAULT: False

draw_boxes

Whether to draw black borders around highlighted bases (default: False).

TYPE: bool DEFAULT: False

show_rip

Which RIP markup categories to include: 'substrate', 'product', or 'both' (default: 'both').

TYPE: str DEFAULT: 'both'

highlight_corrected

If True, only corrected positions in the consensus will be colored, all others will be gray (default: True).

TYPE: bool DEFAULT: True

flag_corrected

If True, corrected positions in the alignment will be marked with asterisks (default: False).

TYPE: bool DEFAULT: False

**kwargs

Additional keyword arguments to pass to drawMiniAlignment function.

DEFAULT: {}

RETURNS DESCRIPTION
str

Path to the output image file.

RAISES DESCRIPTION
ValueError

If calculate_rip has not been called first.

Notes

The visualization uses different colors to distinguish RIP-related mutations: - Red: RIP products (typically T from C→T mutations) - Blue: RIP substrates (unmutated nucleotides in RIP context) - Yellow: Non-RIP deaminations (only if reaminate=True) - Target bases are displayed in black text, while surrounding context is in grey text

plot_strand_bias

plot_strand_bias(output_file: Optional[str] = None, mode: str = 'rip', **kwargs)

Draw a diverging stacked-bar chart of per-column RIP strand bias.

Bars are drawn above the axis where the deamination is observed on the forward strand and below it where it is observed on the reverse strand.

PARAMETER DESCRIPTION
output_file

Path to write the figure to. Use .svg or .pdf for publication output.

TYPE: str DEFAULT: None

mode

Which deamination events to display (default: 'rip').

TYPE: (rip, non_rip, all_deamination) DEFAULT: 'rip'

**kwargs

Additional options forwarded to :func:derip2.plotting.strandbias.plot_strand_bias, such as scale, stack, xaxis, color_by, emphasis and column_range. columns selects which positions are lettered when xaxis is 'logo' or 'derip'; every column is drawn as a bar regardless.

DEFAULT: {}

RETURNS DESCRIPTION
Figure

The figure.

RAISES DESCRIPTION
ValueError

If :meth:calculate_rip has not been called first.

get_cri_values

get_cri_values()

Return a list of CRI values for all sequences in the alignment.

If a sequence doesn't have a CRI value yet, calculate it first.

RETURNS DESCRIPTION
list of dict

List of dictionaries containing CRI, PI, SI values and sequence ID, in the same order as sequences appear in the alignment.

get_rsi_values

get_rsi_values(**kwargs)

Return per-sequence RSI values, calculating them if needed.

PARAMETER DESCRIPTION
**kwargs

Passed to :meth:calculate_rsi when RSI has not yet been computed.

DEFAULT: {}

RETURNS DESCRIPTION
list of dict

One record per sequence, in alignment order.

get_gc_content

get_gc_content()

Calculate and return the GC content for all sequences in the alignment.

RETURNS DESCRIPTION
list of dict

List of dictionaries containing sequence ID and GC content, in the same order as sequences appear in the alignment.

RAISES DESCRIPTION
ValueError

If no alignment is loaded.

get_consensus_string

get_consensus_string() -> str

Get the deRIPed consensus sequence as a string.

RETURNS DESCRIPTION
str

The deRIPed consensus sequence.

RAISES DESCRIPTION
ValueError

If calculate_rip has not been called first.

sort_by_cri

sort_by_cri(descending=True, inplace=False)

Sort the alignment by CRI score.

PARAMETER DESCRIPTION
descending

If True, sort in descending order (highest CRI first). Default: True.

TYPE: bool DEFAULT: True

inplace

If True, replace the current alignment with the sorted alignment. If False, return a new alignment without modifying the original (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
MultipleSeqAlignment

A new alignment with sequences sorted by CRI score.

sort_by_rsi

sort_by_rsi(descending: bool = True, inplace: bool = False)

Sort the alignment by RIP strandedness imbalance.

PARAMETER DESCRIPTION
descending

If True (default), sequences with the most forward-strand RIP come first and those with the most reverse-strand RIP last.

TYPE: bool DEFAULT: True

inplace

If True, replace the current alignment and discard all computed results, which must then be recalculated (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
MultipleSeqAlignment

The sorted alignment.

Notes

Sequences whose RSI is undefined (NaN, because one strand carries no substrate and no product) sort to the end regardless of direction. They carry no evidence, so placing them at either extreme would misrepresent them.

filter_by_cri

filter_by_cri(min_cri=0.0, inplace=False)

Filter the alignment to remove sequences with CRI values below a threshold.

PARAMETER DESCRIPTION
min_cri

Minimum CRI value to keep a sequence in the alignment (default: 0.0).

TYPE: float DEFAULT: 0.0

inplace

If True, replace the current alignment with the filtered alignment. If False, return a new alignment without modifying the original (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
MultipleSeqAlignment

A new alignment containing only sequences with CRI values >= min_cri.

RAISES DESCRIPTION
ValueError

If no alignment is loaded or if filtering would remove all sequences.

Warning

If fewer than 2 sequences remain after filtering.

Notes

CRI values will be calculated for sequences that don't already have them. If inplace=True, this will modify the original alignment in the DeRIP object.

filter_by_gc

filter_by_gc(min_gc=0.0, inplace=False)

Filter the alignment to remove sequences with GC content below a threshold.

PARAMETER DESCRIPTION
min_gc

Minimum GC content to keep a sequence in the alignment (default: 0.0). Value should be between 0.0 and 1.0.

TYPE: float DEFAULT: 0.0

inplace

If True, replace the current alignment with the filtered alignment. If False, return a new alignment without modifying the original (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
MultipleSeqAlignment

A new alignment containing only sequences with GC content >= min_gc.

RAISES DESCRIPTION
ValueError

If no alignment is loaded or if filtering would remove all sequences.

Warning

If fewer than 2 sequences remain after filtering.

Notes

GC content will be calculated for sequences that don't already have it. If inplace=True, this will modify the original alignment in the DeRIP object.

keep_low_cri

keep_low_cri(n=2, inplace=False)

Retain only the n sequences with the lowest CRI values.

PARAMETER DESCRIPTION
n

Number of sequences with lowest CRI values to keep (default: 2).

TYPE: int DEFAULT: 2

inplace

If True, replace the current alignment with the filtered alignment. If False, return a new alignment without modifying the original (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
MultipleSeqAlignment

A new alignment containing only the n sequences with lowest CRI values.

RAISES DESCRIPTION
ValueError

If no alignment is loaded.

Notes

CRI values will be calculated for sequences that don't already have them. If inplace=True, this will modify the original alignment in the DeRIP object. If n is greater than the number of sequences, no filtering occurs. If n is less than 2, no filtering occurs to ensure DeRIP has enough sequences to work with.

keep_high_gc

keep_high_gc(n=2, inplace=False)

Retain only the n sequences with the highest GC content.

PARAMETER DESCRIPTION
n

Number of sequences with highest GC content to keep (default: 2).

TYPE: int DEFAULT: 2

inplace

If True, replace the current alignment with the filtered alignment. If False, return a new alignment without modifying the original (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
MultipleSeqAlignment

A new alignment containing only the n sequences with highest GC content.

RAISES DESCRIPTION
ValueError

If no alignment is loaded.

Notes

GC content will be calculated for sequences that don't already have it. If inplace=True, this will modify the original alignment in the DeRIP object. If n is greater than the number of sequences, no filtering occurs. If n is less than 2, no filtering occurs to ensure DeRIP has enough sequences to work with.

Strand bias statistics

strand_bias

RIP Strandedness Imbalance (RSI): a per-sequence measure of which strand RIP acted on.

Notes

Background

RIP deaminates the C of a CpA dinucleotide. Read on the forward strand, a reverse-strand CpA appears as TpG, so RIP acting on either strand converts a forward-strand dinucleotide to TpA::

forward substrate   CA  --RIP-->  TA
reverse substrate   TG  --RIP-->  TA

A single round of meiotic RIP acts on one strand of a given duplex, so progeny sequences carry a strand-biased signature: either their CpA sites converted, or their TpG sites converted, rarely both. RSI quantifies that asymmetry.

Definition

For each sequence::

p_fwd = fwd_products / (fwd_products + fwd_substrates)
p_rev = rev_products / (rev_products + rev_substrates)
RSI   = p_fwd - p_rev

RSI lies in [-1, 1]. Positive values indicate RIP predominantly on the forward strand, negative values the reverse strand. Both 0 (no RIP) and 0 (both strands fully converted) are neutral, so RSI must be read alongside its components p_fwd and p_rev, which distinguish the two cases.

Because the proportions are normalised independently per strand, unequal abundances of CpA and TpG substrate motifs do not bias the score.

Substrates versus products

Unmutated substrates (CA, TG) are directly observed in a sequence. Products (TA) must be inferred: a TA is only attributable to RIP when the alignment column shows an aligned, unmutated substrate in some other sequence. The two are therefore counted with different scopes, controlled by substrate_scope.

Counting substrates only inside RIP-classified columns would give a sequence with no RIP at all p_fwd = 0 / 0, when the correct answer is 0.

Ambiguity

A physical TA dinucleotide spans two columns: the T at column i and the A at column j. It is evidence of forward RIP if column i is a forward RIP column (some sequence retains an aligned CA), and evidence of reverse RIP if column j is a reverse RIP column (some sequence retains an aligned TG). When both hold the strand of origin is unrecoverable from the alignment alone. The ambiguous policy decides how such events are attributed; n_ambiguous is always reported so the choice can be audited.

Substrates are never ambiguous: a CA's second base is A (not G) and a TG's first base is T (not C), so neither can be read as the other strand's substrate.

RSIResult dataclass

RSIResult(rsi: ndarray, p_fwd: ndarray, p_rev: ndarray, fwd_prod: ndarray, fwd_sub: ndarray, rev_prod: ndarray, rev_sub: ndarray, n_ambiguous: ndarray, z: ndarray, pvalue: ndarray, ambiguous: str, substrate_scope: str)

Per-sequence RIP strandedness imbalance and its components.

All arrays have shape (n_rows,) and are indexed by alignment row.

ATTRIBUTE DESCRIPTION
rsi

p_fwd - p_rev, in [-1, 1]. NaN when either strand has no evidence.

TYPE: ndarray

p_fwd, p_rev

Proportion of available forward (reverse) substrate sites converted to product. NaN when that strand has neither substrate nor product.

TYPE: ndarray

fwd_prod, rev_prod

Attributed product counts. Fractional under the 'split' and 'weight' policies.

TYPE: ndarray

fwd_sub, rev_sub

Counts of unmutated substrate dinucleotides.

TYPE: ndarray

n_ambiguous

Number of TA dinucleotides attributable to either strand.

TYPE: ndarray

z

Two-proportion z statistic for p_fwd vs p_rev.

TYPE: ndarray

pvalue

Two-sided p-value for the null that RIP struck both strands equally.

TYPE: ndarray

ambiguous

The attribution policy used.

TYPE: str

substrate_scope

The substrate counting scope used.

TYPE: str

pooled

pooled()

Pool counts across all sequences and recompute the imbalance.

Summing the raw counts before taking the ratios weights each sequence by how many informative sites it carries, unlike the mean of the per-row RSI values, which weights every sequence equally regardless of evidence.

RETURNS DESCRIPTION
dict

p_fwd, p_rev, RSI, the four pooled counts, n_ambiguous, z and pvalue for the alignment as a whole. Proportions are NaN when the corresponding denominator is zero.

as_records

as_records(ids=None)

Return the result as a list of per-sequence dictionaries.

PARAMETER DESCRIPTION
ids

Sequence identifiers, one per row. Defaults to row indices.

TYPE: sequence of str DEFAULT: None

RETURNS DESCRIPTION
list of dict

One dictionary per sequence, in alignment order.

compute_rsi

compute_rsi(cls: ColumnClassification, ambiguous: str = 'split', substrate_scope: str = 'all') -> RSIResult

Compute the RIP Strandedness Imbalance for every sequence in an alignment.

PARAMETER DESCRIPTION
cls

Classification produced by :func:derip2.aln_ops.classify_columns.

TYPE: ColumnClassification

ambiguous

How to attribute TA dinucleotides that could have arisen from RIP on either strand (default: 'split').

  • 'split': contribute 0.5 to each strand. Uses all the data and is unbiased when ambiguity is strand-symmetric.
  • 'exclude': drop from both strands. Most conservative; discards the products of heavily RIP'd sequences.
  • 'weight': split in proportion to the evidence, giving the forward strand nC(i) / (nC(i) + nG(j)) where nC(i) is the count of unmutated C at the T's column and nG(j) the count of unmutated G at the A's column.
  • 'both': contribute 1.0 to each strand. Keeps counts integral but inflates both proportions toward 1.

TYPE: (split, exclude, weight, both) DEFAULT: 'split'

substrate_scope

Which unmutated substrate dinucleotides enter the denominators (default: 'all').

  • 'all': every observed CA and TG in the sequence. Substrates are directly observed and need no column-level inference.
  • 'assessable': only those in columns passing the max_snp_noise gate. Matches the scope of markupdict['rip_substrate'].
  • 'rip_like_columns': only those in columns that also contain a product. Symmetric with the product scope, but yields NaN for sequences with no RIP.

TYPE: (all, assessable, rip_like_columns) DEFAULT: 'all'

RETURNS DESCRIPTION
RSIResult

Per-sequence RSI, components, ambiguity counts and significance.

RAISES DESCRIPTION
ValueError

If ambiguous or substrate_scope is not a recognised option.

Notes

Products are always counted only within RIP columns (fwd_col / rev_col), because a TA can only be attributed to RIP when an aligned sequence retains the unmutated substrate.

A denominator of zero yields NaN rather than 0: a strand with neither substrate nor product carries no evidence, and reporting 0 would disguise "no data" as "perfectly one-sided".

Examples:

>>> from derip2.aln_ops import classify_alignment
>>> from derip2.stats import compute_rsi
>>> cls = classify_alignment(alignment)
>>> res = compute_rsi(cls, ambiguous='split')
>>> res.rsi
array([ 1.0, -1.0,  0.0])

RIP column classification

aln_ops

Alignment operations for deRIP2.

This module provides functions for manipulating and analyzing DNA sequence alignments, with a focus on detecting and correcting RIP (Repeat-Induced Point mutation) mutations. It includes utilities for loading alignments, tracking RIP-like mutations, building consensus sequences, and outputting corrected sequences in various formats.

ColumnClassification dataclass

ColumnClassification(arr: ndarray, next_idx: ndarray, prev_idx: ndarray, ca: ndarray, ta: ndarray, tg: ndarray, ta2: ndarray, ct_ok: ndarray, ga_ok: ndarray, fwd_block: ndarray, rev_block: ndarray, fwd_col: ndarray, rev_col: ndarray, modC: ndarray, modG: ndarray, base_counts: ndarray, reaminate: bool)

Per-cell and per-column classification of RIP context across an alignment.

This is the single source of truth for "which cells are RIP substrate, product, or non-RIP deamination, and on which strand". Both the consensus correction (:func:apply_classification) and the strand-bias statistics consume it, so the two can never disagree.

RIP deaminates the C of a CpA dinucleotide. Read on the forward strand a reverse-strand CpA appears as TpG, so RIP on either strand yields a forward strand TpA::

Target strand:    ++  --
Wild type:     5' CA--TG 3'
RIP mutated:   5' TA--TA 3'

Dinucleotides are defined per row over the nearest non-gap neighbour, so a C-A spanning a gap column is still a CpA substrate.

ATTRIBUTE DESCRIPTION
arr

(n_rows, n_cols) byte array of the alignment, dtype 'S1'.

TYPE: ndarray

next_idx, prev_idx

(n_rows, n_cols) int arrays giving the column index of the closest non-gap base to the right / left of each cell (-1 if none).

TYPE: ndarray

ca, ta, tg, ta2

(n_rows, n_cols) boolean masks of the four dinucleotide contexts: ca = C followed by A (forward substrate), ta = T followed by A (forward product candidate), tg = G preceded by T (reverse substrate), ta2 = A preceded by T (reverse product candidate).

TYPE: ndarray

ct_ok, ga_ok

(n_cols,) boolean. Column has enough C/T (or G/A) content to be assessed, i.e. proportion of non-gap bases >= max_snp_noise.

TYPE: ndarray

fwd_block, rev_block

(n_cols,) boolean. Column is a candidate for forward (reverse) correction: gate passed, strand is the majority, and both the substrate and product bases occur somewhere in the column.

TYPE: ndarray

fwd_col, rev_col

(n_cols,) boolean. Column shows both an unmutated substrate dinucleotide and a product dinucleotide, so a product observed here can be attributed to RIP. These are the "RIP columns" used by the strand-bias statistics.

TYPE: ndarray

modC, modG

(n_cols,) boolean. Column's consensus base is corrected to the ancestral C (G).

TYPE: ndarray

base_counts

(n_cols, 5) int64 counts of A, C, G, T, - per column.

TYPE: ndarray

reaminate

Whether non-RIP-context deaminations are also corrected.

TYPE: bool

Notes

fwd_col requires at least one surviving CA somewhere in the column. A column in which every row has been converted to TA therefore cannot be recognised as a RIP column: with no ancestral C left in any sequence, the alignment carries no evidence that the column was ever CpA. RIP is only visible where at least one sibling sequence escaped it.

nA property

nA: ndarray

Per-column count of A bases.

RETURNS DESCRIPTION
ndarray

(n_cols,) int array.

nC property

nC: ndarray

Per-column count of C bases.

RETURNS DESCRIPTION
ndarray

(n_cols,) int array.

nG property

nG: ndarray

Per-column count of G bases.

RETURNS DESCRIPTION
ndarray

(n_cols,) int array.

nT property

nT: ndarray

Per-column count of T bases.

RETURNS DESCRIPTION
ndarray

(n_cols,) int array.

n_gap property

n_gap: ndarray

Per-column count of gap characters.

RETURNS DESCRIPTION
ndarray

(n_cols,) int array.

base_count property

base_count: ndarray

Per-column count of unambiguous ACGT bases.

RETURNS DESCRIPTION
ndarray

(n_cols,) int array. IUPAC ambiguity codes are excluded.

sub_fwd property

sub_fwd: ndarray

Forward RIP substrate cells: C in CpA context, in assessable columns.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

sub_rev property

sub_rev: ndarray

Reverse RIP substrate cells: G in TpG context, in assessable columns.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

prod_fwd property

prod_fwd: ndarray

Forward RIP product cells: T in TpA context, in forward RIP columns.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

prod_rev property

prod_rev: ndarray

Reverse RIP product cells: A in TpA context, in reverse RIP columns.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

nonrip_fwd property

nonrip_fwd: ndarray

T cells in a forward candidate column that are not RIP products.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

nonrip_rev property

nonrip_rev: ndarray

A cells in a reverse candidate column that are not RIP products.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

mask_Y property

mask_Y: ndarray

Mask of cells overwritten with the IUPAC code Y (C/T) in the masked alignment.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

mask_R property

mask_R: ndarray

Mask of cells overwritten with the IUPAC code R (A/G) in the masked alignment.

RETURNS DESCRIPTION
ndarray

(n_rows, n_cols) boolean mask.

add_fwd property

add_fwd: ndarray

Per-row count of forward-strand RIP events.

RETURNS DESCRIPTION
ndarray

(n_rows,) int array.

add_rev property

add_rev: ndarray

Per-row count of reverse-strand RIP events.

RETURNS DESCRIPTION
ndarray

(n_rows,) int array.

add_nonrip property

add_nonrip: ndarray

Per-row count of non-RIP deamination events.

RETURNS DESCRIPTION
ndarray

(n_rows,) int array.

corrected_positions property

corrected_positions: List[int]

Column indices whose consensus base was corrected.

RETURNS DESCRIPTION
list of int

Ascending column indices.

classify_columns

classify_columns(arr: ndarray, next_idx: ndarray, prev_idx: ndarray, max_snp_noise: float = 0.5, min_rip_like: float = 0.1, reaminate: bool = False, block_size: Optional[int] = None, progress: bool = True) -> ColumnClassification

Classify every cell and column of an alignment by RIP context.

This is a vectorised reformulation of the per-column scan that :func:correctRIP used to perform, and reproduces its decisions exactly. Forward-strand RIP (C→T in CpA context) and reverse-strand RIP (G→A in TpG context) are detected independently.

A column is assessed on the forward strand when its C+T bases make up at least max_snp_noise of the non-gap bases, and is a correction candidate only when C/T is the strict majority over G/A. Because every non-gap base falls in exactly one of the C/T and G/A pairs, the two proportions sum to one, so the strict inequality makes forward and reverse correction mutually exclusive. A column can never be corrected on both strands, and the Y/R masks can never collide.

PARAMETER DESCRIPTION
arr

(n_rows, n_cols) byte array of the alignment, dtype 'S1', as produced by :func:alignment_to_array.

TYPE: ndarray

next_idx

Non-gap neighbour indices from :func:_nongap_neighbors.

TYPE: ndarray

prev_idx

Non-gap neighbour indices from :func:_nongap_neighbors.

TYPE: ndarray

max_snp_noise

Minimum proportion of a column's non-gap bases that must be C/T (or G/A) for that strand to be assessed (default: 0.5).

TYPE: float DEFAULT: 0.5

min_rip_like

Minimum proportion of a column's C/T (or G/A) bases that must sit in RIP dinucleotide context before the column is corrected (default: 0.1).

TYPE: float DEFAULT: 0.1

reaminate

If True, correct C→T and G→A transitions outside RIP context too (default: False).

TYPE: bool DEFAULT: False

block_size

Number of columns processed per block. Blocking bounds peak memory and is bit-identical to processing the whole array at once, because every reduction is within a single column and neighbour gathers index the full array. Defaults to a width chosen from a 64 MiB budget.

TYPE: int DEFAULT: None

progress

Show a progress bar when more than one block is processed (default: True).

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
ColumnClassification

Cell masks, column flags, and per-column base counts.

Notes

Cell classification (substrate / product / non-RIP) and the per-row tallies depend only on max_snp_noise; min_rip_like and reaminate affect only whether a column's consensus base is corrected and masked.

classify_alignment

classify_alignment(align: MultipleSeqAlignment, max_snp_noise: float = 0.5, min_rip_like: float = 0.1, reaminate: bool = False, block_size: Optional[int] = None, progress: bool = True) -> ColumnClassification

Convenience wrapper: decode an alignment and classify its RIP context.

PARAMETER DESCRIPTION
align

The alignment to classify.

TYPE: MultipleSeqAlignment

max_snp_noise

See :func:classify_columns (default: 0.5).

TYPE: float DEFAULT: 0.5

min_rip_like

See :func:classify_columns (default: 0.1).

TYPE: float DEFAULT: 0.1

reaminate

See :func:classify_columns (default: False).

TYPE: bool DEFAULT: False

block_size

See :func:classify_columns.

TYPE: int DEFAULT: None

progress

See :func:classify_columns (default: True).

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
ColumnClassification

Classification of the alignment.

apply_classification

apply_classification(align: MultipleSeqAlignment, tracker: Dict[int, NamedTuple], RIPcounts: Dict[int, NamedTuple], cls: ColumnClassification) -> Tuple[Dict[int, NamedTuple], Dict[int, NamedTuple], AlignIO.MultipleSeqAlignment, List[int], Dict[str, List[RIPPosition]]]

Apply a column classification to the consensus tracker, counters and mask.

PARAMETER DESCRIPTION
align

The alignment the classification was computed from; supplies record metadata for the rebuilt masked alignment.

TYPE: MultipleSeqAlignment

tracker

Consensus tracker keyed by column index. Not mutated.

TYPE: Dict[int, NamedTuple]

RIPcounts

Per-sequence RIP counters keyed by row index. Not mutated.

TYPE: Dict[int, NamedTuple]

cls

Classification produced by :func:classify_columns.

TYPE: ColumnClassification

RETURNS DESCRIPTION
Tuple

(tracker, RIPcounts, maskedAlign, corrected_positions, markupdict).

Strand bias plotting

strandbias

Diverging stacked-bar figures of per-column RIP strand bias.

Each alignment column that carries RIP signal becomes one bar. The bar is drawn above the axis when the deamination is observed on the forward strand (C→T in CpA context) and below when it is observed on the reverse strand (G→A, seen on the forward strand as the loss of a TpG).

A bar therefore sits at the column where the deaminated base itself lies. A forward event is scored at the C's column; the reverse event of the same duplex is scored at the G's column, one position to the right. Bars for a single physical TpA dinucleotide can consequently appear in adjacent columns on opposite sides of the axis — this is the strand ambiguity, made visible.

Within a bar the RIP product segment is drawn against the zero line and the unmutated substrate stacks outward. Every product segment therefore shares a common baseline, so the extent of RIP can be compared across columns at a glance.

plot_strand_bias

plot_strand_bias(cls, outfile=None, mode='rip', scale='column', stack='signal', xaxis='none', color_by='base', columns='all', column_range=None, consensus_seq=None, title=None, width=None, height=4.2, dpi=300, max_columns=None, emphasis=True, ax=None)

Draw a diverging stacked-bar chart of per-column RIP strand bias.

PARAMETER DESCRIPTION
cls

Classification produced by :func:derip2.aln_ops.classify_columns.

TYPE: ColumnClassification

outfile

Path to write the figure to; format inferred from the extension. Use .svg or .pdf for publication. If None, nothing is written.

TYPE: str DEFAULT: None

mode

Which deamination events to display (default: 'rip').

TYPE: (rip, non_rip, all_deamination) DEFAULT: 'rip'

scale

Bar height normalisation (default: 'column').

TYPE: (column, alignment, counts) DEFAULT: 'column'

stack

Which bases the bar is made of (default: 'signal'). 'signal' stacks the RIP product and its unmutated substrate; 'product' draws the product alone; 'all' adds every remaining base as a translucent noise segment. The bar is never rescaled, so the missing height honestly shows how much of the column was excluded.

TYPE: (signal, product, all) DEFAULT: 'signal'

xaxis

Decoration drawn in the gutter around the zero line: nothing, a sequence logo, or the deRIP'd consensus base (default: 'none'). When set, the bars are offset from the zero line so the lettering is never obscured.

TYPE: (none, logo, derip) DEFAULT: 'none'

color_by

Colour segments by nucleotide identity or by the role the base plays (default: 'base').

TYPE: (base, role) DEFAULT: 'base'

columns

Which positions are lettered when xaxis is 'logo' or 'derip' (default: 'all'). Every column is drawn as a bar whatever this is set to. 'rip' letters the RIP-like columns and the partner base of each motif; 'substrate' letters only untouched substrate columns and their partners.

TYPE: (rip, substrate, all) DEFAULT: 'rip'

column_range

(start, end) half-open alignment column range to restrict the plot to. Use this to zoom into a region of a large alignment.

TYPE: tuple of int DEFAULT: None

consensus_seq

Gapped deRIP'd consensus, required when xaxis='derip'.

TYPE: str DEFAULT: None

title

Figure title. Defaults to a description of the mode.

TYPE: str DEFAULT: None

width

Figure width in inches. Defaults to a width scaled to the column count, with no upper bound short of the matplotlib canvas limit.

TYPE: float DEFAULT: None

height

Figure height in inches (default: 4.2).

TYPE: float DEFAULT: 4.2

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

max_columns

Refuse to draw more than this many bars. Unset by default: long alignments are drawn in full, on the assumption that the output is vector and can be zoomed.

TYPE: int DEFAULT: None

emphasis

Wash the columns in which the current mode observed a transition, and fade the bars and letters of the columns that merely provide context (default: True).

TYPE: bool DEFAULT: True

ax

Draw into an existing axes instead of creating a figure.

TYPE: Axes DEFAULT: None

RETURNS DESCRIPTION
Figure

The figure containing the chart.

RAISES DESCRIPTION
ValueError

If an option is unrecognised, if xaxis='derip' without a consensus, or if max_columns is set and more columns would be drawn.

Notes

Bars above the axis are forward-strand columns; bars below are reverse-strand columns. Columns where neither strand holds a majority carry no correction and are marked with a hatched band rather than dropped silently.

Examples:

>>> from derip2.aln_ops import classify_alignment
>>> cls = classify_alignment(alignment)
>>> plot_strand_bias(cls, outfile='bias.svg')

report

Self-contained HTML report of a deRIP2 strand-bias analysis.

Figures are embedded as inline SVG rather than linked or base64-encoded raster images: the report stays a single file, the figures remain vector (so they can be zoomed or lifted straight into a manuscript), and no external asset is ever fetched.

write_html_report

write_html_report(derip, output_file, title=None, ambiguous='split', **kwargs)

Write a single-file HTML report of the strand-bias analysis.

PARAMETER DESCRIPTION
derip

A DeRIP object on which calculate_rip() has already been run.

TYPE: DeRIP

output_file

Destination path.

TYPE: str

title

Report heading. Defaults to 'deRIP2 strand bias report'.

TYPE: str DEFAULT: None

ambiguous

Ambiguity policy used for RSI (default: 'split').

TYPE: (split, exclude, weight, both) DEFAULT: 'split'

**kwargs

Forwarded to each figure, e.g. scale, xaxis, columns.

DEFAULT: {}

RETURNS DESCRIPTION
str

The path written.

Notes

Panels that cannot be drawn — for instance because a max_columns limit was passed and exceeded — are reported inline as a note rather than aborting the report.

Per-sequence reporting

persequence

Single-sequence figures for the per-sequence HTML report.

These render one alignment row at a time, in the same visual system as the alignment-wide strand-bias chart (:mod:derip2.plotting.strandbias): the same colourblind-validated palette, typography and light publication surface, so the per-sequence report reads as one document with the rest of the package.

Two figures are provided:

  • :func:per_sequence_strand_bias — a fixed-height binary bar strip showing, for one sequence, which RIP-like columns carry a forward-strand event (above the axis) or a reverse-strand event (below), coloured by whether the base is the RIP product or the surviving substrate.
  • :func:sequence_row_strip — the subject and deRIP'd reference rows drawn base-by-base, with RIP-like columns shaded as in the alignment-wide plot.
  • :func:rip_completion_bar / :func:gc_content_bar — small horizontal stacked-bar summaries.

All return the matplotlib figure so the report can embed it as inline SVG.

per_sequence_strand_bias

per_sequence_strand_bias(cls, row_index: int, *, seq_id: Optional[str] = None, title: Optional[str] = None, height: float = 2.2, width: Optional[float] = None, dpi: int = 300, outfile: Optional[str] = None, ax=None)

Draw a fixed-height binary strand-bias strip for a single sequence.

Every RIP-like column that this sequence participates in becomes one bar of unit height. A forward-strand event is drawn above the axis, a reverse-strand event below it, and the bar is coloured by the role the sequence's base plays: the RIP product (the deaminated base) or the surviving substrate.

Because a cell holds one base, each column contributes at most one bar: a forward product (T of TpA), a forward substrate (C of CpA), a reverse product (A of TpA) or a reverse substrate (G of TpG). The four are mutually exclusive per cell, so the strip is unambiguous.

PARAMETER DESCRIPTION
cls

Classification of the whole alignment; only row row_index is read.

TYPE: ColumnClassification

row_index

Index of the sequence (alignment row) to plot.

TYPE: int

seq_id

Sequence identifier, used in the default title.

TYPE: str DEFAULT: None

title

Figure title. Defaults to a description naming seq_id.

TYPE: str DEFAULT: None

height

Figure height in inches (default: 2.2).

TYPE: float DEFAULT: 2.2

width

Figure width in inches. Defaults to a width scaled to the number of columns (:func:derip2.plotting.strandbias._figure_width); pass an explicit value to control bar density for a scrolling container.

TYPE: float DEFAULT: None

dpi

Raster resolution when outfile is a raster path (default: 300).

TYPE: int DEFAULT: 300

outfile

Path to write the figure to. When None the figure is returned unsaved.

TYPE: str DEFAULT: None

ax

Existing axes to draw on. When given, no new figure is created and outfile is ignored.

TYPE: Axes DEFAULT: None

RETURNS DESCRIPTION
Figure

The figure the strip was drawn on.

sequence_row_strip

sequence_row_strip(cls, row_index: int, *, seq_id: Optional[str] = None, consensus_seq: Optional[str] = None, cds_tracks=None, title: Optional[str] = None, height: float = 1.0, width: Optional[float] = None, dpi: int = 300, outfile: Optional[str] = None)

Draw the subject and deRIP'd reference rows as base-coloured strips.

Both aligned sequences are drawn base-by-base, coloured by nucleotide identity with the shared palette (A green, C blue, G violet, T red; gaps white). The subject is drawn on top and the reconstructed deRIP'd reference below it, separated by a narrow gap. Triangle markers above the subject flag its role at each column, and columns the whole-alignment strand-bias analysis marks as RIP-like — those carrying a RIP product on either strand anywhere in the alignment — are shaded with the same hueless wash used by :func:derip2.plotting.strandbias.plot_strand_bias.

PARAMETER DESCRIPTION
cls

Classification of the whole alignment; row row_index is the subject.

TYPE: ColumnClassification

row_index

Index of the subject sequence (alignment row) to draw.

TYPE: int

seq_id

Subject sequence identifier, used to label its row.

TYPE: str DEFAULT: None

consensus_seq

The deRIP'd reference (one base per column), drawn as the second row.

TYPE: str DEFAULT: None

cds_tracks

Gene-annotation tracks to draw in a sub-plot below the alignment rows, each (exon_spans, strand, stop_columns, label, colour): the per-exon (start_col, end_col) spans (drawn as rounded segments with an arrowhead at the strand 3' end and joined across introns by a midline), this subject's stop-codon columns (marked * above the track), a row label and a hex colour.

TYPE: list of tuple DEFAULT: None

title

Figure title. Untitled by default (the report supplies a heading).

TYPE: str DEFAULT: None

height

Figure height in inches (default: 1.0).

TYPE: float DEFAULT: 1.0

width

Figure width in inches. Defaults to a width scaled to the number of columns; pass an explicit value to match the strand-bias strip so the two line up column-for-column in a scrolling container.

TYPE: float DEFAULT: None

dpi

Raster resolution when outfile is a raster path (default: 300).

TYPE: int DEFAULT: 300

outfile

Path to write the figure to. When None the figure is returned unsaved.

TYPE: str DEFAULT: None

RETURNS DESCRIPTION
Figure

The figure the strip was drawn on.

rip_completion_bar

rip_completion_bar(stats, *, title: Optional[str] = None, width: float = 6.6, height: float = 1.7, dpi: int = 300, outfile: Optional[str] = None)

Draw horizontal stacked bars of the fraction of RIP-like sites that are RIP'd.

For each strand, the available RIP-like sites are the surviving substrate dinucleotides plus the RIP products (converted sites). The bar shows what fraction of that substrate has been converted — the RIP product segment — against the intact substrate, so a nearly full blue bar is a heavily RIP'd strand and a nearly empty one has escaped RIP.

Three bars are drawn: forward, reverse and the two combined.

PARAMETER DESCRIPTION
stats

A per-sequence statistics row exposing fwd_product, fwd_substrate, rev_product and rev_substrate (as produced by :meth:derip2.derip.DeRIP.summarize_stats).

TYPE: Mapping

title

Figure title.

TYPE: str DEFAULT: None

width

Figure size in inches. Fixed by default so the bars line up across the per-sequence report's pages.

TYPE: float DEFAULT: 6.6

height

Figure size in inches. Fixed by default so the bars line up across the per-sequence report's pages.

TYPE: float DEFAULT: 6.6

dpi

Raster resolution when outfile is a raster path (default: 300).

TYPE: int DEFAULT: 300

outfile

Path to write the figure to. When None the figure is returned unsaved.

TYPE: str DEFAULT: None

RETURNS DESCRIPTION
Figure

The figure the bars were drawn on.

gc_content_bar

gc_content_bar(stats, *, title: Optional[str] = None, width: float = 6.6, height: float = 1.0, dpi: int = 300, outfile: Optional[str] = None)

Draw a horizontal stacked bar of this sequence's GC content.

The bar is split into the G+C fraction (filled) and the A+T remainder, with the percentage labelled. RIP lowers GC by converting C to T, so a low bar is consistent with heavy RIP.

PARAMETER DESCRIPTION
stats

A per-sequence statistics row exposing GC (a percentage in [0, 100]), as produced by :meth:derip2.derip.DeRIP.summarize_stats.

TYPE: Mapping

title

Figure title.

TYPE: str DEFAULT: None

width

Figure size in inches. Fixed by default so the bar lines up across pages.

TYPE: float DEFAULT: 6.6

height

Figure size in inches. Fixed by default so the bar lines up across pages.

TYPE: float DEFAULT: 6.6

dpi

Raster resolution when outfile is a raster path (default: 300).

TYPE: int DEFAULT: 300

outfile

Path to write the figure to. When None the figure is returned unsaved.

TYPE: str DEFAULT: None

RETURNS DESCRIPTION
Figure

The figure the bar was drawn on.

resolve_cmap

resolve_cmap(cmap=None)

Coerce a user-supplied colormap specification to a matplotlib colormap.

Lets callers restyle the conversion heatmap without importing matplotlib: a name selects any registered colormap (append _r to reverse it), a list of colours builds a custom ramp, and a colormap object is taken as given. In every case the "no data" colour is set to :data:NO_DATA_COLOR, so empty cells stay consistent with the rest of the report whatever palette is in use.

PARAMETER DESCRIPTION
cmap

One of:

  • None (default) -- the package default, :data:CONVERSION_CMAP.
  • a registered matplotlib colormap name, e.g. 'coolwarm', 'magma_r', 'viridis'.
  • a :class:~matplotlib.colors.Colormap instance.
  • a sequence of two or more matplotlib colours (hex strings, named colours or RGB(A) tuples), interpolated into a continuous ramp in the order given, low value first.

TYPE: str or Colormap or sequence DEFAULT: None

RETURNS DESCRIPTION
Colormap

The resolved colormap, with its "bad" (no-data) colour set.

RAISES DESCRIPTION
ValueError

If cmap names a colormap matplotlib does not know, is a sequence of fewer than two colours, or contains a value that is not a valid colour.

TypeError

If cmap is not one of the accepted types.

Examples:

>>> resolve_cmap('magma_r').name
'magma_r'
>>> resolve_cmap(['#ffffff', '#2a78d6']).name
'derip2_custom'

text_color_on

text_color_on(rgb)

Pick black or white text for maximum contrast against a background colour.

Uses the WCAG relative luminance (a linearised, weighted sum of the channels) rather than the gamma-encoded approximation, so the choice matches what the contrast standard would score.

PARAMETER DESCRIPTION
rgb

Background colour as (r, g, b) (or (r, g, b, a); alpha is ignored), each channel in [0, 1].

TYPE: sequence of float

RETURNS DESCRIPTION
str

'white' on dark backgrounds, 'black' on light ones.

persequence_report

Self-contained, interactive per-sequence HTML report.

Where :mod:derip2.report gives one alignment-wide view of strand bias, this module gives one panel per input sequence: the alignment row with its RIP sites highlighted, a fixed-height per-sequence strand-bias strip, a per-sequence SBS-96 mutation spectrum measured against the reconstructed ancestor, and that sequence's summary statistics. The panels are stacked in a single HTML file and shown one at a time; the reader steps between sequences with the arrow keys or the prev/next buttons.

As with :mod:derip2.report, every figure is embedded as inline SVG so the report is a single self-contained file with no external assets. Each figure is given a unique ID prefix (s{row}{kind}-) because matplotlib reuses element IDs across figures and a browser resolves href="#id" to the first match in the document — without unique prefixes, later figures would borrow the first figure's glyphs.

write_per_sequence_report

write_per_sequence_report(derip, output_file, *, title=None, ambiguous='split', max_seqs=None, gff=None, genetic_code=1, spectra_ref_index=None, flank_length=1)

Write a single-file, arrow-key-navigable per-sequence HTML report.

PARAMETER DESCRIPTION
derip

A DeRIP object on which calculate_rip() has already been run.

TYPE: DeRIP

output_file

Destination path.

TYPE: str

title

Report heading. Defaults to 'deRIP2 per-sequence report'.

TYPE: str DEFAULT: None

ambiguous

Ambiguity policy used for the per-sequence RSI statistics (default: 'split').

TYPE: (split, exclude, weight, both) DEFAULT: 'split'

max_seqs

Cap the number of sequence panels. When the alignment has more sequences than this, the first max_seqs rows in alignment order are kept and a truncation note is shown; sort or filter the alignment first (e.g. :meth:derip2.derip.DeRIP.sort_by_rsi) to change which sequences those are. None (default) renders every sequence.

TYPE: int DEFAULT: None

gff

Path to a GFF3 gene model. When given, each annotated sequence's panel gains a gene-effect table and the deRIP-restored protein.

TYPE: str DEFAULT: None

genetic_code

NCBI translation table for the effect prediction (default: 1).

TYPE: int DEFAULT: 1

spectra_ref_index

Alignment row index of a sequence to use as the reference for the mutation spectra (per-sequence and the pooled overview), instead of the default deRIP-corrected consensus. Supports negative indexing. The reference sequence's own panel then shows an empty (self-comparison) spectrum.

TYPE: int DEFAULT: None

flank_length

Number of flanking bases each side of a RIP-like dinucleotide for the flank-context spectra and conversion heatmap (default 1 → 4×4 grid; 2 → 16×16).

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
str

The path written.

RAISES DESCRIPTION
ValueError

If spectra_ref_index is out of range for the alignment.

Notes

Rendering hundreds of sequences produces hundreds of inline-SVG figures and a correspondingly large file; max_seqs is the recommended mitigation for large alignments.

Gene annotation and RIP effect prediction

annotation

GFF3 gene annotation and RIP effect prediction over a gapped alignment.

deRIP2 reconstructs an un-RIP'd ancestral sequence for a family of aligned repeats. When a gene model is supplied for one or more of those sequences, this module answers a follow-on question: what did RIP do to the protein? It

  1. parses a GFF3 file into per-sequence genes (:func:parse_gff3),
  2. maps each gene's ungapped coordinates onto gapped alignment columns (:func:ungapped_to_column_map), so a feature lines up with the alignment, and
  3. translates each sequence's CDS and compares it to the reconstructed ancestor, reporting premature stops, non-synonymous changes, frameshifts and broken splice sites (:func:predict_gene_effects, :func:translate_cds).

GFF3 coordinates are 1-based and inclusive, in the ungapped sequence's own frame; the alignment is gapped. The coordinate map is the bridge between the two.

No new dependency is introduced: GFF3 is parsed with the standard library and translation uses Biopython's :meth:Bio.Seq.Seq.translate, already a project dependency. The genetic code defaults to the NCBI standard table (1) and is configurable for organisms that use an alternate code.

Gene dataclass

Gene(gene_id: str, seqid: str, strand: str, cds: List[Feature] = list())

A gene grouped to its coding exons, in transcription order via strand.

ATTRIBUTE DESCRIPTION
gene_id

Identifier for the gene / transcript the CDS features belong to.

TYPE: str

seqid

Sequence identifier, matched against alignment record IDs.

TYPE: str

strand

'+' or '-'.

TYPE: str

cds

CDS features, sorted by start ascending (forward-strand order). The transcription order is derived from strand when the CDS is assembled.

TYPE: list of Feature

Feature dataclass

Feature(seqid: str, ftype: str, start: int, end: int, strand: str, phase: Optional[int], attributes: Dict[str, str], feature_id: Optional[str], parent: Optional[str])

One GFF3 feature line, coordinates 1-based inclusive on the forward strand.

ATTRIBUTE DESCRIPTION
seqid

Sequence identifier; matched against alignment record IDs.

TYPE: str

ftype

Feature type ('gene', 'mRNA', 'CDS', 'exon', ...).

TYPE: str

start, end

1-based inclusive bounds in the ungapped sequence's own coordinates.

TYPE: int

strand

'+' or '-' ('.' is treated as '+').

TYPE: str

phase

CDS phase (0, 1 or 2) where given, else None.

TYPE: int or None

attributes

Parsed column-9 key/value attributes.

TYPE: dict of str to str

feature_id

The ID attribute, if present.

TYPE: str or None

parent

The Parent attribute, if present.

TYPE: str or None

EffectRecord dataclass

EffectRecord(seq_id: str, gene_id: str, kind: str, aa_pos: Optional[int] = None, ref_aa: Optional[str] = None, alt_aa: Optional[str] = None, gapped_col: Optional[int] = None, nt_ref: Optional[str] = None, nt_alt: Optional[str] = None)

One predicted effect of RIP on a sequence's coding sequence.

ATTRIBUTE DESCRIPTION
seq_id

The sequence the effect was found in.

TYPE: str

gene_id

The gene / transcript affected.

TYPE: str

kind

One of 'missense', 'premature_stop', 'frameshift', 'splice_site' or 'synonymous'.

TYPE: str

aa_pos

1-based amino-acid position of the change (None for whole-CDS effects such as frameshifts).

TYPE: int or None

ref_aa, alt_aa

Ancestral and observed amino acid (or splice dinucleotide) at the site.

TYPE: str or None

gapped_col

Alignment column of the affected codon's middle base (or the splice site), for cross-referencing the figures.

TYPE: int or None

nt_ref, nt_alt

Ancestral and observed nucleotide context, where meaningful.

TYPE: str or None

parse_gff3

parse_gff3(path: str) -> Dict[str, List[Gene]]

Parse a GFF3 file into genes grouped by sequence identifier.

CDS features are grouped by their Parent (falling back to the mRNA/gene ID or a synthesised key) and sorted into forward-strand order. Only the gene hierarchy is retained; other feature types are ignored.

PARAMETER DESCRIPTION
path

Path to the GFF3 file.

TYPE: str

RETURNS DESCRIPTION
dict of str to list of Gene

Mapping of sequence identifier to its genes, in first-seen order.

RAISES DESCRIPTION
ValueError

If a coordinate field is not an integer or start > end.

Notes

A gene whose CDS features disagree on strand is dropped with a warning: a single transcript cannot be transcribed from both strands.

ungapped_to_column_map

ungapped_to_column_map(row_bytes: ndarray) -> np.ndarray

Map a sequence's ungapped positions to their gapped alignment columns.

PARAMETER DESCRIPTION
row_bytes

A single alignment row as an 'S1' byte array (one entry per column), e.g. ColumnClassification.arr[row_index].

TYPE: ndarray

RETURNS DESCRIPTION
ndarray

Int array where element u is the column index of the u-th non-gap base. Its length equals the ungapped sequence length, so a 1-based GFF coordinate pos maps to column result[pos - 1].

predict_gene_effects

predict_gene_effects(gene: Gene, target_row: ndarray, ref_row: ndarray, ungapped_to_col: ndarray, *, seq_id: str = '', genetic_code: int = 1, include_synonymous: bool = False) -> List[EffectRecord]

Predict the coding effects of RIP on one sequence, versus the ancestor.

The gene's CDS is assembled in transcription order for both the observed sequence (target_row) and the reconstructed ancestor (ref_row), translated, and compared codon by codon. Length differences that are not a multiple of three are reported as frameshifts; canonical splice boundaries broken in the target are reported as splice-site effects.

PARAMETER DESCRIPTION
gene

The gene to evaluate.

TYPE: Gene

target_row

The observed and ancestral alignment rows ('S1' byte arrays). Both must be indexed by the same columns, i.e. drawn from the same alignment.

TYPE: ndarray

ref_row

The observed and ancestral alignment rows ('S1' byte arrays). Both must be indexed by the same columns, i.e. drawn from the same alignment.

TYPE: ndarray

ungapped_to_col

The observed sequence's ungapped-to-column map, used to place the CDS.

TYPE: ndarray

seq_id

Identifier stamped onto each returned record.

TYPE: str DEFAULT: ''

genetic_code

NCBI translation table (default: 1).

TYPE: int DEFAULT: 1

include_synonymous

Also emit 'synonymous' records (default: False; usually noise).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
list of EffectRecord

Effects in codon order, splice-site effects appended.

translate_cds

translate_cds(gene: Gene, row_bytes: ndarray, ungapped_to_col: ndarray, genetic_code: int = 1) -> str

Translate one sequence's CDS for a gene, rendering stops as '*'.

PARAMETER DESCRIPTION
gene

The gene to translate.

TYPE: Gene

row_bytes

The sequence's alignment row ('S1' byte array).

TYPE: ndarray

ungapped_to_col

The sequence's ungapped-to-column map.

TYPE: ndarray

genetic_code

NCBI translation table (default: 1, the standard code).

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
str

The amino-acid sequence, '*' for each stop codon. Empty if the CDS could not be mapped.

compute_effects_for_alignment

compute_effects_for_alignment(derip, genes_by_seqid: Dict[str, List[Gene]], genetic_code: int = 1) -> Dict[str, List[EffectRecord]]

Predict RIP effects for every annotated sequence in a DeRIP alignment.

Each gene is evaluated against the reconstructed ancestor (deRIP2's gapped consensus). Genes whose sequence identifier is not in the alignment are skipped.

PARAMETER DESCRIPTION
derip

A DeRIP object on which calculate_rip() has run.

TYPE: DeRIP

genes_by_seqid

Parsed genes keyed by sequence identifier.

TYPE: dict of str to list of Gene

genetic_code

NCBI translation table (default: 1).

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
dict of str to list of EffectRecord

Effects keyed by sequence identifier (only sequences with a gene and at least one effect appear).

deripd_translations

deripd_translations(derip, genes_by_seqid: Dict[str, List[Gene]], genetic_code: int = 1) -> Dict[str, str]

Translate each gene's CDS on the reconstructed deRIP'd sequence.

Columns are taken from the gene's owning sequence, but the bases are read from the deRIP'd consensus, so the returned protein is what the restored (un-RIP'd) coding sequence encodes.

PARAMETER DESCRIPTION
derip

A DeRIP object on which calculate_rip() has run.

TYPE: DeRIP

genes_by_seqid

Parsed genes keyed by sequence identifier.

TYPE: dict of str to list of Gene

genetic_code

NCBI translation table (default: 1).

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
dict of str to str

Gene identifier to amino-acid string ('*' for stops).

write_snp_effects

write_snp_effects(output_file: str, effects_by_seq: Dict[str, List[EffectRecord]], deripd_aa: Dict[str, str]) -> str

Write a tab-separated summary of RIP coding effects.

PARAMETER DESCRIPTION
output_file

Destination path.

TYPE: str

effects_by_seq

Per-sequence effects (:func:compute_effects_for_alignment).

TYPE: dict of str to list of EffectRecord

deripd_aa

Per-gene deRIP'd translations (:func:deripd_translations).

TYPE: dict of str to str

RETURNS DESCRIPTION
str

The path written.

build_annotation_spans

build_annotation_spans(genes_by_seqid: Dict[str, List[Gene]], row_lookup: Dict[str, ndarray], colors: Optional[Dict[str, str]] = None) -> List[Tuple[int, int, str, str, int]]

Project gene CDS exons onto alignment columns as stacked track spans.

Each gene occupies its own track row; its CDS exons are drawn as separate coloured spans (gaps split an exon into contiguous column runs). The result is ready to pass to :func:derip2.plotting.minialign.drawMiniAlignment as annotation_track.

PARAMETER DESCRIPTION
genes_by_seqid

Parsed genes keyed by sequence identifier.

TYPE: dict of str to list of Gene

row_lookup

Maps each sequence identifier to its alignment row ('S1' byte array), used to convert ungapped coordinates to columns.

TYPE: dict of str to numpy.ndarray

colors

Feature-type colour map; defaults to :data:DEFAULT_ANNOTATION_COLORS.

TYPE: dict of str to str DEFAULT: None

RETURNS DESCRIPTION
list of tuple

(start_col, end_col, color, label, track_row) spans.

load_annotation_colors

load_annotation_colors(path: str) -> Dict[str, str]

Load a two-column type<TAB>hex annotation-colour override file.

PARAMETER DESCRIPTION
path

Path to a whitespace/tab-separated file of feature_type colour rows. Blank lines and # comments are ignored.

TYPE: str

RETURNS DESCRIPTION
dict of str to str

Feature type to colour, merged over :data:DEFAULT_ANNOTATION_COLORS.

Mutation spectra statistics

mutation_spectra

Trinucleotide-context substitution spectra (SBS-96 / SBS-192) from an alignment.

This module computes single-base-substitution spectra by comparing every aligned sequence to an inferred ancestral reference (deRIP2's reconstructed consensus) and reading each substitution's trinucleotide context from that ancestor. It is the tree-free baseline method: every difference between a tip and the single reference is counted as one event, with its 5'/3' context taken from the nearest non-gap ancestral bases.

Because there is no phylogeny, recurrence can only be reported as a multi-hit column proxy: how many sequences independently carry each derived state at a site. True independent-event counting requires ancestral reconstruction on a tree and is provided by the phylogenetic path in :mod:derip2.spectra (later milestone). The API here is deliberately event-stream shaped so that path can reuse the same channel assembly.

See Also

derip2.spectra.channels : SBS-96/192 channel ordering and pyrimidine folding. derip2.stats.strand_bias : The RSI statistic, the sibling per-alignment measure.

SpectraResult dataclass

SpectraResult(sbs96: ndarray, sbs192: Optional[ndarray], sample_names: List[str], event_rows: ndarray, event_cols: ndarray, event_ref: ndarray, event_alt: ndarray, event_five: Optional[ndarray], event_three: Optional[ndarray], event_sample: ndarray, homoplasy_counts: ndarray, ancestor_ref: ndarray, n_indel_or_ambiguous: int, n_unassignable_context: int, method: str = 'baseline', context: str = 'trinucleotide', event_parent_names: Optional[List[str]] = None, event_child_names: Optional[List[str]] = None, event_down1: Optional[ndarray] = None, event_down2: Optional[ndarray] = None)

Trinucleotide-context substitution spectra for an alignment.

ATTRIBUTE DESCRIPTION
sbs96

(96, n_samples) float array of 96-channel counts. For the default 'trinucleotide' context these are SBS-96 (pyrimidine-collapsed) counts in the order of :data:derip2.spectra.channels.SBS96_CHANNELS; for the 'downstream' context they are the downstream-triplet counts in the order of :data:derip2.spectra.channels.DOWNSTREAM_CHANNELS. The :attr:context field and the channel labels disambiguate the two.

TYPE: ndarray

sbs192

(192, n_samples) float array of strand-resolved SBS-192 counts, in the order of :data:derip2.spectra.channels.SBS192_CHANNELS. None for the 'downstream' context, which has no orientation-invariant strand-resolved form.

TYPE: ndarray or None

sample_names

Column labels for the matrices, one per sample.

TYPE: list of str

event_rows, event_cols

(n_events,) int arrays: the alignment row and column of every counted substitution, in discovery order.

TYPE: ndarray

event_ref, event_alt

(n_events,) 'S1' arrays: the reference (ancestral) and derived base of every event, on the observed (input) strand.

TYPE: ndarray

event_five, event_three

(n_events,) 'S1' arrays: the 5' and 3' flanking bases read from the ancestor. None for the 'downstream' context (which uses :attr:event_down1/:attr:event_down2 instead).

TYPE: ndarray or None

event_down1, event_down2

(n_events,) 'S1' arrays: the two pyrimidine-strand downstream bases of every event. Populated only for the 'downstream' context; None otherwise.

TYPE: ndarray or None

event_sample

(n_events,) int array indexing :attr:sample_names.

TYPE: ndarray

homoplasy_counts

(n_cols, 4) int array: for each column, how many sequences carry each derived base (A, C, G, T) as a substitution away from the ancestor. A column with a value >= 2 was hit independently more than once (baseline proxy for recurrence).

TYPE: ndarray

ancestor_ref

(n_cols,) 'S1' array of the reference base per column. For the baseline this is the single ancestor; for the phylogenetic path it is the reconstructed root sequence.

TYPE: ndarray

n_indel_or_ambiguous

Number of tip/ancestor differences skipped because one side was a gap or a non-ACGT base (not a callable substitution).

TYPE: int

n_unassignable_context

Number of substitutions dropped because a full trinucleotide context could not be resolved (terminal columns).

TYPE: int

method

'baseline' for the single-reference spectra or 'phylogenetic' for the branch-traversal spectra.

TYPE: str

context

'trinucleotide' for the 5'/3'-flank SBS-96/192 model or 'downstream' for the pyrimidine-folded downstream-triplet model.

TYPE: str

event_parent_names, event_child_names

For the phylogenetic path, the parent and child node names of every event's edge (None for the baseline).

TYPE: list of str or None

sbs96_channels property

sbs96_channels: List[str]

Canonical SBS-96 channel labels, aligned to :attr:sbs96 rows.

RETURNS DESCRIPTION
list of str

The 96 channel labels in row order.

sbs192_channels property

sbs192_channels: List[str]

Canonical SBS-192 channel labels, aligned to :attr:sbs192 rows.

RETURNS DESCRIPTION
list of str

The 192 channel labels in row order.

downstream_channels property

downstream_channels: List[str]

Canonical downstream-triplet channel labels, aligned to :attr:sbs96 rows.

Only meaningful when :attr:context is 'downstream' (the sbs96 array then holds the downstream counts).

RETURNS DESCRIPTION
list of str

The 96 downstream channel labels in row order.

event_records

event_records() -> List[Dict]

Return every counted substitution as a list of dictionaries.

RETURNS DESCRIPTION
list of dict

One dictionary per event, in discovery order, with keys sample, row, col, ref, alt, five_prime, three_prime, sbs96 and sbs192 (the two channel labels). Phylogenetic results additionally carry parent and child node names, and their row is the child-node ordinal rather than an alignment row.

homoplasy_table

homoplasy_table(min_hits: int = 2) -> List[Dict]

Return substitutions that recurred in >= min_hits independent lineages.

Recurrence is counted over the actual per-event reference and derived bases (the parent base for the phylogenetic path, the ancestor for the baseline), so a column hit by two distinct substitutions is reported as two separate entries and the reference base is always the base the event mutated from.

PARAMETER DESCRIPTION
min_hits

Minimum number of independent lineages carrying the same (column, ref, alt) substitution for it to be reported (default: 2).

TYPE: int DEFAULT: 2

RETURNS DESCRIPTION
list of dict

One dictionary per recurrent (column, ref, alt) meeting the threshold, with keys col, ref, alt, n_independent, sorted by descending n_independent then column then derived base.

as_dict

as_dict() -> Dict

Return a JSON-serialisable summary of the spectra.

Used for golden regression tests. Event-level detail is omitted; the matrices, sample names, homoplasy hits and skip counts fully pin the result.

RETURNS DESCRIPTION
dict

Nested dictionary of the SBS-96/192 matrices (as nested lists), the sample names, the >= 2 homoplasy table and the two skip counts.

compute_spectra

compute_spectra(column_classes, ancestor_seq: str, *, samples: Optional[Sequence[str]] = None, context: str = 'trinucleotide') -> SpectraResult

Compute trinucleotide or downstream-triplet spectra against an ancestor.

Every alignment cell whose base differs from the ancestral base at that column, where both are unambiguous (ACGT), is counted as one substitution event. The context is read from the ancestor using the nearest non-gap bases:

  • context='trinucleotide' (default): the 5'/3' flanks, matching the Alexandrov reference-context convention. Events are folded to the pyrimidine strand for SBS-96 and kept strand-resolved for SBS-192.
  • context='downstream': the two bases downstream of the mutated base on the pyrimidine strand (CHG-aware), producing a single pyrimidine-folded 96-channel matrix. sbs192 is None in this mode.
PARAMETER DESCRIPTION
column_classes

The cached per-cell classification; only its arr (the (n_rows, n_cols) observed-base byte array) is consumed here, guaranteeing the spectra are computed over the same alignment the correction used.

TYPE: ColumnClassification

ancestor_seq

The gapped ancestral/consensus sequence, one base per alignment column (deRIP2's gapped_consensus).

TYPE: str

samples

Per-row sample label to split the matrices by (length n_rows). Default None pools every sequence into one AllSequences sample.

TYPE: sequence of str or None DEFAULT: None

context

Which sequence context to classify substitutions by (default: 'trinucleotide').

TYPE: (trinucleotide, downstream) DEFAULT: 'trinucleotide'

RETURNS DESCRIPTION
SpectraResult

The assembled spectra, per-event detail, homoplasy proxy and skip counts.

RAISES DESCRIPTION
ValueError

If context is not 'trinucleotide' or 'downstream'.

assemble_matrices

assemble_matrices(five_c: ndarray, ref_c: ndarray, alt_c: ndarray, three_c: ndarray, sample_c: ndarray, n_samples: int, weights: Optional[ndarray] = None) -> Tuple[np.ndarray, np.ndarray]

Accumulate an event stream into SBS-96 and SBS-192 count matrices.

This is the single assembly core shared by the tree-free baseline and the phylogenetic branch-traversal path. Each event is a tuple of base codes (five, ref, alt, three) plus the sample it belongs to; the precomputed :data:IDX96_TABLE / :data:IDX192_TABLE map it to its two channel rows.

PARAMETER DESCRIPTION
five_c

(n_events,) int arrays of base codes (0..3) for the 5' flank, reference, derived and 3' flank of each event.

TYPE: ndarray

ref_c

(n_events,) int arrays of base codes (0..3) for the 5' flank, reference, derived and 3' flank of each event.

TYPE: ndarray

alt_c

(n_events,) int arrays of base codes (0..3) for the 5' flank, reference, derived and 3' flank of each event.

TYPE: ndarray

three_c

(n_events,) int arrays of base codes (0..3) for the 5' flank, reference, derived and 3' flank of each event.

TYPE: ndarray

sample_c

(n_events,) int array indexing the sample columns.

TYPE: ndarray

n_samples

Number of sample columns in the output matrices.

TYPE: int

weights

(n_events,) float weights (e.g. posterior products). Default None counts every event as 1.

TYPE: ndarray DEFAULT: None

RETURNS DESCRIPTION
tuple of numpy.ndarray

(sbs96, sbs192) of shapes (96, n_samples) and (192, n_samples).

assemble_downstream

assemble_downstream(down1_c: ndarray, ref_c: ndarray, alt_c: ndarray, down2_c: ndarray, sample_c: ndarray, n_samples: int, weights: Optional[ndarray] = None) -> np.ndarray

Accumulate an event stream into a downstream-triplet count matrix.

Uses the same gather-and-scatter core as :func:assemble_matrices but with the downstream channel-index table :data:IDX_DS_TABLE. The two context codes are the pyrimidine-strand downstream bases resolved by :func:derip2.spectra.channels.downstream_context.

PARAMETER DESCRIPTION
down1_c

(n_events,) int arrays of base codes (0..3) for the first downstream base, reference, derived and second downstream base of each event.

TYPE: ndarray

ref_c

(n_events,) int arrays of base codes (0..3) for the first downstream base, reference, derived and second downstream base of each event.

TYPE: ndarray

alt_c

(n_events,) int arrays of base codes (0..3) for the first downstream base, reference, derived and second downstream base of each event.

TYPE: ndarray

down2_c

(n_events,) int arrays of base codes (0..3) for the first downstream base, reference, derived and second downstream base of each event.

TYPE: ndarray

sample_c

(n_events,) int array indexing the sample columns.

TYPE: ndarray

n_samples

Number of sample columns in the output matrix.

TYPE: int

weights

(n_events,) float weights. Default None counts every event as 1.

TYPE: ndarray DEFAULT: None

RETURNS DESCRIPTION
ndarray

The (96, n_samples) downstream count matrix.

Mutation spectra plotting

spectra

Native matplotlib figures for SBS-96 / SBS-192 mutation spectra.

These reproduce the familiar SigProfiler spectrum layouts — the six-block SBS-96 bar plot, the twelve-block strand-resolved SBS-192 plot, a strand-asymmetry panel and a homoplasy (recurrence) plot — without depending on SigProfilerPlotting. The palette, typography and light publication surface are shared with the strand-bias figures (:mod:derip2.plotting.strandbias) so the whole package renders as one visual system.

All public functions accept a :class:derip2.stats.mutation_spectra.SpectraResult and, optionally, an output path. They return the matplotlib figure so callers can compose or further style it.

plot_sbs96

plot_sbs96(result, outfile: Optional[str] = None, *, title: Optional[str] = None, percentage: bool = False, dpi: int = 300, sample: Optional[int] = None, width: float = 11.0, bare: bool = False)

Draw the canonical six-block SBS-96 spectrum, one panel per sample.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: SpectraResult

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

title

Figure title.

TYPE: str or None DEFAULT: None

percentage

Plot each sample as a percentage of its total (default: counts).

TYPE: bool DEFAULT: False

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

sample

Draw only this single sample (by column index into :attr:~derip2.stats.mutation_spectra.SpectraResult.sample_names) rather than one panel per sample. When None (default) every sample is drawn, one panel each.

TYPE: int or None DEFAULT: None

width

Figure width in inches (default: 11.0). Wider than a page so the 96 trinucleotide ticks so they do not overlap.

TYPE: float DEFAULT: 11.0

bare

Omit the per-sample title and the context caption/suptitle (default: False). Use when an embedding caller supplies its own heading, to avoid a redundant sample label overlapping the title.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Figure

The rendered figure.

RAISES DESCRIPTION
IndexError

If sample is out of range for the available samples.

plot_sbs192

plot_sbs192(result, outfile: Optional[str] = None, *, title: Optional[str] = None, percentage: bool = False, dpi: int = 300)

Draw the strand-resolved twelve-block SBS-192 spectrum, one panel per sample.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: SpectraResult

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

title

Figure title.

TYPE: str or None DEFAULT: None

percentage

Plot each sample as a percentage of its total (default: counts).

TYPE: bool DEFAULT: False

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

RETURNS DESCRIPTION
Figure

The rendered figure.

plot_downstream

plot_downstream(result, outfile: Optional[str] = None, *, title: Optional[str] = None, percentage: bool = False, dpi: int = 300, sample: Optional[int] = None, width: float = 11.0, bare: bool = False)

Draw the pyrimidine-folded downstream-triplet spectrum, one panel per sample.

The six substitution blocks mirror the SBS-96 layout, but each bar is classified by the mutated base plus its two downstream bases (motif ref d1 d2, first base bold). The downstream counts are read from result.sbs96 (which holds the 96-channel matrix for the downstream context).

PARAMETER DESCRIPTION
result

The computed spectra (result.context should be 'downstream').

TYPE: SpectraResult

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

title

Figure title.

TYPE: str or None DEFAULT: None

percentage

Plot each sample as a percentage of its total (default: counts).

TYPE: bool DEFAULT: False

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

sample

Draw only this single sample (by column index into :attr:~derip2.stats.mutation_spectra.SpectraResult.sample_names). When None (default) every sample is drawn, one panel each.

TYPE: int or None DEFAULT: None

width

Figure width in inches (default: 11.0). Wider than a page so the 96 downstream ticks so they do not overlap.

TYPE: float DEFAULT: 11.0

bare

Omit the per-sample title and the context caption/suptitle (default: False), for embedding under an external heading.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Figure

The rendered figure.

RAISES DESCRIPTION
IndexError

If sample is out of range for the available samples.

strand_asymmetry

strand_asymmetry(result, sample: int = 0) -> List[dict]

Summarise coding- versus template-strand counts per pyrimidine class.

For each of the six pyrimidine substitution classes, the coding-strand count is the sum of its SBS-192 channels and the template-strand count is the sum of its reverse-complement purine partner's channels. A binomial test against an even 50/50 split gives a screening p-value for strand bias.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: SpectraResult

sample

Sample column to summarise (default: 0).

TYPE: int DEFAULT: 0

RETURNS DESCRIPTION
list of dict

One dict per pyrimidine class with keys class, coding, template, ratio (coding / template, inf if template is zero) and pvalue.

RAISES DESCRIPTION
ValueError

If the result has no SBS-192 matrix (the downstream context).

plot_strand_asymmetry

plot_strand_asymmetry(result, outfile: Optional[str] = None, *, sample: int = 0, min_count: int = 10, title: Optional[str] = None, dpi: int = 300)

Plot coding- versus template-strand counts for each pyrimidine class.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: SpectraResult

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

sample

Sample column to plot (default: 0).

TYPE: int DEFAULT: 0

min_count

A class is only tested (and starred) when both strands carry at least this many events (default: 10). A strand with near-zero counts gives an unstable binomial test, so such classes are drawn but not flagged.

TYPE: int DEFAULT: 10

title

Figure title.

TYPE: str or None DEFAULT: None

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

RETURNS DESCRIPTION
Figure

The rendered figure.

plot_homoplasy

plot_homoplasy(result, outfile: Optional[str] = None, *, min_hits: int = 2, title: Optional[str] = None, dpi: int = 300)

Plot alignment columns hit by the same substitution in >= min_hits rows.

Each qualifying (column, derived base) is a stem whose height is the number of independent sequences carrying it, coloured by its pyrimidine-folded substitution class. This is the baseline recurrence proxy.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: SpectraResult

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

min_hits

Minimum independent hits for a site to be drawn (default: 2).

TYPE: int DEFAULT: 2

title

Figure title.

TYPE: str or None DEFAULT: None

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

RETURNS DESCRIPTION
Figure

The rendered figure.

Spectra comparison

spectra_compare

Statistical comparison of mutation spectra.

Two spectra (e.g. two species, two clades, or two precalculated SBS matrices) can be compared in two complementary ways:

  • Cosine similarity — a scale-free effect size in [0, 1]. 1.0 means the two channel profiles have identical shape; lower values mean they differ. It ignores the total number of events, so it answers "do these look alike?".
  • Chi-squared test of homogeneity — a significance test of whether the channel counts could have come from one shared distribution. It answers "is the difference more than sampling noise?", and its per-channel standardised residuals show which channels drive any difference.

The two are used together: with very large spectra almost any difference is "significant", so read the p-value alongside the cosine similarity (how different) and the residuals (different where).

The chi-squared p-value is computed here from the regularised incomplete gamma function, so this module needs no SciPy — consistent with the rest of deRIP2's hand-rolled statistics.

cosine_similarity

cosine_similarity(a: Sequence[float], b: Sequence[float]) -> float

Cosine similarity between two spectra vectors.

PARAMETER DESCRIPTION
a

Channel count (or proportion) vectors of equal length.

TYPE: sequence of float

b

Channel count (or proportion) vectors of equal length.

TYPE: sequence of float

RETURNS DESCRIPTION
float

Cosine similarity in [0, 1] for non-negative inputs; nan if either vector is all zero.

RAISES DESCRIPTION
ValueError

If the two vectors have different lengths.

chi2_homogeneity

chi2_homogeneity(matrix: ndarray, sample_names: Optional[List[str]] = None) -> Dict

Chi-squared test of homogeneity across the columns of a count matrix.

The null hypothesis is that every column (sample/group) draws its channel counts from the same underlying distribution. Channels that are empty across all samples are dropped and the degrees of freedom reduced accordingly.

PARAMETER DESCRIPTION
matrix

(n_channels, n_samples) non-negative count matrix.

TYPE: ndarray

sample_names

Column labels, used only for the returned summary.

TYPE: list of str DEFAULT: None

RETURNS DESCRIPTION
dict

chi2 (statistic), dof, pvalue, cramers_v (effect size in [0, 1]), n_samples, n_channels_tested, residuals (the (n_channels, n_samples) standardised Pearson residuals, 0 for dropped channels) and sample_names.

RAISES DESCRIPTION
ValueError

If the matrix has fewer than two columns or contains negative counts.

compare_spectra

compare_spectra(a: Sequence[float], b: Sequence[float], channels: Optional[Sequence[str]] = None, *, top: int = 8) -> Dict

Compare two spectra: cosine similarity plus a chi-squared homogeneity test.

PARAMETER DESCRIPTION
a

Channel count vectors of equal length (e.g. two group columns, or one column from each of two precalculated matrices in the same context).

TYPE: sequence of float

b

Channel count vectors of equal length (e.g. two group columns, or one column from each of two precalculated matrices in the same context).

TYPE: sequence of float

channels

Channel labels, used to report the most differentiating channels.

TYPE: sequence of str DEFAULT: None

top

How many top differentiating channels to return (default: 8).

TYPE: int DEFAULT: 8

RETURNS DESCRIPTION
dict

cosine_similarity, the full chi-squared result (chi2, dof, pvalue, cramers_v), and top_channels — a list of {channel, a, b, residual} for the channels with the largest absolute difference in standardised residual between the two columns, most extreme first.

RAISES DESCRIPTION
ValueError

If the vectors differ in length, or channels (when given) does not match their length.

compare_matrix_files

compare_matrix_files(path_a: str, path_b: str, *, sample_a: int = 0, sample_b: int = 0, top: int = 8) -> Dict

Compare two spectra matrix files, guarding that they share a context.

Each file is read with :func:derip2.spectra.matrix_io.read_sbs_matrix; the two channel-label lists must match exactly (same membership and order), which guarantees the matrices describe the same sequence context. One sample column from each file is then compared with :func:compare_spectra.

PARAMETER DESCRIPTION
path_a

Paths to two MutationType tab-separated matrix files.

TYPE: str

path_b

Paths to two MutationType tab-separated matrix files.

TYPE: str

sample_a

Which sample column of each file to compare (default: 0).

TYPE: int DEFAULT: 0

sample_b

Which sample column of each file to compare (default: 0).

TYPE: int DEFAULT: 0

top

How many top differentiating channels to return (default: 8).

TYPE: int DEFAULT: 8

RETURNS DESCRIPTION
dict

The :func:compare_spectra result (cosine similarity, chi-squared summary and top differentiating channels).

RAISES DESCRIPTION
ValueError

If the two files use different channel sets (contexts), or if a requested sample column is out of range.

pairwise_compare

pairwise_compare(matrix: ndarray, sample_names: Sequence[str], *, correction: str = 'bonferroni') -> List[Dict]

Compare every pair of sample columns with a chi-squared homogeneity test.

PARAMETER DESCRIPTION
matrix

(n_channels, n_samples) count matrix.

TYPE: ndarray

sample_names

Column labels, one per sample.

TYPE: sequence of str

correction

Multiple-testing correction applied to the pairwise p-values (default: 'bonferroni').

TYPE: (bonferroni, none) DEFAULT: 'bonferroni'

RETURNS DESCRIPTION
list of dict

One dict per pair with a, b, cosine_similarity, chi2, dof, pvalue, pvalue_adjusted and cramers_v, sorted by ascending adjusted p-value.

RAISES DESCRIPTION
ValueError

If sample_names length does not match the number of columns.

Flank-context spectra statistics

flank_spectra

Flanking-context spectra of RIP-like sites from an alignment.

This module answers a specific biological question: among the RIP substrate dinucleotides (CpA, or TpG when the CpA is on the reverse strand) that survive in otherwise RIP-affected sequences, is there a local sequence context that protects them from deamination? To probe it we classify every RIP-like dinucleotide by the single base one position upstream and one downstream — a 4 bp motif [up][center][down] — and compare the flank-context distribution of surviving substrate sites against that of realised product (TpA) sites.

Two site states are counted per sequence, using the boolean cell masks of a :class:derip2.aln_ops.ColumnClassification (the single source of truth for RIP context, gap-aware over nearest non-gap neighbours):

  • Substratecls.ca (C followed by A) and cls.tg (G preceded by T), counted anywhere in the sequence, not only in RIP-informative columns. This deliberately uses the raw dinucleotide masks, not the ct_ok/ga_ok-gated sub_fwd/sub_rev used by the strand-bias statistic, because the question is about every surviving substrate.
  • Productcls.prod_fwd (ta & fwd_col) and cls.prod_rev (ta2 & rev_col): a TpA sitting in a column that also shows a surviving substrate, so the product is attributable to RIP.

Each state yields a (16, n_rows) count matrix (one column per alignment row), folded so every reverse-strand motif is reverse-complemented onto the CA/TA-equivalent channel (see :mod:derip2.spectra.flank_channels).

See Also

derip2.spectra.flank_channels : The 16-channel labelling and fold lookup. derip2.stats.spectra_compare : The cosine / chi-squared comparison reused here. derip2.stats.mutation_spectra : The sibling trinucleotide SBS-96/192 spectra.

FlankSpectraResult dataclass

FlankSpectraResult(sub_fwd: ndarray, sub_rev: ndarray, prod_fwd: ndarray, prod_rev: ndarray, sample_names: List[str], n_skipped_flank: Dict[str, int], flank_length: int = 1, channels_substrate: List[str] = (lambda: list(FLANK16_LABELS_CA))(), channels_product: List[str] = (lambda: list(FLANK16_LABELS_TA))())

Per-sequence flanking-context spectra of RIP-like sites.

Four count matrices, each (n_channels, n_rows) with one column per alignment row (the row is the sample index) and n_channels == 4 ** (2 * flank_length) (16 for the default 1 bp flank). Every motif is folded so its centre is CA (substrate) or TA (product) and its channel is indexed by the resolved flanks (see :mod:derip2.spectra.flank_channels).

ATTRIBUTE DESCRIPTION
sub_fwd, sub_rev

(n_channels, n_rows) float counts of forward (CpA) and reverse (TpG) substrate sites, counted anywhere in each sequence.

TYPE: ndarray

prod_fwd, prod_rev

(n_channels, n_rows) float counts of forward and reverse RIP product (TpA) sites in RIP-informative columns.

TYPE: ndarray

sample_names

Column labels, one per alignment row.

TYPE: list of str

n_skipped_flank

Per-state count of sites dropped because an up or down flank could not be resolved to an ACGT base (terminal columns, or a non-ACGT neighbour). Keyed by :data:STATE_KEYS.

TYPE: dict of str to int

flank_length

Number of flanking bases resolved on each side of the centre (default 1).

TYPE: int

channels_substrate, channels_product

The motif labels for the substrate (CA) and product (TA) states, aligned to the matrix rows.

TYPE: list of str

substrate_combined

substrate_combined() -> np.ndarray

Combined-strand substrate spectrum.

RETURNS DESCRIPTION
ndarray

(16, n_rows) sum of :attr:sub_fwd and :attr:sub_rev.

product_combined

product_combined() -> np.ndarray

Combined-strand product spectrum.

RETURNS DESCRIPTION
ndarray

(16, n_rows) sum of :attr:prod_fwd and :attr:prod_rev.

matrix

matrix(state: str, strand: str) -> np.ndarray

Return one (16, n_rows) count matrix by state and strand.

PARAMETER DESCRIPTION
state

Which site state to return.

TYPE: (substrate, product) DEFAULT: 'substrate'

strand

Which strand's counts ('combined' sums the two strands).

TYPE: (combined, forward, reverse) DEFAULT: 'combined'

RETURNS DESCRIPTION
ndarray

The (16, n_rows) matrix.

RAISES DESCRIPTION
ValueError

If state or strand is not recognised.

pooled

pooled() -> Dict[str, np.ndarray]

Pool every sequence into a single alignment-wide spectrum per matrix.

RETURNS DESCRIPTION
dict of str to numpy.ndarray

Keys :data:STATE_KEYS; each value a (16,) row-summed vector.

as_dict

as_dict() -> Dict

Return a JSON-serialisable summary for golden regression tests.

RETURNS DESCRIPTION
dict

The four count matrices as nested lists, the sample names, the per-state skipped-flank counts and the two channel-label sets.

compute_flank_spectra

compute_flank_spectra(column_classes, sample_names: Optional[List[str]] = None, flank_length: int = 1) -> FlankSpectraResult

Compute per-sequence flanking-context spectra of RIP-like sites.

Substrate sites (cls.ca / cls.tg) are counted anywhere in each sequence; product sites (cls.prod_fwd / cls.prod_rev) only in RIP-informative columns. Gating is strictly per cell: a site contributes a flank only when its own core dinucleotide satisfies one of those masks, so a "noise" cell in a RIP-like column — a base that is neither the surviving substrate nor the realised product (e.g. a G or an unrelated SNP) — is False in every mask and never contributes a flank.

Each site's flank_length upstream and downstream bases are resolved over the nearest non-gap neighbours and folded onto the CA/TA-equivalent channel, giving 4 ** (2 * flank_length) channels (16 for the default 1 bp flank). The computation is fully vectorised over the whole alignment; the alignment row is the sample index, so no per-row Python loop is needed.

PARAMETER DESCRIPTION
column_classes

The RIP classification, providing arr, next_idx, prev_idx and the ca/tg masks and prod_fwd/prod_rev cell properties.

TYPE: ColumnClassification

sample_names

Per-row labels (length n_rows). Defaults to the row ordinals as strings.

TYPE: list of str DEFAULT: None

flank_length

Number of flanking bases resolved on each side of the centre dinucleotide (default 1). Must be >= 1.

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
FlankSpectraResult

The four (4 ** (2 * flank_length), n_rows) count matrices, the flank length and per-state skipped counts.

RAISES DESCRIPTION
ValueError

If sample_names is given and its length is not n_rows, or if flank_length < 1.

compare_flank_spectra

compare_flank_spectra(result: FlankSpectraResult, row_index: int, *, min_sites: int = 20, top: int = 6) -> Dict[str, Dict]

Run the five per-sequence flank-context comparisons for one alignment row.

Substrate (CA-centred) channel k and product (TA-centred) channel k share the same (up, down) flank context, so the two spectra are compared position-by-position as a like-for-like flank-context test (labelled by the centre-agnostic up.down pair). The chi-squared p-value is only trustworthy when both spectra carry enough sites; a chi2_reliable flag records whether both totals reach min_sites so callers can lead with the scale-free cosine effect size.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: FlankSpectraResult

row_index

Which alignment row (sample column) to compare.

TYPE: int

min_sites

Minimum site count on both sides for the chi-squared test to be flagged reliable (default: 20).

TYPE: int DEFAULT: 20

top

Number of most-differentiating flank channels to report per comparison (default: 6).

TYPE: int DEFAULT: 6

RETURNS DESCRIPTION
dict of str to dict

Keyed by :data:COMPARISON_KEYS. Each value is the :func:derip2.stats.spectra_compare.compare_spectra result augmented with n_a, n_b (the two site totals) and chi2_reliable.

compare_flank_spectra_pooled

compare_flank_spectra_pooled(result: FlankSpectraResult, *, min_sites: int = 20, top: int = 6) -> Dict[str, Dict]

Run the five flank-context comparisons on the alignment-wide pooled spectra.

Same five comparisons as :func:compare_flank_spectra, but on the counts summed across every sequence (:meth:FlankSpectraResult.pooled), for the report's overview page.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: FlankSpectraResult

min_sites

Minimum site count on both sides for the reliability flag (default: 20).

TYPE: int DEFAULT: 20

top

Number of most-differentiating flank channels to report (default: 6).

TYPE: int DEFAULT: 6

RETURNS DESCRIPTION
dict of str to dict

Keyed by :data:COMPARISON_KEYS, as in :func:compare_flank_spectra.

differential_channels

differential_channels(substrate: ndarray, product: ndarray, *, min_sites: int = 20, alpha: float = 0.05) -> np.ndarray

Flag flank channels differentially enriched between substrate and product.

For each of the 16 channels this computes the adjusted standardised residual of the (16, 2) substrate/product contingency table (Agresti/Haberman): under the null of a shared flank distribution these are approximately standard normal, so a channel with |residual| beyond the two-sided alpha critical value is enriched (or depleted) in one state relative to the other. No multiple-testing correction is applied, consistent with the effect-size-first stance of the rest of this module; the flags are meant as visual guides on the spectra, read alongside the omnibus chi-squared.

The whole comparison is gated on reliability: if either state has fewer than min_sites total sites, no channel is flagged (all False).

PARAMETER DESCRIPTION
substrate

(16,) channel count vectors for the two states (same flank order).

TYPE: ndarray

product

(16,) channel count vectors for the two states (same flank order).

TYPE: ndarray

min_sites

Minimum total sites required in both states for any flag (default: 20).

TYPE: int DEFAULT: 20

alpha

Two-sided significance level for the per-channel test (default: 0.05).

TYPE: float DEFAULT: 0.05

RETURNS DESCRIPTION
ndarray

(16,) boolean mask; True where the channel is differentially enriched between the two states.

write_flank_matrix

write_flank_matrix(result: FlankSpectraResult, path: str) -> str

Write the flank-context spectra as a tidy (long-form) TSV.

One row per sample x state x strand x channel, so the file is trivial to pivot or filter downstream. Combined-strand rows are the sum of the forward and reverse counts.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: FlankSpectraResult

path

Destination path.

TYPE: str

RETURNS DESCRIPTION
str

The path written.

write_flank_comparisons

write_flank_comparisons(result: FlankSpectraResult, path: str, *, min_sites: int = 20) -> str

Write the per-sequence flank-context comparison statistics as a TSV.

One row per sample x comparison (:data:COMPARISON_KEYS), carrying the cosine effect size, Cramér's V, the chi-squared statistic/p-value, the two site totals, the reliability flag and the most-differentiating channels.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: FlankSpectraResult

path

Destination path.

TYPE: str

min_sites

Minimum site count on both sides for chi2_reliable (default: 20).

TYPE: int DEFAULT: 20

RETURNS DESCRIPTION
str

The path written.

Flank-context spectra plotting

flank_spectra

Native matplotlib figures for flanking-context spectra of RIP-like sites.

Each figure is three bihistograms — one per strand view (combined, forward, reverse) — comparing the two site states back to back: surviving substrate counts extend to the left and realised RIP product counts to the right of a shared centre line, one row per [up][centre][down] flank channel. Because a substrate CpA motif and its product TpA share the same flanks, every row is labelled by the CA-state motif (e.g. GCAG labels the substrate GCAG and the equivalent product GTAG). Channels whose enrichment differs significantly between the two states are marked.

The palette, typography and light publication surface are shared with the rest of the package: the substrate/product bar colours come from :mod:derip2.plotting.persequence (blue substrate, orange product, matching the per-sequence strand-bias strip), and the axis styling and save helpers are reused from :mod:derip2.plotting.spectra.

plot_flank_bihistograms

plot_flank_bihistograms(result, sample: int, outfile: Optional[str] = None, *, strands=_STRANDS, title: Optional[str] = None, percentage: bool = False, width: float = 11.0, panel_height: float = 5.2, min_sites: int = 20, alpha: float = 0.05, dpi: int = 300, bare: bool = False)

Draw the flank-context bihistograms for one sequence.

One bihistogram per strand view (combined, forward, reverse): substrate counts extend left, product counts right, one row per CA-state flank channel. Channels differentially enriched between the two states (adjusted standardised residual beyond the alpha critical value, when both states have at least min_sites sites) are highlighted and marked.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: FlankSpectraResult

sample

Column index into result.sample_names (the alignment row to draw).

TYPE: int

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

strands

Which strand views to draw, one panel each (default: combined, forward, reverse). Pass e.g. ('combined',) for a single-panel figure.

TYPE: tuple of str DEFAULT: _STRANDS

title

Figure heading (omitted when bare).

TYPE: str or None DEFAULT: None

percentage

Plot each state as a percentage of its own total (default: counts).

TYPE: bool DEFAULT: False

width

Figure width in inches (default: 11.0).

TYPE: float DEFAULT: 11.0

panel_height

Figure height in inches (default: 5.2), tall enough for 16 rows.

TYPE: float DEFAULT: 5.2

min_sites

Minimum sites per state for a channel to be eligible for a significance mark (default: 20).

TYPE: int DEFAULT: 20

alpha

Per-channel two-sided significance level (default: 0.05).

TYPE: float DEFAULT: 0.05

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

bare

Omit the caption/suptitle for embedding under an external heading (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Figure

The rendered figure.

RAISES DESCRIPTION
IndexError

If sample is out of range for the available samples.

plot_flank_bihistograms_pooled

plot_flank_bihistograms_pooled(result, outfile: Optional[str] = None, *, strands=_STRANDS, title: Optional[str] = None, percentage: bool = False, width: float = 11.0, panel_height: float = 5.2, min_sites: int = 20, alpha: float = 0.05, dpi: int = 300, bare: bool = False)

Draw the flank-context bihistograms pooled across every sequence.

Same layout as :func:plot_flank_bihistograms, but on the alignment-wide row-summed counts (:meth:FlankSpectraResult.pooled), for the report's overview page.

PARAMETER DESCRIPTION
result

The computed spectra.

TYPE: FlankSpectraResult

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

strands

Which strand views to draw, one panel each (default: combined, forward, reverse). The report overview passes ('combined',).

TYPE: tuple of str DEFAULT: _STRANDS

title

Figure heading (omitted when bare).

TYPE: str or None DEFAULT: None

percentage

Plot each state as a percentage of its own total (default: counts).

TYPE: bool DEFAULT: False

width

Figure width in inches (default: 11.0).

TYPE: float DEFAULT: 11.0

panel_height

Figure height in inches (default: 5.2).

TYPE: float DEFAULT: 5.2

min_sites

Minimum sites per state for a channel to be eligible for a significance mark (default: 20).

TYPE: int DEFAULT: 20

alpha

Per-channel two-sided significance level (default: 0.05).

TYPE: float DEFAULT: 0.05

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

bare

Omit the caption/suptitle for embedding (default: False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Figure

The rendered figure.

plot_flank_conversion_heatmap

plot_flank_conversion_heatmap(result, sample: Optional[int] = None, outfile: Optional[str] = None, *, flank_sort: str = 'proximal', cmap=None, title: Optional[str] = None, dpi: int = 300, bare: bool = False)

Draw a heatmap of RIP conversion as a function of the up/down flank bases.

For a RIP target CpA (the fixed centre dinucleotide) each cell shows the product share100 * product / (substrate + product) — i.e. the percentage of that flank motif converted from the substrate (CpA) to the product (TpA) state, as a joint function of the flank_length bases immediately 5' (rows) and 3' (columns) of the target. The grid is 4 ** flank_length on a side (4x4 for a 1 bp flank, 16x16 for 2 bp). Cell counts are annotated only for the 4x4 grid; wider grids rely on colour and the dinucleotide axis labels alone.

Colour defaults to viridis: dark purple where the motif has kept its substrate, through teal and green, to bright yellow where it has been fully converted. This encodes magnitude only — unlike the bihistograms, hue here does not name the substrate or product state. Cells for motifs seen zero times are left white, so a blank reads as a hole in the grid rather than a low conversion rate. Pass cmap to use a different palette.

PARAMETER DESCRIPTION
result

The computed spectra (any flank width).

TYPE: FlankSpectraResult

sample

Alignment row to draw; None (default) pools across every sequence.

TYPE: int or None DEFAULT: None

outfile

Output path; when None the figure is returned unsaved.

TYPE: str or None DEFAULT: None

flank_sort

How the upstream (row) flank motifs are ordered (default 'proximal'). The downstream (column) axis is always ordered by the base nearest the centre (its natural label order). 'proximal' orders the upstream axis the same way — by the flank base nearest the centre first, then the next base out — so both axes read from the core outward and, for a 2 bp flank, motifs sharing a nearest 5' base are grouped together. 'alphabetical' instead sorts both axes by the plain motif string (the upstream axis then sorts by its distal base first). For a 1 bp flank the two modes are identical.

TYPE: (proximal, alphabetical) DEFAULT: 'proximal'

cmap

Palette for the 0-100 % scale. Accepts a registered matplotlib colormap name (append _r to reverse it, e.g. 'magma_r', 'RdYlBu_r'), a :class:~matplotlib.colors.Colormap, or a list of two or more colours to interpolate between, low value first. Defaults to the package ramp.

The default viridis is both colourblind-safe and monotone in lightness, so it also reads in greyscale. See :func:derip2.plotting.persequence.resolve_cmap.

TYPE: str or Colormap or sequence DEFAULT: None

title

Figure heading (omitted when bare).

TYPE: str or None DEFAULT: None

dpi

Raster resolution (default: 300).

TYPE: int DEFAULT: 300

bare

Omit the default title for embedding under an external heading.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Figure

The rendered heatmap.

RAISES DESCRIPTION
IndexError

If sample is out of range for the available samples.

ValueError

If flank_sort is not 'proximal' or 'alphabetical', or if cmap cannot be resolved to a colormap.

Maximum RIP sequences

maxrip

Maximum-RIP counterfactuals of the deRIP'd consensus.

Where :mod:derip2.aln_ops runs RIP backwards — restoring the ancestral C and G that RIP deaminated — this module runs it forwards to exhaustion. Given the deRIP'd consensus it produces the sequence that would result if every RIP target it still carries had been mutated, answering "how far could this locus have gone?" rather than "where did it start?".

Three variants are offered, differing only in which sites count as targets:

'all' Every RIP substrate site present in the consensus: a C whose 3' neighbour is A becomes T, and a G whose 5' neighbour is T becomes A. This is the pure counterfactual and ignores the alignment entirely. 'observed' The same rule, but restricted to alignment columns where RIP demonstrably occurred in at least one input sequence. Conservative: it will not invent mutation at a site the family gives no evidence for. 'all_plus_nonrip' 'all', plus the columns where the alignment shows deamination outside RIP dinucleotide context. Models a locus subject to both RIP and context-independent cytosine deamination.

Context comes from the consensus; evidence comes from the alignment. The deRIP'd consensus is a chimera — conserved columns, then RIP corrections, then a fill from a chosen reference row — so a restored C can end up beside a filled A and form a CpA that exists in no single input sequence. Since these variants are claims about the reconstructed ancestor, the dinucleotide context is read off the consensus itself; the per-column masks of :class:derip2.aln_ops.ColumnClassification are consulted only to decide which columns carry evidence (the 'observed' and 'all_plus_nonrip' filters).

Gap handling matches the alignment scan exactly, by reusing :func:derip2.aln_ops._nongap_neighbors: a C-A spanning a gap column is a substrate site, just as it is when the alignment is classified.

MaxRIPResult dataclass

MaxRIPResult(variant: str, gapped_seq: str, seq: str, converted_cols: ndarray, converted_positions: ndarray, strand: ndarray, n_forward: int, n_reverse: int)

A maximally RIP-mutated variant of the deRIP'd consensus.

ATTRIBUTE DESCRIPTION
variant

Which rule produced this sequence; one of :data:MAX_RIP_VARIANTS.

TYPE: str

gapped_seq

The mutated consensus with gap columns preserved, so it stays aligned column-for-column with the input alignment.

TYPE: str

seq

gapped_seq with gaps removed.

TYPE: str

converted_cols

Ascending alignment column indices that were mutated (int64).

TYPE: ndarray

converted_positions

The same sites as zero-based offsets into seq (int64).

TYPE: ndarray

strand

'S1' array of b'+' / b'-', parallel to converted_cols, recording whether each site was a forward (CpA) or reverse (TpG) target.

TYPE: ndarray

n_forward

Number of forward-strand conversions.

TYPE: int

n_reverse

Number of reverse-strand conversions.

TYPE: int

n_converted property

n_converted: int

Total number of converted sites.

RETURNS DESCRIPTION
int

n_forward + n_reverse.

as_record

as_record(seq_id: str = 'maxRIPseq', gapped: bool = False) -> SeqRecord

Wrap the sequence as a :class:~Bio.SeqRecord.SeqRecord for writing.

PARAMETER DESCRIPTION
seq_id

Record id and name (default 'maxRIPseq').

TYPE: str DEFAULT: 'maxRIPseq'

gapped

Emit the column-aligned sequence rather than the ungapped one (default False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
SeqRecord

The sequence, with the variant named in its description.

compute_max_rip

compute_max_rip(gapped_consensus: Union[str, SeqRecord, Seq], cls: ColumnClassification, *, variant: str = 'all') -> MaxRIPResult

Build a maximally RIP-mutated variant of a deRIP'd consensus.

Substrate context is read from gapped_consensus itself; cls supplies only the per-column evidence used by the 'observed' and 'all_plus_nonrip' variants. See the module docstring for why.

Conversion runs to a fixed point, so the result is stable: re-running this function on its own output converts nothing.

For 'all' and 'observed' a single pass already is that fixed point, because a context-derived conversion cannot create a new target. A forward C would need its 3' neighbour to become A, which only a reverse G-to-A does, and that requires the base before the G to be T — but here it is the C itself; the reverse case is symmetric.

'all_plus_nonrip' genuinely does cascade, because its extra sites are context-free: a C converted to T immediately 5' of a G creates a TpG that was not a substrate beforehand. A maximally mutated sequence should carry that downstream conversion too, so the passes repeat until nothing changes. Each pass strictly reduces the number of C and G, so the loop always terminates.

PARAMETER DESCRIPTION
gapped_consensus

The column-aligned deRIP'd consensus, the same length as the alignment.

TYPE: str or Seq or SeqRecord

cls

The alignment's cached column classification.

TYPE: ColumnClassification

variant

Which rule to apply (default 'all').

TYPE: (all, observed, all_plus_nonrip) DEFAULT: 'all'

RETURNS DESCRIPTION
MaxRIPResult

The mutated sequence and the sites that were changed.

RAISES DESCRIPTION
ValueError

If variant is unknown, or if the consensus length does not match the alignment width recorded in cls.

write_max_rip_fasta

write_max_rip_fasta(results, output_file: str, seq_id: str = 'maxRIPseq', gapped: bool = False) -> str

Write one or more maximum-RIP sequences to a multi-FASTA file.

PARAMETER DESCRIPTION
results

The sequences to write, in the order they should appear.

TYPE: iterable of MaxRIPResult

output_file

Destination path.

TYPE: str

seq_id

Base record id; each record is suffixed with its variant name so the records stay uniquely identifiable (default 'maxRIPseq').

TYPE: str DEFAULT: 'maxRIPseq'

gapped

Write the column-aligned sequences rather than the ungapped ones (default False).

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
str

output_file, for chaining.

max_rip_multifasta

max_rip_multifasta(results, seq_id: str = 'maxRIPseq', width: int = 60) -> str

Render maximum-RIP sequences as a plain multi-FASTA string.

Used by the HTML report's download link, which embeds the text directly rather than writing a file.

PARAMETER DESCRIPTION
results

The sequences to render.

TYPE: iterable of MaxRIPResult

seq_id

Base record id; suffixed with each variant name (default 'maxRIPseq').

TYPE: str DEFAULT: 'maxRIPseq'

width

Line-wrap width (default: 60).

TYPE: int DEFAULT: 60

RETURNS DESCRIPTION
str

A FASTA document; empty when results is empty.

Phylogenetic spectra (ancestral state reconstruction)

tree_asr

Phylogeny and ancestral-state reconstruction for the mutation-spectrum pipeline.

This module wraps IQ-TREE to infer a maximum-likelihood tree and marginal ancestral sequences, then roots the tree and orients every edge parent -> child so that substitutions can be polarised. It is the only place in deRIP2 that shells out to an external binary; all subprocess handling is isolated here.

The workflow is:

  1. :func:run_iqtree runs iqtree --ancestral on a written alignment, producing <prefix>.treefile (Newick, named internal nodes) and <prefix>.state (per-internal-node marginal posteriors).
  2. :func:parse_state reads the .state file into per-node ancestral sequences and per-site probabilities.
  3. :func:build_reconstruction loads the tree with ete4, roots it, orients edges away from the root, and assembles a :class:TreeReconstruction giving every node a sequence (tips from the alignment, internal nodes from the .state).

IQ-TREE must be on PATH as iqtree3, iqtree2 or iqtree; ete4 must be installed (the optional spectra dependency group).

TreeReconstruction dataclass

TreeReconstruction(edges: List[Tuple[str, str]], node_seq: Dict[str, ndarray], node_prob: Dict[str, ndarray], root_name: str, tip_names: List[str], n_cols: int, manifest: dict = dict())

A rooted, ancestrally-reconstructed tree ready for branch traversal.

ATTRIBUTE DESCRIPTION
edges

Directed (parent_name, child_name) edges, oriented away from the root.

TYPE: list of tuple of str

node_seq

Every node name (tips and internal) mapped to its (n_cols,) 'S1' sequence.

TYPE: dict of str to numpy.ndarray

node_prob

Every node name mapped to its (n_cols,) per-site state probability (tips are all 1.0).

TYPE: dict of str to numpy.ndarray

root_name

Name of the node chosen as the root.

TYPE: str

tip_names

Names of the leaf nodes (alignment sequences).

TYPE: list of str

n_cols

Alignment width.

TYPE: int

manifest

Provenance: rooting method, outgroup, IQ-TREE version, node counts, etc.

TYPE: dict

build_reconstruction

build_reconstruction(treefile: str, state_path: str, alignment, *, rooting: str = 'midpoint', outgroup=None, manifest_extra: Optional[dict] = None) -> TreeReconstruction

Assemble a rooted, oriented, ancestrally-reconstructed tree.

PARAMETER DESCRIPTION
treefile

Path to the IQ-TREE .treefile.

TYPE: str

state_path

Path to the IQ-TREE .state file.

TYPE: str

alignment

The alignment IQ-TREE was run on; supplies tip sequences.

TYPE: MultipleSeqAlignment

rooting

How to root the tree (default 'midpoint').

TYPE: (midpoint, outgroup, none) DEFAULT: 'midpoint'

outgroup

Outgroup tip name(s), required when rooting == 'outgroup'.

TYPE: str or list of str DEFAULT: None

manifest_extra

Extra key/values to record in the reconstruction manifest.

TYPE: dict DEFAULT: None

RETURNS DESCRIPTION
TreeReconstruction

The rooted tree with a sequence for every node.

RAISES DESCRIPTION
ValueError

If a tree node has no reconstructed or observed sequence, or the alignment width does not match the .state sites.

reconstruct

reconstruct(alignment, work_prefix: str, *, model: str = 'MFP', threads: str = 'AUTO', rooting: str = 'midpoint', outgroup=None, tree: Optional[str] = None, binary: Optional[str] = None) -> TreeReconstruction

Run IQ-TREE on an alignment and build a rooted reconstruction in one call.

PARAMETER DESCRIPTION
alignment

The alignment to analyse.

TYPE: MultipleSeqAlignment

work_prefix

Prefix for the written alignment and all IQ-TREE outputs.

TYPE: str

model

Substitution model for -m (default 'MFP').

TYPE: str DEFAULT: 'MFP'

threads

Value for IQ-TREE -T (default 'AUTO'). 'AUTO' benchmarks the best thread count, which adds noticeable overhead on tiny alignments; pass a fixed integer string (e.g. '1') to skip it.

TYPE: str DEFAULT: 'AUTO'

rooting

Rooting strategy (default 'midpoint').

TYPE: (midpoint, outgroup, none) DEFAULT: 'midpoint'

outgroup

Outgroup tip name(s) when rooting == 'outgroup'.

TYPE: str or list of str DEFAULT: None

tree

Path to a fixed user tree; passed to IQ-TREE via -te so ancestral states are reconstructed on that topology.

TYPE: str DEFAULT: None

binary

Explicit IQ-TREE executable.

TYPE: str DEFAULT: None

RETURNS DESCRIPTION
TreeReconstruction

The rooted, oriented, ancestrally-reconstructed tree.

assign_clades

assign_clades(reconstruction: TreeReconstruction) -> Dict[str, str]

Assign every non-root node to the clade of its root-child ancestor.

Each subtree hanging directly off the root is one clade, named by its root-child node. This yields the samples_by_child mapping used to partition the spectra by lineage.

PARAMETER DESCRIPTION
reconstruction

The rooted reconstruction.

TYPE: TreeReconstruction

RETURNS DESCRIPTION
dict of str to str

Maps each non-root node name to its clade label.

assign_groups

assign_groups(reconstruction: TreeReconstruction, group_by_tip: Dict[str, str], *, mixed_label: str = 'mixed', ungrouped_label: str = 'ungrouped') -> Dict[str, str]

Attribute each branch to a group when its whole descendant clade shares one.

Groups are defined on the tips (e.g. species labels). A branch parent -> child is attributed to a group only when every tip descending from child belongs to that group; branches whose descendants span more than one group (the ancestral trunk) are labelled mixed_label. This gives the samples_by_child mapping needed to report per-group spectra from the phylogenetic path.

PARAMETER DESCRIPTION
reconstruction

The rooted reconstruction.

TYPE: TreeReconstruction

group_by_tip

Maps each tip node name (as it appears in the tree) to a group label.

TYPE: dict of str to str

mixed_label

Label for branches whose descendants span several groups (default 'mixed').

TYPE: str DEFAULT: 'mixed'

ungrouped_label

Label used for tips absent from group_by_tip (default 'ungrouped').

TYPE: str DEFAULT: 'ungrouped'

RETURNS DESCRIPTION
dict of str to str

Maps each non-root node name to its group label.

run_iqtree

run_iqtree(alignment_path: str, prefix: str, *, model: str = 'MFP', threads: str = 'AUTO', fixed_tree: Optional[str] = None, binary: Optional[str] = None, extra_args: Optional[List[str]] = None) -> Dict[str, str]

Run IQ-TREE with marginal ancestral state reconstruction.

PARAMETER DESCRIPTION
alignment_path

Path to the input alignment (FASTA).

TYPE: str

prefix

Output prefix; IQ-TREE writes <prefix>.treefile, <prefix>.state and friends.

TYPE: str

model

Substitution model passed to -m (default 'MFP', ModelFinder Plus).

TYPE: str DEFAULT: 'MFP'

threads

Value for -T (default 'AUTO').

TYPE: str DEFAULT: 'AUTO'

fixed_tree

Path to a user tree. When given it is passed via -te so IQ-TREE reconstructs ancestral states on that fixed topology instead of inferring a new one.

TYPE: str DEFAULT: None

binary

Explicit IQ-TREE executable; otherwise auto-detected.

TYPE: str DEFAULT: None

extra_args

Additional command-line arguments appended verbatim.

TYPE: list of str DEFAULT: None

RETURNS DESCRIPTION
dict

Paths of the key outputs: treefile, state, iqtree (the report) and binary / version used.

RAISES DESCRIPTION
FileNotFoundError

If IQ-TREE is not found, or an expected output file is missing.

RuntimeError

If IQ-TREE exits with a non-zero status.

find_iqtree

find_iqtree(binary: Optional[str] = None) -> str

Locate an IQ-TREE executable on PATH.

PARAMETER DESCRIPTION
binary

An explicit executable name or path to use. When None the known IQ-TREE names are tried in order (iqtree3, iqtree2, iqtree).

TYPE: str DEFAULT: None

RETURNS DESCRIPTION
str

The resolved path to the executable.

RAISES DESCRIPTION
FileNotFoundError

If no IQ-TREE executable can be found.

iqtree_version

iqtree_version(binary: str) -> str

Return the version banner of an IQ-TREE executable.

PARAMETER DESCRIPTION
binary

Path to the IQ-TREE executable.

TYPE: str

RETURNS DESCRIPTION
str

The first non-empty line of iqtree --version, or 'unknown' if it cannot be determined.

call_mutations

Branch-by-branch substitution calling for the phylogenetic mutation spectrum.

Given a rooted, ancestrally-reconstructed tree (:class:TreeReconstruction), this walks every directed parent -> child edge and logs each column where the two sequences differ as one independent substitution event. The trinucleotide context is read from the parent sequence at that branch — the sequence state at the moment the mutation occurred — using the nearest non-gap bases.

Counting events per edge, rather than per tip against one reference, is what makes recurrent (homoplasic) deamination visible: the same C>T arising independently on three branches is three events here, and the homoplasy table records that a column was hit on multiple independent branches.

The assembled event stream is fed to the same channel-assembly core (:func:derip2.stats.mutation_spectra.assemble_matrices) as the tree-free baseline, so the two methods produce directly comparable SBS-96 / SBS-192 matrices.

compute_spectra_from_tree

compute_spectra_from_tree(reconstruction, *, samples_by_child: Optional[Dict[str, str]] = None, min_prob: float = 0.0, context: str = 'trinucleotide') -> SpectraResult

Call substitutions along every branch and assemble the mutation spectra.

PARAMETER DESCRIPTION
reconstruction

A rooted, oriented, ancestrally-reconstructed tree.

TYPE: TreeReconstruction

samples_by_child

Maps a child node name to a sample label, so events can be partitioned by clade. Children absent from the map fall into a trunk sample. Default None pools all branches into one AllBranches sample.

TYPE: dict of str to str DEFAULT: None

min_prob

Drop events whose combined parent/child state posterior probability is below this threshold (default 0.0, keep all).

TYPE: float DEFAULT: 0.0

context

Which sequence context to classify substitutions by (default: 'trinucleotide'). 'downstream' builds the pyrimidine-folded downstream-triplet matrix and leaves sbs192 None.

TYPE: (trinucleotide, downstream) DEFAULT: 'trinucleotide'

RETURNS DESCRIPTION
SpectraResult

The phylogenetic spectra, per-event detail (with parent/child names) and the true (per-branch) homoplasy counts.

Spectra channels and matrix IO

channels

SBS-96 and SBS-192 channel bookkeeping for trinucleotide mutation spectra.

The single-base-substitution (SBS) classification counts each substitution in the context of its immediately flanking 5' and 3' bases.

SBS-96 collapses every event onto the pyrimidine strand: the six pyrimidine substitution types (C>A, C>G, C>T, T>A, T>C, T>G) times the sixteen 5'/3' flank combinations. A purine-reference event is folded to its pyrimidine complement by reverse-complementing the whole trinucleotide, which swaps and complements the two flanks (the load-bearing correctness detail).

SBS-192 is strand-resolved: it keeps the reference base as observed on a defined reference strand (here the coding sense strand), so all twelve substitution types times sixteen flanks = 192 channels are retained. This exposes strand asymmetries (e.g. APOBEC/AID or transcription-coupled biases) that the collapsed SBS-96 hides. This is the plain purine+pyrimidine channel form described in the design (labels such as A[G>T]A), not the transcriptional T:/U: prefixed form some SigProfiler versions emit for 192.

Channel label form is the SigProfiler convention 5[REF>ALT]3 (e.g. A[C>A]A). SBS96_CHANNELS and SBS192_CHANNELS give the canonical row order used by the matrix files and plots.

sbs96_channel

sbs96_channel(five: str, ref: str, alt: str, three: str) -> str

Return the SBS-96 (pyrimidine-collapsed) channel label for an event.

PARAMETER DESCRIPTION
five

The 5' flanking base on the reference strand.

TYPE: str

ref

The reference (ancestral) base.

TYPE: str

alt

The derived base.

TYPE: str

three

The 3' flanking base on the reference strand.

TYPE: str

RETURNS DESCRIPTION
str

The folded channel label, e.g. A[C>A]A.

sbs192_channel

sbs192_channel(five: str, ref: str, alt: str, three: str) -> str

Return the strand-resolved SBS-192 channel label for an event.

No pyrimidine folding is applied: the reference base is kept as observed on the coding reference strand, so all twelve substitution types are retained.

PARAMETER DESCRIPTION
five

The 5' flanking base on the reference strand.

TYPE: str

ref

The reference (ancestral) base.

TYPE: str

alt

The derived base.

TYPE: str

three

The 3' flanking base on the reference strand.

TYPE: str

RETURNS DESCRIPTION
str

The unfolded channel label, e.g. A[G>T]A.

downstream_channel

downstream_channel(ref: str, alt: str, d1: str, d2: str) -> str

Return the downstream-triplet channel label for a pyrimidine-folded event.

This is a pure label builder: ref/alt are expected to already be on the pyrimidine strand (ref in C/T) and d1/d2 to already be the pyrimidine-strand downstream bases, exactly as :func:downstream_context resolves them. Folding of a purine-reference event is the caller's responsibility (mirroring how :func:sbs96_channel is composed via :func:fold_to_pyrimidine), because the two downstream bases are selected from different physical neighbours depending on the reference strand.

PARAMETER DESCRIPTION
ref

The pyrimidine reference base (C or T).

TYPE: str

alt

The derived base on the pyrimidine strand.

TYPE: str

d1

The first downstream base on the pyrimidine strand.

TYPE: str

d2

The second downstream base on the pyrimidine strand.

TYPE: str

RETURNS DESCRIPTION
str

The channel label, e.g. [C>T]AG.

trinucleotide_context

trinucleotide_context(seq: ndarray, col: int, next_idx: ndarray, prev_idx: ndarray) -> Optional[Tuple[str, str]]

Resolve the 5' and 3' flanking bases of a column using nearest non-gap bases.

The flanks are read from seq at the nearest non-gap (and non-ambiguous) neighbour columns, whose indices are supplied precomputed in next_idx and prev_idx. When either neighbour is absent (a terminal column, indicated by -1) the event cannot be assigned a full trinucleotide context and None is returned.

PARAMETER DESCRIPTION
seq

1-D byte array (dtype 'S1') of the reference/ancestral sequence, with every non-ACGT position already normalised to a gap so that the neighbour indices skip over it.

TYPE: ndarray

col

The column whose flanks are wanted.

TYPE: int

next_idx

1-D int array; the column index of the nearest non-gap base to the right of each column, or -1.

TYPE: ndarray

prev_idx

1-D int array; the column index of the nearest non-gap base to the left of each column, or -1.

TYPE: ndarray

RETURNS DESCRIPTION
tuple of str or None

(five, three) uppercase bases, or None if either flank is unresolvable.

downstream_context

downstream_context(seq: ndarray, col: int, next_idx: ndarray, prev_idx: ndarray) -> Optional[Tuple[str, str]]

Resolve the two pyrimidine-strand downstream bases of a column.

The reference base at col sets the strand on which "downstream" is read so that the result is invariant to the orientation of the input alignment:

  • Pyrimidine reference (C/T): the two downstream bases are read directly from the nearest non-gap neighbours to the right (next_idx chained once to reach the second base).
  • Purine reference (A/G): the equivalent pyrimidine event lives on the opposite strand, whose two downstream bases are the reverse-complement of the two upstream bases here. So the two nearest non-gap neighbours to the left (prev_idx chained once) are complemented and returned.

Non-ACGT positions must already be normalised to gaps in seq so the neighbour indices skip over them (as for :func:trinucleotide_context). When either required second neighbour is absent (a terminal column, or -- for a purine reference -- a column too close to the 5' end) the event has no full downstream context and None is returned. This 5'/3' asymmetry is inherent to reading a fixed two-base window on the pyrimidine strand.

PARAMETER DESCRIPTION
seq

1-D byte array (dtype 'S1') of the reference/ancestral sequence, with every non-ACGT position already normalised to a gap.

TYPE: ndarray

col

The column of the mutated (reference) base.

TYPE: int

next_idx

1-D int array; the column index of the nearest non-gap base to the right of each column, or -1.

TYPE: ndarray

prev_idx

1-D int array; the column index of the nearest non-gap base to the left of each column, or -1.

TYPE: ndarray

RETURNS DESCRIPTION
tuple of str or None

(d1, d2) uppercase pyrimidine-strand downstream bases, or None if the full two-base context is unresolvable.

fold_to_pyrimidine

fold_to_pyrimidine(five: str, ref: str, alt: str, three: str) -> Tuple[str, str, str, str]

Fold a substitution onto the pyrimidine strand for SBS-96.

If the reference base is already a pyrimidine (C or T) the event is returned unchanged. If it is a purine, the whole trinucleotide is reverse-complemented: the reference and derived bases are complemented, and the two flanks are complemented and swapped (the old 3' becomes the new 5'). For example G>A in context T_C (5'=T, 3'=C) folds to C>T in context G_A.

PARAMETER DESCRIPTION
five

The 5' flanking base on the reference strand.

TYPE: str

ref

The reference (ancestral) base.

TYPE: str

alt

The derived base.

TYPE: str

three

The 3' flanking base on the reference strand.

TYPE: str

RETURNS DESCRIPTION
tuple of str

(five, ref, alt, three) on the pyrimidine strand.

revcomp_base

revcomp_base(base: str) -> str

Return the Watson-Crick complement of a single uppercase DNA base.

PARAMETER DESCRIPTION
base

A single character, one of A, C, G or T.

TYPE: str

RETURNS DESCRIPTION
str

The complementary base.

RAISES DESCRIPTION
KeyError

If base is not one of the four canonical DNA bases.

flank_channels

Channel bookkeeping for flanking-context spectra of RIP-like sites.

Where the SBS-96 model (see :mod:derip2.spectra.channels) classifies a substitution by its 5'/3' trinucleotide context, this model classifies a dinucleotide site by the single base one position upstream and one position downstream — a 4 bp motif [up][center][down] with a fixed two-base centre. Only the two flanks vary, giving 4 x 4 = 16 channels per site state.

Two site states are counted (each with a fixed centre after orientation folding):

  • Substrate — the surviving RIP substrate dinucleotide, CpA read on the pyrimidine (forward) strand. Centre 'CA'. A reverse-strand substrate reads as TpG on the forward strand and is reverse-complemented back to CA.
  • Product — the RIP product dinucleotide TpA in a RIP-informative column. Centre 'TA' (TpA is its own reverse complement's centre).

Orientation folding reverse-complements a reverse-strand motif so every count lands on the CA/TA-equivalent channel. Reverse-complementing a 4 bp motif [up][X][Y][down] gives [comp(down)][comp(Y)][comp(X)][comp(up)]: the two flanks swap sides and complement (the same load-bearing detail as SBS-96's pyrimidine fold). The centre CA <-> TG maps to CA and TA <-> TA, so both states keep a fixed centre after folding.

Channel order matches the SBS-96 flank convention: the upstream base varies in the outer loop and the downstream base in the inner loop, so the 16 flanks are laid out AA, AC, AG, AT, CA, ..., TT for a given centre (e.g. ACAA, ACAC, ACAG, ACAT, CCAA, ..., TCAT for centre CA).

flank_channel_labels

flank_channel_labels(center: str, width: int = 1) -> List[str]

Enumerate the [up][center][down] motif labels for a site state.

The upstream flank (width bases, written 5'->3') varies in the outer loop and the downstream flank in the inner loop, so the returned order matches the mixed-radix channel index of :func:flank_channel_index. For width == 1 this reproduces the 16-channel up*4 + down ordering exactly (e.g. ['ACAA', 'ACAC', ..., 'TCAT'] for center='CA').

PARAMETER DESCRIPTION
center

The fixed two-base centre, 'CA' (substrate) or 'TA' (product).

TYPE: str

width

Number of flanking bases on each side (default 1).

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
list of str

The 4 ** (2 * width) motif labels in canonical channel order.

RAISES DESCRIPTION
ValueError

If center is not a two-character ACGT string, or width < 1.

flank_pair_labels

flank_pair_labels(width: int = 1) -> List[str]

Enumerate the centre-agnostic up.down flank-pair labels.

These label the flank context alone (no centre dinucleotide), for comparing a substrate (CA-centred) spectrum against a product (TA-centred) one position-by-position without implying a shared centre motif.

PARAMETER DESCRIPTION
width

Number of flanking bases on each side (default 1).

TYPE: int DEFAULT: 1

RETURNS DESCRIPTION
list of str

The 4 ** (2 * width) flank-pair labels in channel order, e.g. ['A.A', 'A.C', ..., 'T.T'] for width == 1.

matrix_io

Read and write SigProfiler-compliant SBS mutation matrices.

A matrix file is tab-separated. The first column is headed MutationType and holds the channel labels in canonical order (A[C>A]A and so on); every remaining column is one sample's counts. This is exactly the format sigProfilerPlotting.plotSBS and SigProfilerAssignment expect, so the files drop straight into those tools when they are installed, while deRIP2 itself keeps no dependency on them.

write_sbs_matrix

write_sbs_matrix(result: SpectraResult, path: str, kind: str = '96') -> str

Write a spectra result to a SigProfiler-compliant SBS matrix file.

PARAMETER DESCRIPTION
result

The computed spectra to serialise.

TYPE: SpectraResult

path

Output file path.

TYPE: str

kind

Which matrix to write (default: '96'). Must be compatible with result.context ('96'/'192' for the trinucleotide context, 'downstream' for the downstream context).

TYPE: (96, 192, downstream) DEFAULT: '96'

RETURNS DESCRIPTION
str

The path written, for convenience.

RAISES DESCRIPTION
ValueError

If kind is unknown, or is not valid for result.context.

read_sbs_matrix

read_sbs_matrix(path: str) -> Tuple[List[str], List[str], np.ndarray]

Read a SigProfiler-compliant SBS matrix file.

PARAMETER DESCRIPTION
path

Path to a tab-separated matrix file with a MutationType first column.

TYPE: str

RETURNS DESCRIPTION
tuple

(channels, sample_names, matrix) where channels is the list of row labels, sample_names the count-column headers and matrix a (n_channels, n_samples) float array.

write_matrix_metadata

write_matrix_metadata(result: SpectraResult, path: str, kind: str = '96') -> str

Write a JSON sidecar describing how a matrix file was produced.

The SBS matrix files are kept as clean MutationType tab-separated tables so third-party tools (e.g. SigProfilerPlotting / SigProfilerAssignment) can read them directly -- those tools reject in-file comment lines, so the provenance (which sequence context and calling method produced the matrix) is written to a companion JSON file instead of into the matrix itself.

PARAMETER DESCRIPTION
result

The computed spectra the matrix was written from.

TYPE: SpectraResult

path

Output path for the JSON sidecar.

TYPE: str

kind

The matrix kind the sidecar documents (default: '96').

TYPE: (96, 192, downstream) DEFAULT: '96'

RETURNS DESCRIPTION
str

The path written, for convenience.

Alignment QC for spectra

qc

Alignment quality control for the phylogenetic mutation-spectrum pipeline.

Alignment artefacts become phantom substitutions, so before any tree is built the alignment is profiled: per-column gap and ambiguity fractions are computed and columns too gappy to give reliable flanking context are flagged. The report is advisory — nothing is removed — but the flags let downstream steps and the reader judge how much of the spectrum rests on well-supported columns.

ColumnProfile dataclass

ColumnProfile(n_rows: int, n_cols: int, gap_fraction: ndarray, ambiguous_fraction: ndarray, context_unreliable: ndarray, gap_threshold: float)

Per-column gap and ambiguity profile of an alignment.

ATTRIBUTE DESCRIPTION
n_rows

Number of sequences.

TYPE: int

n_cols

Number of alignment columns.

TYPE: int

gap_fraction

(n_cols,) fraction of rows that are a gap in each column.

TYPE: ndarray

ambiguous_fraction

(n_cols,) fraction of rows that are a non-ACGT, non-gap symbol.

TYPE: ndarray

context_unreliable

(n_cols,) boolean; True where the gap fraction exceeds the threshold, so flanking context resolved through the column should be distrusted.

TYPE: ndarray

gap_threshold

The gap fraction above which a column is flagged.

TYPE: float

n_flagged property

n_flagged: int

Number of columns flagged as context-unreliable.

RETURNS DESCRIPTION
int

Count of flagged columns.

profile_alignment

profile_alignment(alignment, gap_threshold: float = 0.5) -> ColumnProfile

Compute the per-column gap and ambiguity profile of an alignment.

PARAMETER DESCRIPTION
alignment

The alignment to profile.

TYPE: MultipleSeqAlignment

gap_threshold

Fraction of gaps above which a column is flagged context-unreliable (default: 0.5).

TYPE: float DEFAULT: 0.5

RETURNS DESCRIPTION
ColumnProfile

The computed profile.

write_column_profile

write_column_profile(profile: ColumnProfile, path: str) -> str

Write the per-column gap/ambiguity profile to a TSV file.

PARAMETER DESCRIPTION
profile

The profile to write.

TYPE: ColumnProfile

path

Destination path.

TYPE: str

RETURNS DESCRIPTION
str

The path written.

write_qc_report

write_qc_report(alignment, profile: ColumnProfile, path: str) -> str

Write a short human-readable QC summary.

PARAMETER DESCRIPTION
alignment

The alignment that was profiled.

TYPE: MultipleSeqAlignment

profile

The computed profile.

TYPE: ColumnProfile

path

Destination path.

TYPE: str

RETURNS DESCRIPTION
str

The path written.