Spectrum classes#
The spectrum classes and their named-collection types.
Class for holding and manipulating a site-frequency spectrum. |
|
Class for holding and manipulating site-frequency spectra of multiple types. |
|
A joint (multi-population) site-frequency spectrum. |
|
A collection of joint (multi-population) site-frequency spectra keyed by type, the multi-population analogue of |
|
A 2-dimensional site-frequency spectrum, i.e. a square matrix whose entry |
|
The two-locus site-frequency spectrum under recombination: a square matrix whose entry |
|
A collection of two-site (two-locus) site-frequency spectra keyed by type, the two-dimensional analogue of |
|
Abstract base class for site-frequency spectrum containers. |
|
Abstract base class for a collection of site-frequency spectra keyed by type, for example the SFS stratified into neutral and selected sites. |
Spectrum#
- class Spectrum(data: Sequence[float])[source]#
Bases:
AbstractSpectrumClass for holding and manipulating a site-frequency spectrum.
Methods:
Initialize spectrum.
Convert to list.
Convert to Spectra object.
Save object to file.
Load object from file.
Convert to array.
Fold the site-frequency spectrum.
Introduce ancestral misidentification at rate epsilon.
Subsample spectrum to a given sample size.
Resample SFS assuming independent Poisson counts.
Check if the site-frequency spectrum is folded.
Normalize SFS so that all non-monomorphic counts add up to 1.
Copy the spectrum.
Create Spectrum from polymorphic counts only.
Create Spectrum from list.
Create Spectrum from polyDFE specification which treats the number of mutational target sites and the divergence counts separately.
Plot spectrum.
The standard (Kingman) neutral site-frequency spectrum for a sample of size
n.Alias of
kingman().Obtain a standard neutral SFS for a given theta and number of sites.
Scale the spectrum to a different theta value by
Load from a JSON string.
Convert to a JSON string.
- property n_polymorphic: float#
The total number of polymorphic sites.
- Returns:
Total number of polymorphic sites
- property theta: float#
Calculate site-wise population mutation rate using Watterson’s estimator. Note that theta is given per site, i.e. Watterson’s estimator is divided by the total number of sites (
n_sites).
- misidentify(epsilon: float)[source]#
Introduce ancestral misidentification at rate epsilon. Note that monomorphic counts won’t be affected.
- Parameters:
epsilon (
float) – Misidentification rate (0 <= epsilon <= 1)- Return type:
- Returns:
Spectrum with misidentification applied
- Raises:
ValueError – If epsilon is not between 0 and 1
- subsample(n: int, mode: Literal['random', 'probabilistic'] = 'probabilistic', seed: int | Generator = None)[source]#
Subsample spectrum to a given sample size.
Warning
If using the ‘random’ mode, The SFS counts are cast to integers before subsampling so this will only provide sensible results if the SFS counts are integers or if they are large enough to be approximated well by integers. The ‘probabilistic’ mode does not have this limitation.
- is_folded()[source]#
Check if the site-frequency spectrum is folded.
- Return type:
- Returns:
True if folded, False otherwise
- normalize()[source]#
Normalize SFS so that all non-monomorphic counts add up to 1.
- Return type:
- Returns:
Normalized spectrum
- static from_polydfe(polymorphic: Sequence, n_sites: float, n_div: float)[source]#
Create Spectrum from polyDFE specification which treats the number of mutational target sites and the divergence counts separately.
- plot(show: bool = True, file: str = None, title: str = None, log_scale: bool = False, show_monomorphic: bool = False, kwargs_legend: dict = {'prop': {'size': 8}}, ax: plt.Axes = None)[source]#
Plot spectrum.
- Parameters:
show (
bool) – Whether to show plot.file (
str) – File to save plot to.title (
str) – Title of plot.log_scale (
bool) – Whether to use log scale on y-axis.show_monomorphic (
bool) – Whether to show monomorphic counts.kwargs_legend (
dict) – Keyword arguments passed toplt.legend(). Only for Python visualization backend.ax (plt.Axes) – Axes to plot on. Only for Python visualization backend.
- Return type:
plt.Axes
- Returns:
Axes
- static kingman(n: int, n_monomorphic: int = 0)[source]#
The standard (Kingman) neutral site-frequency spectrum for a sample of size
n.
- static standard_kingman(n: int, n_monomorphic: int = 0)[source]#
Alias of
kingman().Deprecated since version 1.0.0: Use
kingman()instead.
- static get_neutral(theta: float, n_sites: float, n: int, r: Sequence[float] = None)[source]#
Obtain a standard neutral SFS for a given theta and number of sites.
- Parameters:
theta (
float) – Population mutation raten_sites (
float) – Number of total sitesn (
int) – Number of frequency classesr (
Sequence[float]) – Nuisance parameters that account for demography. An array of lengthn-1whose elements are multiplied element-wise with the polymorphic counts of the Kingman SFS. By default, no demography effects are considered which is equivalent tor = [1] * (n-1). Note that non-default values ofrwill also affect estimates of the population mutation rate.
- Return type:
- Returns:
Neutral SFS
- classmethod from_json(json: str)#
Load from a JSON string.
- Parameters:
json (
str) – JSON string.- Return type:
Self- Returns:
Spectrum
- Raises:
ValueError – If the payload does not decode to this class.
Spectra#
- class Spectra(data: Dict[str, Iterable])[source]#
Bases:
AbstractSpectraClass for holding and manipulating site-frequency spectra of multiple types.
Methods:
Initialize spectra.
Create from array of spectra.
Normalize spectra by sum of all entries.
Save object to file.
Convert to dictionary of spectrum objects.
Get representation as dataframe.
Convert to numpy array.
Convert to nested list.
Convert to dictionary.
Select types.
Copy object.
Get a Spectra object with zero counts but having the same shape and types as self.
Group over given levels and sum up spectra so the spectra are summed over the levels that were not specified.
Check whether column names contain dots.
Replace dots in column names with a given string.
Merge types of two Spectra objects.
Load from nested dictionary first indexed by types and then by samples.
Load Spectra object from dataframe.
Save object to file.
Create from dict of spectrum objects indexed by type.
Create from single spectrum object.
Convert to Spectrum object by summing over all types.
Visualize spectra.
Remove types whose spectra have no counts.
Remove types whose spectra have some zero entries.
Remove types whose spectra have fewer than equal
n_polymorphicpolymorphic sites.Rename types.
Prefix types, i.e. 'type' -> 'prefix.type' for all types.
Reorder levels.
Print spectra.
Fold spectra.
Subsample spectra to a given sample size.
Resample SFS assuming independent Poisson counts.
Check whether spectra are folded.
Sort types alphabetically.
- property n_monomorphic: Series#
The number of monomorphic sites.
- Returns:
Number of monomorphic sites
- property n_polymorphic: Series#
The total number of polymorphic sites per type.
- Returns:
Total number of polymorphic sites for each type
- static from_list(data: Sequence, types: List)[source]#
Create from array of spectra. Note that data.ndim needs to be 2.
- property n_sites: Series#
The number of mutational target sites which is the sum of all SFS entries.
- Returns:
Number of mutational target sites for each type
- property n_div: Series#
The number of divergence counts.
- Returns:
Number of divergence counts for each type
- property has_div: Series#
Whether n_div was specified.
- Returns:
Whether n_div was specified for each type
- property theta: Series#
Calculate site-wise population mutation rate using Watterson’s estimator. Note that theta is given per site, i.e. Watterson’s estimator is divided by the total number of sites (
n_sites).
- property Theta: Series#
Calculate genome-wide population mutation rate using Watterson’s estimator.
- normalize()[source]#
Normalize spectra by sum of all entries.
- Return type:
- Returns:
Normalized spectra
- select(keys: str | List[str] | ndarray | tuple, use_regex: bool = True)[source]#
Select types. Alias for __getitem__.
- get_empty()[source]#
Get a Spectra object with zero counts but having the same shape and types as self.
- Return type:
- Returns:
Spectra object with zero counts
- merge_groups(level: List[int] | int = 0)[source]#
Group over given levels and sum up spectra so the spectra are summed over the levels that were not specified.
- Parameters:
- Return type:
- Returns:
Spectra object with merged groups
- Raises:
ValueError – If some type has no name at one of the requested levels
- has_dots()[source]#
Check whether column names contain dots.
- Return type:
- Returns:
True if column names contain dots, False otherwise
- static from_dict(data: dict)[source]#
Load from nested dictionary first indexed by types and then by samples.
- static from_dataframe(data: DataFrame)[source]#
Load Spectra object from dataframe.
- Parameters:
data (
DataFrame) – Dataframe- Return type:
- Returns:
Spectra object
- static from_spectra(spectra: Dict[str, Spectrum])[source]#
Create from dict of spectrum objects indexed by type.
- static from_spectrum(sfs: Spectrum)[source]#
Create from single spectrum object. The type of the spectrum is set to ‘all’.
- to_spectrum()[source]#
Convert to Spectrum object by summing over all types.
- Return type:
- Returns:
Spectrum object
- plot(show: bool = True, file: str = None, title: str = None, log_scale: bool = False, use_subplots: bool = False, show_monomorphic: bool = False, kwargs_legend: dict = {'prop': {'size': 8}}, ax: plt.Axes = None)[source]#
Visualize spectra.
- Parameters:
show (
bool) – Whether to show the plot.file (
str) – File name to save the plot to.title (
str) – Plot title.log_scale (
bool) – Whether to use log scale on y-axis.use_subplots (
bool) – Whether to use subplots. Only for Python visualization backend.show_monomorphic (
bool) – Whether to show monomorphic sites.kwargs_legend (
dict) – Keyword arguments passed toplt.legend(). Only for Python visualization backend.ax (plt.Axes) – Axes to plot on. Only for Python visualization backend and if
use_subplotsisFalse.
- Return type:
plt.Axes
- Returns:
Axes
- drop_empty()[source]#
Remove types whose spectra have no counts.
- Return type:
- Returns:
Spectra with non-empty types
- drop_zero_entries()[source]#
Remove types whose spectra have some zero entries. Note that we ignore zero counts in the last entry i.e. fixed derived alleles.
- Return type:
- Returns:
Spectra with non-zero entries
- drop_sparse(n_polymorphic: int)[source]#
Remove types whose spectra have fewer than equal
n_polymorphicpolymorphic sites.
- subsample(n: int, mode: Literal['random', 'probabilistic'] = 'probabilistic', seed: int | Generator = None)[source]#
Subsample spectra to a given sample size.
Warning
If using the ‘random’ mode, The SFS counts are cast to integers before subsampling so this will only provide sensible results if the SFS counts are integers or if they are large enough to be approximated by integers. The ‘probabilistic’ mode does not have this limitation.
- property is_empty: bool#
Whether the collection holds no parsed mass, either because there are no types or because every spectrum is all zero. Counting types alone does not answer this for the two-site and joint collections, which always carry an
alltype even when no site made it into the spectra.- Returns:
True if nothing was counted.
JointSFS#
- class JointSFS(data: ndarray | list, pop_names: List[str] = None)[source]#
Bases:
AbstractSpectrumA joint (multi-population) site-frequency spectrum.
The data is a
P-dimensional array of shape(n_0 + 1, ..., n_{P-1} + 1)wherePis the number of populations and entry(k_0, ..., k_{P-1})counts sites (or branch length) withk_pderived alleles in populationp. For two populations this is a 2-dimensional array (analogous to but generally rectangular, unlike the squareTwoSFS); for three populations it is a 3-dimensional array, and so on.Methods:
Construct from a data array.
Marginalize the joint SFS onto a subset of populations by summing over the other populations.
Fold the joint SFS by the total derived count across populations, the dadi/moments convention: ancestral and derived is one site-level property, so every axis is reflected at once.
Check if the joint SFS is folded.
Plot the joint SFS as a 2-dimensional heatmap.
Plot the joint SFS of two populations as a surface, with the two allele-count axes on the horizontal plane and the number of sites as height.
Create a deep copy.
Load from file.
Load from a JSON string.
Save to file (in JSON format).
Convert to a JSON string.
- __init__(data: ndarray | list, pop_names: List[str] = None)[source]#
Construct from a data array.
- Parameters:
- Raises:
ValueError – If the data is not at least 1-dimensional or if the number of population names does not match the number of axes.
- marginalize(pops: Sequence[int])[source]#
Marginalize the joint SFS onto a subset of populations by summing over the other populations. This is useful for example to obtain a 2-dimensional view of a higher-dimensional joint SFS.
- Parameters:
pops (
Sequence[int]) – The population indices to keep, in the desired axis order.- Return type:
- Returns:
A joint SFS over the specified populations.
- Raises:
ValueError – If any population index is out of range.
- fold()[source]#
Fold the joint SFS by the total derived count across populations, the dadi/moments convention: ancestral and derived is one site-level property, so every axis is reflected at once. Entries above half the total sample size are emptied into their reflection, and entries on the boundary are shared between the two. This only makes sense for counts or frequencies, and folding a folded joint SFS is a no-op.
- Return type:
- Returns:
Folded joint SFS.
- is_folded()[source]#
Check if the joint SFS is folded.
- Return type:
- Returns:
Whether the joint SFS is folded.
- plot(pops: Tuple[int, int] = (0, 1), ax: plt.Axes = None, title: str = None, log_scale: bool = True, mask_monomorphic: bool = True, cbar_kws: Dict = None, show: bool = True)[source]#
Plot the joint SFS as a 2-dimensional heatmap. For more than two populations, the joint SFS is first marginalized onto the two requested populations (summing over the others). The colour scale is logarithmic by default, since the joint SFS is heavily skewed toward the low-frequency corner.
- Parameters:
pops (
Tuple[int,int]) – The two population indices to plot (y-axis, x-axis).ax (plt.Axes) – Axes to plot on.
title (
str) – Title of the plot.log_scale (
bool) – Whether to use a logarithmic color scale (defaultTrue).mask_monomorphic (
bool) – Whether to mask the monomorphic corners (all-zero and all-derived).cbar_kws (
Dict) – Keyword arguments for the color bar.show (
bool) – Whether to show the plot.
- Return type:
plt.Axes
- Returns:
Axes.
- Raises:
ValueError – If not exactly two populations are requested or the marginalized data is not 2-dimensional.
- plot_surface(pops: Tuple[int, int] = (0, 1), ax: plt.Axes = None, title: str = None, log_scale: bool = False, mask_monomorphic: bool = True, cmap: str = 'viridis', show: bool = True)[source]#
Plot the joint SFS of two populations as a surface, with the two allele-count axes on the horizontal plane and the number of sites as height. For more than two populations, the joint SFS is first marginalized onto the two requested populations (summing over the others).
- Parameters:
pops (
Tuple[int,int]) – The two population indices to plot (y-axis, x-axis).ax (plt.Axes) – Axes to plot on.
title (
str) – Title of the plot.log_scale (
bool) – Whether to use a logarithmic color scale.mask_monomorphic (
bool) – Whether to mask the monomorphic corners (all-zero and all-derived).cmap (
str) – The colormap.show (
bool) – Whether to show the plot.
- Return type:
plt.Axes
- Returns:
Axes.
- Raises:
ValueError – If not exactly two populations are requested or the marginalized data is not 2-dimensional.
- copy()#
Create a deep copy.
- Return type:
Self- Returns:
Deep copy.
- classmethod from_file(file: str)#
Load from file.
- Parameters:
file (
str) – File path.- Return type:
Self- Returns:
Spectrum
- classmethod from_json(json: str)#
Load from a JSON string.
- Parameters:
json (
str) – JSON string.- Return type:
Self- Returns:
Spectrum
- Raises:
ValueError – If the payload does not decode to this class.
JointSpectra#
- class JointSpectra(data: Dict[str, JointSFS | ndarray], pop_names: List[str] = None)[source]#
Bases:
_DictSpectraSerialization,AbstractSpectraA collection of joint (multi-population) site-frequency spectra keyed by type, the multi-population analogue of
Spectra. This is the return type ofparse()when the parser is given populations, with oneJointSFSper stratification type (or a singlealltype when no stratifications are used).Methods:
Construct from a dictionary of joint spectra.
Marginalize every joint SFS onto a subset of populations (see
JointSFS.marginalize()).Get the joint spectra as a dictionary keyed by type.
Load from file.
Load from a JSON string.
Save to file (in JSON format).
Convert to a JSON string.
- __init__(data: Dict[str, JointSFS | ndarray], pop_names: List[str] = None)[source]#
Construct from a dictionary of joint spectra.
- property pop_names: List[str]#
Names of the populations (one per axis), taken from the first type.
- Raises:
ValueError – If the collection is empty.
- property n_pops: int#
Number of populations (dimensions of each joint SFS).
- Raises:
ValueError – If the collection is empty.
- property shape: Tuple[int, ...]#
Shape of each joint SFS.
- Raises:
ValueError – If the collection is empty.
- property all: JointSFS#
The
alltype, equal to the sum of all joint spectra.- Raises:
ValueError – If the collection is empty.
- marginalize(pops: Sequence[int])[source]#
Marginalize every joint SFS onto a subset of populations (see
JointSFS.marginalize()).
- classmethod from_file(file: str)#
Load from file.
- Parameters:
file (
str) – File path.- Return type:
Self- Returns:
Spectra.
- classmethod from_json(json: str)#
Load from a JSON string.
- Parameters:
json (
str) – JSON string.- Return type:
Self- Returns:
Spectra.
- Raises:
ValueError – If the payload does not decode to this class.
- property is_empty: bool#
Whether the collection holds no parsed mass, either because there are no types or because every spectrum is all zero. Counting types alone does not answer this for the two-site and joint collections, which always carry an
alltype even when no site made it into the spectra.- Returns:
True if nothing was counted.
TwoSFS#
- class TwoSFS(data: ndarray | list)[source]#
Bases:
AbstractSpectrumA 2-dimensional site-frequency spectrum, i.e. a square matrix whose entry
(i, j)relates the number of derived alleles at a pair of frequency classesiandjof a single population (for example the second moment of the SFS). For the joint spectrum across populations, which is generally rectangular, seeJointSFS.Methods:
Construct from a data matrix.
Check if the 2-SFS is folded.
Fold the 2-SFS by adding up
iandn - ifor both axes.Symmetrize the 2-SFS so that
i, jandj, iare the same.The interior (segregating) block of the 2-SFS: pairs for which both sites carry between
1andn - 1derived alleles, i.e. both are polymorphic.The class-resolved branch-length covariance
Cov(L_i, L_j)between two linked sites, returned over the segregating interior of a full-sizeTwoSFS(monomorphic bins zeroed).The class-resolved branch-length correlation corresponding to
cov():R[i, j] = Cov(L_i, L_j) / sqrt(Var(L_i) Var(L_j))over the segregating interior, standardized by the branch-length variances (the interior diagonal of the full-spectrum covariance).The frequency pointwise mutual information (fPMI) of two linked sites, over the segregating interior.
Fill the monomorphic entries (first and last row and column) of the 2-SFS.
Plot the 2-SFS as a heatmap.
Plot the 2-SFS as a surface.
Mask both the primary and secondary diagonal entries of the 2-SFS matrix.
Get the maximum absolute entry of the 2-SFS matrix.
Mask the upper triangular entries of the 2-SFS matrix.
Create a deep copy.
Load from file.
Load from a JSON string.
Save to file (in JSON format).
Convert to a JSON string.
- __init__(data: ndarray | list)[source]#
Construct from a data matrix.
- Parameters:
- Raises:
ValueError – If the data is not a square 2-dimensional array.
- n: int = None#
The matrix dimension along one axis (the sample size plus one, i.e. the number of derived-count bins).
- is_folded()[source]#
Check if the 2-SFS is folded.
- Return type:
- Returns:
Whether the 2-SFS is folded.
- fold()[source]#
Fold the 2-SFS by adding up
iandn - ifor both axes. Note that this only makes sense for counts or frequencies.- Return type:
- Returns:
Folded 2-SFS.
- symmetrize()[source]#
Symmetrize the 2-SFS so that
i, jandj, iare the same.- Return type:
- Returns:
Symmetric 2-SFS.
- interior(normalize: bool = False)[source]#
The interior (segregating) block of the 2-SFS: pairs for which both sites carry between
1andn - 1derived alleles, i.e. both are polymorphic. The two monomorphic bins (all-ancestral and all-derived) are excluded, matching the polymorphic block of the standard site-frequency spectrum.- Parameters:
normalize (
bool) – IfTrue, return the conditional joint distributionP(i, j | both polymorphic)instead of the raw pair counts.- Return type:
- Returns:
The
(n - 1) x (n - 1)interior block, or its normalization.- Raises:
ValueError – If
normalizeis requested but the interior is empty.
- cov()[source]#
The class-resolved branch-length covariance
Cov(L_i, L_j)between two linked sites, returned over the segregating interior of a full-sizeTwoSFS(monomorphic bins zeroed). Entry(i, j)is the covariance of the branch lengths subtendingiandjderived alleles at the two loci; a positive entry means the two classes co-vary positively across linked sites. It is the deviation of the full joint class distribution from independence,P(i, j) - P(i) P(j), normalized over all pairs so thatP(i)is the true site-frequency spectrum. It therefore matches PhaseGen’ssfs2.mean - outer(sfs.mean)(up to the constant mutational scale) and reproduces the multiple-merger signal, unlike a polymorphic-only normalization.This requires the monomorphic-site counts: parse an all-sites input with the monomorphic (invariant) sites specified. With only a
TargetSiteCounter(extrapolated, not real, monomorphic counts) the result is approximate and can be unreliable, as the interior residual is hypersensitive to the target-site count; use a real all-sites input for an accurate covariance, orfpmi()for a monomorphic-free statistic on polymorphic-only data. For a valid two-SFS the interior diagonal is a nonnegative branch-length variance; an arbitrary (non-coalescent) input can give a non-positive-semidefinite result.- Return type:
- Returns:
The branch-length covariance over the interior, embedded in a full-size
TwoSFS.- Raises:
ValueError – If the 2-SFS is empty, non-finite, or carries no monomorphic-involving pairs.
- corr()[source]#
The class-resolved branch-length correlation corresponding to
cov():R[i, j] = Cov(L_i, L_j) / sqrt(Var(L_i) Var(L_j))over the segregating interior, standardized by the branch-length variances (the interior diagonal of the full-spectrum covariance). For a valid (coalescent) two-SFS this is a proper correlation, matching PhaseGen’s branch-length correlation, with entries in[-1, 1]and a unit diagonal. Likecov(), it requires the monomorphic-site counts and is only approximate under aTargetSiteCounter(seecov();fpmi()needs no monomorphic sites). Classes with negligible branch-length variance are returned as zero, and because the underlying quantity is a cross-covariance between the two loci (not a within-locus covariance matrix), the entries are clipped to[-1, 1]as a safeguard for arbitrary input.- Return type:
- Returns:
The branch-length correlation over the interior, embedded in a full-size
TwoSFS.- Raises:
ValueError – If the 2-SFS is empty, non-finite, or carries no monomorphic-involving pairs.
- fpmi()[source]#
The frequency pointwise mutual information (fPMI) of two linked sites, over the segregating interior. For the normalized joint distribution
p(i, j)of the derived-allele classes of paired polymorphic sites, entry(i, j)islog[p(i, j) / (p(i) p(j))], the log-ratio of the observed joint to the product of its marginals: positive where classesiandjco-occur more often than under independence, negative where they co-occur less, and zero for independent loci.Unlike
cov()/corr(), fPMI is a ratio computed purely from the polymorphic interior, so it needs no monomorphic sites and is exactly invariant to them: a polymorphic-only (SNP) spectrum gives the same result as the all-sites spectrum. It is the statistic of Fenton, Rice, Novembre and Desai (2025, Genetics 229(4):iyaf023, https://doi.org/10.1093/genetics/iyaf023) for detecting departures from Kingman coalescence; its low-frequency associations shift toward positive under multiple-merger genealogies.- Return type:
- Returns:
The fPMI over the interior, embedded in a full-size
TwoSFS; classes absent from the spectrum are returned as zero.- Raises:
ValueError – If the 2-SFS is empty or non-finite, or has no polymorphic pairs.
- fill_monomorphic(fill_value=nan)[source]#
Fill the monomorphic entries (first and last row and column) of the 2-SFS.
- Parameters:
fill_value – Value to fill the monomorphic entries with.
- Return type:
- Returns:
2-SFS
- plot(ax: plt.Axes = None, title: str = None, max_abs: float = None, log_scale: bool = False, cbar_kws: Dict = None, show: bool = True)[source]#
Plot the 2-SFS as a heatmap.
- Parameters:
- Return type:
plt.Axes
- Returns:
Axes.
- plot_surface(ax: plt.Axes = None, title: str = None, max_abs: float = None, vmin: float = None, vmax: float = None, show: bool = True)[source]#
Plot the 2-SFS as a surface.
- mask_diagonal(fill_value=nan)[source]#
Mask both the primary and secondary diagonal entries of the 2-SFS matrix.
The primary diagonal runs from the top-left to the bottom-right, and the secondary diagonal runs from the top-right to the bottom-left.
- Parameters:
fill_value – The value to fill the diagonal entries with.
- Return type:
- Returns:
A new 2-SFS with both diagonals masked.
- get_max_abs()[source]#
Get the maximum absolute entry of the 2-SFS matrix.
- Return type:
- Returns:
The maximum absolute entry.
- mask_upper(fill_value=nan)[source]#
Mask the upper triangular entries of the 2-SFS matrix.
- Parameters:
fill_value – The value to fill the upper triangular entries with.
- Return type:
- Returns:
A new 2-SFS with upper triangular entries masked.
- copy()#
Create a deep copy.
- Return type:
Self- Returns:
Deep copy.
- classmethod from_file(file: str)#
Load from file.
- Parameters:
file (
str) – File path.- Return type:
Self- Returns:
Spectrum
- classmethod from_json(json: str)#
Load from a JSON string.
- Parameters:
json (
str) – JSON string.- Return type:
Self- Returns:
Spectrum
- Raises:
ValueError – If the payload does not decode to this class.
TwoLocusSFS#
- class TwoLocusSFS(data: ndarray | list)[source]#
Bases:
TwoSFSThe two-locus site-frequency spectrum under recombination: a square matrix whose entry
(i, j)is the expected product of the branch length subtendingisamples at locus 0 andjsamples at locus 1, for two loci separated by a given recombination rater. It interpolates between the within-tree cross-moment of the SFS atr = 0(fully linked) and the outer product of the marginal SFS asrtends to infinity (independent loci).Methods:
Construct from a data matrix.
Create a deep copy.
The class-resolved branch-length correlation corresponding to
cov():R[i, j] = Cov(L_i, L_j) / sqrt(Var(L_i) Var(L_j))over the segregating interior, standardized by the branch-length variances (the interior diagonal of the full-spectrum covariance).The class-resolved branch-length covariance
Cov(L_i, L_j)between two linked sites, returned over the segregating interior of a full-sizeTwoSFS(monomorphic bins zeroed).Fill the monomorphic entries (first and last row and column) of the 2-SFS.
Fold the 2-SFS by adding up
iandn - ifor both axes.The frequency pointwise mutual information (fPMI) of two linked sites, over the segregating interior.
Load from file.
Load from a JSON string.
Get the maximum absolute entry of the 2-SFS matrix.
The interior (segregating) block of the 2-SFS: pairs for which both sites carry between
1andn - 1derived alleles, i.e. both are polymorphic.Check if the 2-SFS is folded.
Mask both the primary and secondary diagonal entries of the 2-SFS matrix.
Mask the upper triangular entries of the 2-SFS matrix.
Plot the 2-SFS as a heatmap.
Plot the 2-SFS as a surface.
Symmetrize the 2-SFS so that
i, jandj, iare the same.Save to file (in JSON format).
Convert to a JSON string.
- __init__(data: ndarray | list)#
Construct from a data matrix.
- Parameters:
- Raises:
ValueError – If the data is not a square 2-dimensional array.
- copy()#
Create a deep copy.
- Return type:
Self- Returns:
Deep copy.
- corr()#
The class-resolved branch-length correlation corresponding to
cov():R[i, j] = Cov(L_i, L_j) / sqrt(Var(L_i) Var(L_j))over the segregating interior, standardized by the branch-length variances (the interior diagonal of the full-spectrum covariance). For a valid (coalescent) two-SFS this is a proper correlation, matching PhaseGen’s branch-length correlation, with entries in[-1, 1]and a unit diagonal. Likecov(), it requires the monomorphic-site counts and is only approximate under aTargetSiteCounter(seecov();fpmi()needs no monomorphic sites). Classes with negligible branch-length variance are returned as zero, and because the underlying quantity is a cross-covariance between the two loci (not a within-locus covariance matrix), the entries are clipped to[-1, 1]as a safeguard for arbitrary input.- Return type:
- Returns:
The branch-length correlation over the interior, embedded in a full-size
TwoSFS.- Raises:
ValueError – If the 2-SFS is empty, non-finite, or carries no monomorphic-involving pairs.
- cov()#
The class-resolved branch-length covariance
Cov(L_i, L_j)between two linked sites, returned over the segregating interior of a full-sizeTwoSFS(monomorphic bins zeroed). Entry(i, j)is the covariance of the branch lengths subtendingiandjderived alleles at the two loci; a positive entry means the two classes co-vary positively across linked sites. It is the deviation of the full joint class distribution from independence,P(i, j) - P(i) P(j), normalized over all pairs so thatP(i)is the true site-frequency spectrum. It therefore matches PhaseGen’ssfs2.mean - outer(sfs.mean)(up to the constant mutational scale) and reproduces the multiple-merger signal, unlike a polymorphic-only normalization.This requires the monomorphic-site counts: parse an all-sites input with the monomorphic (invariant) sites specified. With only a
TargetSiteCounter(extrapolated, not real, monomorphic counts) the result is approximate and can be unreliable, as the interior residual is hypersensitive to the target-site count; use a real all-sites input for an accurate covariance, orfpmi()for a monomorphic-free statistic on polymorphic-only data. For a valid two-SFS the interior diagonal is a nonnegative branch-length variance; an arbitrary (non-coalescent) input can give a non-positive-semidefinite result.- Return type:
- Returns:
The branch-length covariance over the interior, embedded in a full-size
TwoSFS.- Raises:
ValueError – If the 2-SFS is empty, non-finite, or carries no monomorphic-involving pairs.
- fill_monomorphic(fill_value=nan)#
Fill the monomorphic entries (first and last row and column) of the 2-SFS.
- Parameters:
fill_value – Value to fill the monomorphic entries with.
- Return type:
- Returns:
2-SFS
- fold()#
Fold the 2-SFS by adding up
iandn - ifor both axes. Note that this only makes sense for counts or frequencies.- Return type:
- Returns:
Folded 2-SFS.
- fpmi()#
The frequency pointwise mutual information (fPMI) of two linked sites, over the segregating interior. For the normalized joint distribution
p(i, j)of the derived-allele classes of paired polymorphic sites, entry(i, j)islog[p(i, j) / (p(i) p(j))], the log-ratio of the observed joint to the product of its marginals: positive where classesiandjco-occur more often than under independence, negative where they co-occur less, and zero for independent loci.Unlike
cov()/corr(), fPMI is a ratio computed purely from the polymorphic interior, so it needs no monomorphic sites and is exactly invariant to them: a polymorphic-only (SNP) spectrum gives the same result as the all-sites spectrum. It is the statistic of Fenton, Rice, Novembre and Desai (2025, Genetics 229(4):iyaf023, https://doi.org/10.1093/genetics/iyaf023) for detecting departures from Kingman coalescence; its low-frequency associations shift toward positive under multiple-merger genealogies.- Return type:
- Returns:
The fPMI over the interior, embedded in a full-size
TwoSFS; classes absent from the spectrum are returned as zero.- Raises:
ValueError – If the 2-SFS is empty or non-finite, or has no polymorphic pairs.
- classmethod from_file(file: str)#
Load from file.
- Parameters:
file (
str) – File path.- Return type:
Self- Returns:
Spectrum
- classmethod from_json(json: str)#
Load from a JSON string.
- Parameters:
json (
str) – JSON string.- Return type:
Self- Returns:
Spectrum
- Raises:
ValueError – If the payload does not decode to this class.
- get_max_abs()#
Get the maximum absolute entry of the 2-SFS matrix.
- Return type:
- Returns:
The maximum absolute entry.
- interior(normalize: bool = False)#
The interior (segregating) block of the 2-SFS: pairs for which both sites carry between
1andn - 1derived alleles, i.e. both are polymorphic. The two monomorphic bins (all-ancestral and all-derived) are excluded, matching the polymorphic block of the standard site-frequency spectrum.- Parameters:
normalize (
bool) – IfTrue, return the conditional joint distributionP(i, j | both polymorphic)instead of the raw pair counts.- Return type:
- Returns:
The
(n - 1) x (n - 1)interior block, or its normalization.- Raises:
ValueError – If
normalizeis requested but the interior is empty.
- mask_diagonal(fill_value=nan)#
Mask both the primary and secondary diagonal entries of the 2-SFS matrix.
The primary diagonal runs from the top-left to the bottom-right, and the secondary diagonal runs from the top-right to the bottom-left.
- Parameters:
fill_value – The value to fill the diagonal entries with.
- Return type:
- Returns:
A new 2-SFS with both diagonals masked.
- mask_upper(fill_value=nan)#
Mask the upper triangular entries of the 2-SFS matrix.
- Parameters:
fill_value – The value to fill the upper triangular entries with.
- Return type:
- Returns:
A new 2-SFS with upper triangular entries masked.
- n: int = None#
The matrix dimension along one axis (the sample size plus one, i.e. the number of derived-count bins).
- plot(ax: plt.Axes = None, title: str = None, max_abs: float = None, log_scale: bool = False, cbar_kws: Dict = None, show: bool = True)#
Plot the 2-SFS as a heatmap.
- Parameters:
- Return type:
plt.Axes
- Returns:
Axes.
- plot_surface(ax: plt.Axes = None, title: str = None, max_abs: float = None, vmin: float = None, vmax: float = None, show: bool = True)#
Plot the 2-SFS as a surface.
- symmetrize()#
Symmetrize the 2-SFS so that
i, jandj, iare the same.- Return type:
- Returns:
Symmetric 2-SFS.
TwoSpectra#
- class TwoSpectra(data: Dict[str, TwoSFS | ndarray])[source]#
Bases:
_DictSpectraSerialization,AbstractSpectraA collection of two-site (two-locus) site-frequency spectra keyed by type, the two-dimensional analogue of
Spectra. This is the return type ofparse()when the two-SFS is parsed with stratifications, holding oneTwoSFSper stratification type. Because the two-SFS pairs sites, stratified parsing counts only within-stratum pairs, so summing the per-type spectra does not in general recover the unstratified two-SFS (cross-stratum pairs are not counted).Methods:
Construct from a dictionary of two-site spectra.
Load from file.
Load from a JSON string.
Save to file (in JSON format).
Convert to a JSON string.
Get the two-site spectra as a dictionary keyed by type.
- __init__(data: Dict[str, TwoSFS | ndarray])[source]#
Construct from a dictionary of two-site spectra.
- property shape: Tuple[int, ...]#
Shape of each two-site SFS.
- Raises:
ValueError – If the collection is empty.
- property all: TwoSFS#
The
alltype, equal to the sum of the per-type two-site spectra (the within-stratum pairs pooled over strata; cross-stratum pairs remain uncounted).- Raises:
ValueError – If the collection is empty.
- classmethod from_file(file: str)#
Load from file.
- Parameters:
file (
str) – File path.- Return type:
Self- Returns:
Spectra.
- classmethod from_json(json: str)#
Load from a JSON string.
- Parameters:
json (
str) – JSON string.- Return type:
Self- Returns:
Spectra.
- Raises:
ValueError – If the payload does not decode to this class.
- property is_empty: bool#
Whether the collection holds no parsed mass, either because there are no types or because every spectrum is all zero. Counting types alone does not answer this for the two-site and joint collections, which always carry an
alltype even when no site made it into the spectra.- Returns:
True if nothing was counted.
AbstractSpectrum#
- class AbstractSpectrum[source]#
Bases:
ABCAbstract base class for site-frequency spectrum containers.
A concrete spectrum wraps a numpy array in
data: the one-dimensionalSpectrum, the two-dimensionalTwoSFS(with itsTwoLocusSFSspecialization), and the multi-populationJointSFS. This base supplies the shared array interface and JSON serialization; subclasses add dimension-specific behaviour such as folding and plotting.Methods:
Create a deep copy.
Save to file (in JSON format).
Convert to a JSON string.
Load from file.
Load from a JSON string.
Plot the spectrum.
- classmethod from_file(file: str)[source]#
Load from file.
- Parameters:
file (
str) – File path.- Return type:
Self- Returns:
Spectrum
- classmethod from_json(json: str)[source]#
Load from a JSON string.
- Parameters:
json (
str) – JSON string.- Return type:
Self- Returns:
Spectrum
- Raises:
ValueError – If the payload does not decode to this class.
AbstractSpectra#
- class AbstractSpectra[source]#
Bases:
ABCAbstract base class for a collection of site-frequency spectra keyed by type, for example the SFS stratified into neutral and selected sites. The concrete backings share this interface but not their storage:
Spectrais DataFrame-backed and one-dimensional, whileJointSpectrais dict-backed and holds multi-populationJointSFSobjects. Code needing only the common collection operations can be written against this base regardless of dimensionality.Methods:
- abstract property all: AbstractSpectrum#
The
alltype, equal to the sum of all spectra.
- property is_empty: bool#
Whether the collection holds no parsed mass, either because there are no types or because every spectrum is all zero. Counting types alone does not answer this for the two-site and joint collections, which always carry an
alltype even when no site made it into the spectra.- Returns:
True if nothing was counted.