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.

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.

plot_alignment

plot_alignment(
    output_file: str,
    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

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.