Sequences¶
Random sequences, shuffling, k-mer counts and backgrounds, sequence complexity, sliding windows, masking, and sampling sites from motifs.
create_sequences
¶
create_sequences(
alphabet: str = "DNA",
seqnum: int = 100,
seqlen: int = 100,
freqs: Sequence[float]
| Mapping[str, float]
| None = None,
seed: int | None = None,
nthreads: int = 1,
) -> list[str]
Random sequences.
alphabet is "DNA", "RNA", "AA" or a string of letters.
freqs gives the frequency of every k-mer of the alphabet, either as a
mapping from k-mers or in the sorted order that
get_kmers() gives; their number sets k, and
sequences are drawn from the Markov model of order k-1 they define. Letters
are uniform by default.
Examples:
>>> import universalmotif as um
>>> um.create_sequences(seqnum=3, seqlen=12, seed=1)
['TTTGGACAGCGC', 'TGGTAGCAAGTA', 'ATAGAAGGACGT']
AT-rich sequences, from letter frequencies:
>>> freqs = {"A": 0.4, "C": 0.1, "G": 0.1, "T": 0.4}
>>> um.create_sequences(seqnum=2, seqlen=12, freqs=freqs, seed=1)
['TTTTGAAATAGA', 'TGGTATCAATTA']
shuffle_sequences
¶
shuffle_sequences(
sequences: str | Sequence[str] | Mapping[str, str],
k: int = 1,
method: str = "euler",
seed: int | None = None,
window: bool = False,
window_size: float = 0.1,
window_overlap: float = 0.01,
nthreads: int = 1,
)
Shuffle sequences while preserving their k-mer composition.
The default method, "euler", keeps k-mer counts exactly, along
with the first and last k-1 letters. "linear" shuffles
non-overlapping blocks of k letters, keeping only those blocks' counts,
and "markov" draws a new sequence from the k-mer frequencies,
keeping them only approximately. With window, each
sliding window is shuffled in turn; window_size below 1 and
window_overlap between 0 and 1 are fractions of each sequence's
length.
Results depend on seed but not on nthreads.
Returns new sequences in the same form as the input, whether a string, a list or a dict with the same keys.
Examples:
>>> import universalmotif as um
>>> seq = "AACCGGTTACGTACGT"
>>> shuffled = um.shuffle_sequences(seq, k=2, seed=1)
>>> shuffled
'ACCGTACGGTAACGTT'
>>> um.count_kmers(shuffled, k=2).equals(um.count_kmers(seq, k=2))
True
shuffle_string
¶
shuffle_string(
string: str,
k: int = 1,
method: str = "euler",
seed: int | None = None,
) -> str
Shuffle one string while keeping its k-mer counts, as
shuffle_sequences() does.
Examples:
>>> import universalmotif as um
>>> um.shuffle_string("ACGTACGTTTGGCCAA", k=2, seed=1)
'ACCGTTGGCAACGTTA'
get_bkg
¶
get_bkg(
sequences: str | Sequence[str] | Mapping[str, str],
k: int | Sequence[int] = (1, 2, 3),
pseudocount: int = 0,
alphabet: str | Sequence[str] | None = None,
rc: bool = False,
merge: bool = True,
window: bool = False,
window_size: float = 0.1,
window_overlap: float = 0,
to_meme: str | PathLike[str] | IO[str] | None = None,
nthreads: int = 1,
) -> pl.DataFrame | None
k-mer counts and frequencies of sequences.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int | Sequence[int]
|
k-mer sizes to count. |
(1, 2, 3)
|
pseudocount
|
int
|
Added to every count. |
0
|
alphabet
|
str | Sequence[str] | None
|
Letters to count. Sequences made only of A, C, G, T and N count as DNA and those made of A, C, G, U and N as RNA, with their four letters as the default; otherwise the default is the letters in the sequences. |
None
|
rc
|
bool
|
Also count the reverse complements. |
False
|
merge
|
bool
|
Combine all sequences into one set of counts; otherwise each sequence gets its own rows. |
True
|
window
|
bool
|
Count in sliding windows. Values of |
False
|
window_size
|
bool
|
Count in sliding windows. Values of |
False
|
window_overlap
|
bool
|
Count in sliding windows. Values of |
False
|
to_meme
|
str | PathLike[str] | IO[str] | None
|
A path or text file to write a MEME background file to instead of
returning the counts. This needs |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A DataFrame with columns |
Examples:
>>> import universalmotif as um
>>> seqs = um.example_sequences()
>>> um.get_bkg(seqs, k=1).rows()
[('A', 32793, 0.32793), ('C', 17095, 0.17095), ('G', 17101, 0.17101), ('T', 33011, 0.33011)]
>>> um.get_bkg(seqs, k=[1, 2]).shape
(20, 3)
count_kmers
¶
count_kmers(
string: str,
k: int = 1,
alph: str | Sequence[str] | None = None,
) -> pl.DataFrame
Count the k-mers in a string.
Every k-mer of alph, which defaults to the letters in the string,
gets a row in sorted order; k-mers with letters outside alph are not
counted. Returns a DataFrame with columns kmer and count, as in
get_bkg().
Examples:
>>> import universalmotif as um
>>> um.count_kmers("AACGTTAC").rows()
[('A', 3), ('C', 2), ('G', 1), ('T', 2)]
>>> counts = um.count_kmers("AACGTTAC", k=2)
>>> counts.shape
(16, 2)
>>> counts.filter(counts["count"] > 0).rows()
[('AA', 1), ('AC', 2), ('CG', 1), ('GT', 1), ('TA', 1), ('TT', 1)]
get_kmers
¶
get_kmers(
letters: str | Sequence[str], k: int = 1
) -> list[str]
All k-mers of some letters, in order, with the first position varying slowest. The letters are used in the order given.
Examples:
>>> import universalmotif as um
>>> um.get_kmers("AC", k=2)
['AA', 'AC', 'CA', 'CC']
>>> len(um.get_kmers("ACGT", k=3))
64
calc_windows
¶
calc_windows(
n: int,
window: int = 1,
overlap: int = 0,
return_incomp: bool = True,
) -> pl.DataFrame
Start and end positions of sliding windows over a sequence of length
n, counted from 0 with the end left out, so that each window is
sequence[start:end].
The last window may be shorter than the others unless return_incomp
is false. A window wider than n shrinks to n.
Examples:
>>> import universalmotif as um
>>> um.calc_windows(11, window=4, overlap=1).rows()
[(0, 4), (3, 7), (6, 10), (9, 11)]
>>> um.calc_windows(11, window=4, overlap=1, return_incomp=False).rows()
[(0, 4), (3, 7), (6, 10)]
window_string
¶
window_string(
string: str,
window: int = 1,
overlap: int = 0,
return_incomp: bool = True,
) -> list[str]
Split a string into sliding windows, as laid out by
calc_windows().
Examples:
>>> import universalmotif as um
>>> um.window_string("ACGTACGTACG", window=4)
['ACGT', 'ACGT', 'ACG']
>>> um.window_string("ACGTACGTACG", window=4, overlap=1)
['ACGT', 'TACG', 'GTAC', 'CG']
slide_fun
¶
slide_fun(
string: str,
fun: Callable[[str], Any],
window: int = 1,
overlap: int = 0,
return_incomp: bool = True,
) -> list[Any]
Apply fun to each sliding window of string, as made by
window_string(). A window longer than the
string is shortened to it when return_incomp is set and is an error
otherwise.
Examples:
>>> import universalmotif as um
>>> def gc(window):
... return (window.count("G") + window.count("C")) / len(window)
>>> um.slide_fun("ACGTTTAGCAGG", gc, window=4)
[0.5, 0.25, 0.75]
calc_complexity
¶
calc_complexity(
string: str | Sequence[str],
complexity_method: str = "WoottonFederhen",
alph: str | Sequence[str] | None = None,
trifonov_max_word_size: int = 7,
)
Sequence complexity.
complexity_method is one of "WoottonFederhen", its approximation
"WoottonFederhenFast", "Trifonov", "TrifonovFast" or
"DUST". The methods come from Wootton and Federhen 1993, Trifonov
1990 and Morgulis et al. 2006, and lower DUST values mean higher
complexity. alph gives the possible letters. By default it is ACGT
when the strings hold only those letters and N, ACGU likewise for RNA,
and otherwise every letter found in the strings, so that all strings are
scored against the same alphabet. Returns a float for one string and a
numpy array for several.
Examples:
>>> import universalmotif as um
>>> round(um.calc_complexity("ACGTTGCAAC"), 3)
0.731
>>> um.calc_complexity(["ACGTTGCAAC", "ATATATATAT"], alph="ACGT").round(3).tolist()
[0.731, 0.399]
sequence_complexity
¶
sequence_complexity(
sequences: str | Sequence[str] | Mapping[str, str],
window_size: float = 20,
window_overlap: float | None = None,
method: str = "WoottonFederhen",
trifonov_max_word_size: int = 7,
nthreads: int = 1,
) -> pl.DataFrame
Complexity in sliding windows along sequences.
window_size below 1 is a fraction of each sequence's length, and so
is window_overlap between 0 and 1, which defaults to half the
window, rounded. A window longer than a sequence shrinks to it. See
calc_complexity() for the methods. Returns a DataFrame with
columns sequence, start, end and complexity, where
positions count from 0 and leave the end out.
Examples:
>>> import universalmotif as um
>>> seqs = {"seq": "ACGTTGCAACATATATATATATATAT"}
>>> res = um.sequence_complexity(seqs, window_size=10, window_overlap=5)
>>> res.select("start", "end").rows()
[(0, 10), (5, 15), (10, 20), (15, 25), (20, 26)]
>>> res["complexity"].round(3).to_list()
[0.731, 0.644, 0.399, 0.399, 0.36]
mask_seqs
¶
mask_seqs(
sequences,
pattern: str,
rc: bool = False,
letter: str = "-",
alphabet: str = "DNA",
)
Replace every occurrence of pattern in the sequences with
letter. Overlapping occurrences are all masked and letters match in
either case. With rc, occurrences of the reverse complement of DNA
and RNA patterns are masked as well. The sequences come back in the form
they were given, whether a string, a list or a dict.
Examples:
>>> import universalmotif as um
>>> um.mask_seqs("AAATTTGCAAATTT", "AAA")
'---TTTGC---TTT'
>>> um.mask_seqs({"s1": "GATTACAGG", "s2": "TTGTAATCT"}, "GATTACA", rc=True)
{'s1': '-------GG', 's2': 'T-------T'}
mask_ranges
¶
mask_ranges(
sequences: Mapping[str, str], ranges, letter: str = "-"
) -> dict[str, str]
Replace the positions in ranges with letter.
sequences maps names to sequences and ranges names positions on
them, counted from 0 with the end left out as in a slice, either as
(chrom, start, end) tuples or
as a DataFrame with a start column, an end, stop or
width column, and the sequence names in a column called chrom,
seqnames, sequence, chr or chromosome, so that the hits
from scan_sequences() can be masked
directly. Ranges may overlap; ranges on unknown sequences or past their
ends are errors.
Examples:
>>> import universalmotif as um
>>> seqs = {"chr1": "ACGTACGTACGT", "chr2": "TTTTGGGG"}
>>> um.mask_ranges(seqs, [("chr1", 2, 6), ("chr2", 0, 2)])
{'chr1': 'AC----GTACGT', 'chr2': '--TTGGGG'}
sample_sites
¶
sample_sites(
motif: Motif, n: int = 100, seed: int | None = None
) -> list[str]
Draw n sites from a motif, each letter chosen with the motif's
probabilities at its position.
Examples:
>>> import universalmotif as um
>>> wbox = um.example_motifs()[5]
>>> wbox.consensus
'GBTTGACYS'
>>> um.sample_sites(wbox, n=3, seed=1)
['TTTTGACCG', 'CGTTGACCC', 'ACTTGACTG']
implant_motifs
¶
implant_motifs(
motifs: Motif | Iterable[Motif],
sequences: str | Sequence[str] | Mapping[str, str],
n_per_seq: int = 1,
rate: float | None = None,
positions: Sequence[Sequence[int]] | None = None,
strand: str = "both",
centre_bias: int = 1,
min_spacing: int = 0,
max_retries: int = 100,
seed: int | None = None,
return_indices: bool = False,
)
Plant sites sampled from DNA or RNA motifs into sequences.
Each sequence gets n_per_seq sites, a Poisson number with mean
rate times its length if rate is given, or one site at each of
its positions, given as starts counted from 0 with one list per
sequence.
Every site
comes from a motif chosen at random, on a random strand unless
strand="+", and overwrites the sequence where it lands.
Random positions are the mean of centre_bias uniform draws, so values
above 1 favour the middle of sequences, and keep at least
min_spacing letters from other sites; a site that cannot be placed
in max_retries attempts is skipped with a warning.
Returns the new sequences in the same form as the input, and with
return_indices also a DataFrame of the sites with the columns
sequence_i, motif_i, start, width, strand and
planted. The indices and start count from 0, and
planted is the site as it reads on the forward strand.
Examples:
>>> import universalmotif as um
>>> wbox = um.example_motifs()[5]
>>> seqs = um.create_sequences(seqnum=3, seqlen=20, seed=1)
>>> new, sites = um.implant_motifs(wbox, seqs, seed=1, return_indices=True)
>>> new
['TTTGGATCTTGACTATCGAA', 'TGGTAGGTCAAAGTGAGCTG', 'AGCTCGACCGGTCTGTCTAG']
>>> sites.select("sequence_i", "start", "strand", "planted").rows()
[(0, 6, '+', 'TCTTGACTA'), (1, 4, '-', 'AGGTCAAAG'), (2, 1, '+', 'GCTCGACCG')]