Mutation spaces

A MutationSpace represents the subset of a coding space centred around a single reference coding sequence. It can be constrained to mutate only certain positions or to sample sequences with a given distance from the reference.

Creating a mutation space

To sample mutants, start with a CodingSpace and a reference coding sequence.

from codeine import CodingSpace

space = CodingSpace('SEQVENCE')

muts = space.mutants(
    'AGCGAGCAGGTGGAGAACTGTGAG',
    max_nts=2,
)

print(muts.n_valid_variants)

Calling space.mutants(...) returns a MutationSpace object. Alternatively the MutationSpace can be constructed directly:

from codeine import CodingSpace, MutationSpace

space = CodingSpace('SEQVENCE')

muts = MutationSpace(
    space=space,
    cds='AGCGAGCAGGTGGAGAACTGTGAG',
    max_nts=2,
)

print(muts.n_valid_variants)

Here, max_nts=2 allows coding sequences with at most two nucleotide differences from the reference sequence.

Distance constraints

Mutation spaces can be constrained by nucleotide distance, codon distance, or both.

muts = space.mutants(
    reference_cds,
    min_nts=1,
    max_nts=3,
    min_codons=1,
    max_codons=2,
)

min_nts and max_nts count individual nucleotide changes (Hamming distance).

min_codons and max_codons count codons that differ, regardless of how many nucleotides differ within each codon. For example, ATGAAGTTT has codon distance 1 from ATGAAATTT.

For longer sequences, the number of variants available can grow significantly as the distance constraints are relaxed. For example:

from codeine import CodingSpace

space = CodingSpace('MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQANLAGKPE', seed=42)

muts = space.mutants(cds=space.sample())

muts.set_distance_constraints(max_nts=0)
print(muts.n_valid_variants) # 1

muts.set_distance_constraints(max_nts=1)
print(muts.n_valid_variants) # 86

muts.set_distance_constraints(max_nts=2)
print(muts.n_valid_variants) # 3599

muts.set_distance_constraints(max_nts=3)
print(muts.n_valid_variants) # 97690

Constraining free positions

Use free_positions to choose which amino acid positions are allowed to vary.

muts = space.mutants(
    reference_cds,
    free_positions=[4, 5, 6, 7, 8],
    max_codons=2,
)

cds = muts.sample()

You can reset free position constraints using muts.unfreeze_all().

Contiguous regions can be supplied using range.

muts = space.mutants(
    reference_cds,
    free_positions=range(20, 41),
    max_nts=5,
)

Don’t forget that positions are 1-based!

Enumerating & sampling variants

Mutation spaces can be counted, enumerated, and sampled just like ordinary coding spaces.

from codeine import CodingSpace

space = CodingSpace('SEQVENCE', seed=42)
muts = space.mutants(
    cds=space.sample(),
    min_nts=2,
    max_nts=2,
)

print(muts.n_valid_variants)

print(space.sample())

for cds in muts.enumerate():
    print(cds)

Inherited constraints

Mutation spaces inherit constraints from the parent CodingSpace.

from codeine import CodingSpace, RestrictionSite

space = CodingSpace(
        aa_seq,
        forbidden_motifs=[
            RestrictionSite.EcoRI,
            RestrictionSite.NotI,
        ],
        max_homopolymer=5,
)

muts = space.mutants(
    reference_cds,
    free_positions=range(10, 31),
    max_codons=3,
)

cds = muts.sample()

The sampled sequences satisfy the mutation-space constraints and the constraints from the original coding space.