sonic-spatial 1.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sonic/__init__.py +73 -0
- sonic/_rasterize.py +95 -0
- sonic/_version.py +24 -0
- sonic/api.py +182 -0
- sonic/comparators/__init__.py +33 -0
- sonic/comparators/base.py +1323 -0
- sonic/comparators/features.py +1250 -0
- sonic/comparators/grid.py +588 -0
- sonic/comparators/irregular.py +600 -0
- sonic/comparators/multisample.py +1669 -0
- sonic/comparators/normalization.py +375 -0
- sonic/detectors/__init__.py +18 -0
- sonic/detectors/base.py +116 -0
- sonic/detectors/grid.py +680 -0
- sonic/detectors/irregular.py +1415 -0
- sonic/kernels/__init__.py +35 -0
- sonic/kernels/base.py +902 -0
- sonic/kernels/fft.py +1067 -0
- sonic/kernels/matrix.py +450 -0
- sonic/kernels/nufft.py +1482 -0
- sonic/statistics.py +1369 -0
- sonic/utils.py +491 -0
- sonic_spatial-1.0.0rc1.dist-info/METADATA +321 -0
- sonic_spatial-1.0.0rc1.dist-info/RECORD +27 -0
- sonic_spatial-1.0.0rc1.dist-info/WHEEL +5 -0
- sonic_spatial-1.0.0rc1.dist-info/licenses/LICENSE +29 -0
- sonic_spatial-1.0.0rc1.dist-info/top_level.txt +1 -0
sonic/__init__.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""
|
|
2
|
+
sonic: kernel-based spatial pattern detection and comparison for spatial omics.
|
|
3
|
+
|
|
4
|
+
The public top-level API is organised in four layers:
|
|
5
|
+
|
|
6
|
+
1. **Kernels** — :class:`MatrixKernel` (dense / sparse), :class:`FFTKernel`
|
|
7
|
+
(regular grid), :class:`NUFFTKernel` (irregular 2D coordinates). The
|
|
8
|
+
:class:`~sonic.kernels.Kernel` and
|
|
9
|
+
:class:`~sonic.kernels.MatrixKernelBase` ABCs live in
|
|
10
|
+
:mod:`sonic.kernels` and are intended for backend authors.
|
|
11
|
+
2. **Statistical tests** — :func:`spatial_q_test` and :func:`spatial_r_test`.
|
|
12
|
+
A single entry point per test dispatches on the kernel type (matrix, FFT,
|
|
13
|
+
or NUFFT). Signature: ``(x, kernel, null_params=None, return_pval=True,
|
|
14
|
+
is_standardized=False)``.
|
|
15
|
+
3. **Detectors** — :class:`DetectorIrregular` consumes :class:`anndata.AnnData`
|
|
16
|
+
(irregular grids, matrix/NUFFT backends); :class:`DetectorGrid` consumes
|
|
17
|
+
:class:`spatialdata.SpatialData` (regular grids, FFT backend).
|
|
18
|
+
4. **Comparators** — cross-sample pattern comparison:
|
|
19
|
+
:class:`ComparatorIrregular` on a list of AnnData (NUFFT backend);
|
|
20
|
+
:class:`ComparatorGrid` on a list of SpatialData (FFT backend).
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import logging
|
|
24
|
+
|
|
25
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
26
|
+
|
|
27
|
+
# Version resolution order: prefer the file written by ``setuptools-scm`` at
|
|
28
|
+
# build time (``src/sonic/_version.py`` — see ``[tool.setuptools_scm]`` in
|
|
29
|
+
# ``pyproject.toml``), fall back to installed-package metadata, then to a
|
|
30
|
+
# last-known release string for unbuilt / shallow-clone checkouts.
|
|
31
|
+
try:
|
|
32
|
+
from sonic._version import version as __version__ # type: ignore[assignment]
|
|
33
|
+
except ImportError: # _version.py absent — source checkout without a build step
|
|
34
|
+
try:
|
|
35
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
36
|
+
|
|
37
|
+
__version__ = version("sonic-spatial")
|
|
38
|
+
except (ImportError, PackageNotFoundError):
|
|
39
|
+
__version__ = "0.0.0+unknown"
|
|
40
|
+
|
|
41
|
+
from sonic.api import Comparator, Detector
|
|
42
|
+
from sonic.comparators import ComparatorGrid, ComparatorIrregular
|
|
43
|
+
from sonic.detectors.grid import DetectorGrid
|
|
44
|
+
from sonic.detectors.irregular import DetectorIrregular
|
|
45
|
+
from sonic.kernels import MatrixKernel
|
|
46
|
+
from sonic.kernels.fft import FFTKernel
|
|
47
|
+
from sonic.kernels.nufft import NUFFTKernel
|
|
48
|
+
from sonic.statistics import spatial_q_test, spatial_r_test
|
|
49
|
+
|
|
50
|
+
# The :class:`~sonic.kernels.Kernel` and
|
|
51
|
+
# :class:`~sonic.kernels.MatrixKernelBase` ABCs are intentionally not
|
|
52
|
+
# re-exported here. They are extension points for backend authors and
|
|
53
|
+
# live at ``sonic.kernels`` (the canonical path). Importing them through
|
|
54
|
+
# ``sonic`` directly is unsupported.
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
# Kernels
|
|
58
|
+
"MatrixKernel",
|
|
59
|
+
"FFTKernel",
|
|
60
|
+
"NUFFTKernel",
|
|
61
|
+
# Statistical tests
|
|
62
|
+
"spatial_q_test",
|
|
63
|
+
"spatial_r_test",
|
|
64
|
+
# Detectors
|
|
65
|
+
"DetectorIrregular",
|
|
66
|
+
"DetectorGrid",
|
|
67
|
+
# Cross-sample
|
|
68
|
+
"ComparatorIrregular",
|
|
69
|
+
"ComparatorGrid",
|
|
70
|
+
# Factories — type-dispatched discovery face on the four classes above
|
|
71
|
+
"Detector",
|
|
72
|
+
"Comparator",
|
|
73
|
+
]
|
sonic/_rasterize.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared :func:`spatialdata.rasterize_bins` wrappers used by
|
|
3
|
+
:class:`sonic.DetectorGrid` and :class:`sonic.ComparatorGrid`.
|
|
4
|
+
|
|
5
|
+
Both consumers need the same boilerplate:
|
|
6
|
+
|
|
7
|
+
1. Coerce the table's X matrix to CSC sparse (required by ``rasterize_bins``).
|
|
8
|
+
2. Forward to ``spatialdata.rasterize_bins`` with the user-supplied keys.
|
|
9
|
+
3. Restore structurally absent grid positions as ``NaN``; SpatialData emits
|
|
10
|
+
zeros for both absent bins and observed zero-valued bins.
|
|
11
|
+
|
|
12
|
+
Callers differ only in what they do with the rasterized image afterwards —
|
|
13
|
+
``DetectorGrid`` stashes it back into ``sdata.images`` under a derived key,
|
|
14
|
+
``ComparatorGrid`` extracts the array and reindexes the gene axis — so the
|
|
15
|
+
shared helper stops after restoring the raster's structural-missing mask.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
import scipy.sparse as sp
|
|
24
|
+
import spatialdata as sd
|
|
25
|
+
|
|
26
|
+
__all__ = ["ensure_csc_table", "rasterize_table"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _mean_fill_missing(values: np.ndarray, axis: tuple[int, ...]) -> np.ndarray:
|
|
30
|
+
"""Mean-fill ``NaN`` bins in place so centering makes their residuals zero."""
|
|
31
|
+
missing = np.isnan(values)
|
|
32
|
+
if not missing.any():
|
|
33
|
+
return values
|
|
34
|
+
n_observed = np.prod([values.shape[i] for i in axis]) - missing.sum(axis=axis, keepdims=True)
|
|
35
|
+
np.copyto(values, 0.0, where=missing)
|
|
36
|
+
sums = values.sum(axis=axis, keepdims=True)
|
|
37
|
+
means = np.full_like(sums, np.nan)
|
|
38
|
+
np.divide(sums, n_observed, out=means, where=n_observed > 0)
|
|
39
|
+
np.copyto(values, means, where=missing)
|
|
40
|
+
return values
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def ensure_csc_table(sdata: Any, table_name: str) -> None:
|
|
44
|
+
"""Coerce ``sdata.tables[table_name].X`` to CSC sparse in-place, if sparse.
|
|
45
|
+
|
|
46
|
+
``spatialdata.rasterize_bins`` performs column-wise slicing and requires CSC.
|
|
47
|
+
Dense arrays are left untouched.
|
|
48
|
+
"""
|
|
49
|
+
if table_name not in sdata.tables:
|
|
50
|
+
raise ValueError(f"Table {table_name!r} not found in sdata.")
|
|
51
|
+
table = sdata.tables[table_name]
|
|
52
|
+
X = getattr(table, "X", None)
|
|
53
|
+
if X is None or isinstance(X, np.ndarray):
|
|
54
|
+
return
|
|
55
|
+
if sp.issparse(X) and X.format != "csc":
|
|
56
|
+
table.X = X.tocsc()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def rasterize_table(
|
|
60
|
+
sdata: Any,
|
|
61
|
+
*,
|
|
62
|
+
bins: str,
|
|
63
|
+
table_name: str,
|
|
64
|
+
col_key: str,
|
|
65
|
+
row_key: str,
|
|
66
|
+
value_key: str | list[str] | None = None,
|
|
67
|
+
return_region_as_labels: bool = False,
|
|
68
|
+
):
|
|
69
|
+
"""Rasterize a table while preserving structural missingness as ``NaN``.
|
|
70
|
+
|
|
71
|
+
``spatialdata.rasterize_bins`` initializes its bounding rectangle with
|
|
72
|
+
zeros, making an absent bin indistinguishable from an observed zero. This
|
|
73
|
+
wrapper reconstructs occupancy from ``row_key`` / ``col_key`` and masks
|
|
74
|
+
only absent positions. The mask is applied lazily to image outputs; label
|
|
75
|
+
outputs are returned unchanged.
|
|
76
|
+
"""
|
|
77
|
+
ensure_csc_table(sdata, table_name)
|
|
78
|
+
rasterized = sd.rasterize_bins(
|
|
79
|
+
sdata,
|
|
80
|
+
bins=bins,
|
|
81
|
+
table_name=table_name,
|
|
82
|
+
col_key=col_key,
|
|
83
|
+
row_key=row_key,
|
|
84
|
+
value_key=value_key,
|
|
85
|
+
return_region_as_labels=return_region_as_labels,
|
|
86
|
+
)
|
|
87
|
+
if return_region_as_labels:
|
|
88
|
+
return rasterized
|
|
89
|
+
|
|
90
|
+
table = sdata.tables[table_name]
|
|
91
|
+
rows = np.asarray(table.obs[row_key])
|
|
92
|
+
cols = np.asarray(table.obs[col_key])
|
|
93
|
+
occupied = np.zeros(rasterized.shape[-2:], dtype=bool)
|
|
94
|
+
occupied[(rows - rows.min()).astype(int), (cols - cols.min()).astype(int)] = True
|
|
95
|
+
return rasterized if occupied.all() else rasterized.where(occupied)
|
sonic/_version.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '1.0.0rc1'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 0, 0, 'rc1')
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
sonic/api.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Top-level factory entry points: :func:`Detector` and :func:`Comparator`.
|
|
3
|
+
|
|
4
|
+
Thin one-liner discovery face on top of the four explicit classes
|
|
5
|
+
(:class:`DetectorIrregular`, :class:`DetectorGrid`,
|
|
6
|
+
:class:`ComparatorIrregular`, :class:`ComparatorGrid`). Dispatches on
|
|
7
|
+
the runtime type of the input data so users don't have to know the
|
|
8
|
+
``Irregular`` / ``Grid`` split:
|
|
9
|
+
|
|
10
|
+
>>> det = Detector(adata) # → DetectorIrregular
|
|
11
|
+
>>> det = Detector(sdata) # → DetectorGrid
|
|
12
|
+
>>> cmp = Comparator([adata, ...]) # → ComparatorIrregular
|
|
13
|
+
>>> cmp = Comparator([sdata, ...]) # → ComparatorGrid
|
|
14
|
+
|
|
15
|
+
The factories only check ``isinstance`` to pick the right class, then
|
|
16
|
+
forward kwargs verbatim. Asymmetry between the two:
|
|
17
|
+
|
|
18
|
+
- :func:`Detector` does **not** pass the data argument to the
|
|
19
|
+
constructor — the caller chains ``.setup_data(data)`` afterwards
|
|
20
|
+
(matching the explicit-class flow).
|
|
21
|
+
- :func:`Comparator` **does** pass the sample list as the first
|
|
22
|
+
positional argument, since both comparator constructors take
|
|
23
|
+
``samples`` there. Cross-sample contrasts (``design``) are
|
|
24
|
+
supplied later, at test time, on
|
|
25
|
+
:meth:`~sonic.ComparatorIrregular.test_diff_freq` /
|
|
26
|
+
:meth:`~sonic.ComparatorIrregular.test_diff_expr`.
|
|
27
|
+
|
|
28
|
+
For advanced use (custom kernel selection, sample-list inputs that
|
|
29
|
+
mix two backends intentionally) prefer the explicit class names —
|
|
30
|
+
the factories deliberately reject mixed-type lists with a
|
|
31
|
+
:class:`TypeError`.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
from collections.abc import Sequence
|
|
37
|
+
from typing import Any
|
|
38
|
+
|
|
39
|
+
from sonic.comparators import ComparatorGrid, ComparatorIrregular
|
|
40
|
+
from sonic.detectors.grid import DetectorGrid
|
|
41
|
+
from sonic.detectors.irregular import DetectorIrregular
|
|
42
|
+
|
|
43
|
+
__all__ = ["Detector", "Comparator"]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _is_anndata(obj: Any) -> bool:
|
|
47
|
+
"""Return True if ``obj`` is an :class:`anndata.AnnData`. Lazy
|
|
48
|
+
import so the factories work even when ``anndata`` isn't
|
|
49
|
+
available — though in practice ``anndata`` is a hard dependency
|
|
50
|
+
of :mod:`sonic`.
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
from anndata import AnnData
|
|
54
|
+
except ImportError: # pragma: no cover — anndata is a hard dep
|
|
55
|
+
return False
|
|
56
|
+
return isinstance(obj, AnnData)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _is_spatialdata(obj: Any) -> bool:
|
|
60
|
+
"""Return True if ``obj`` is a :class:`spatialdata.SpatialData`.
|
|
61
|
+
Lazy import so the factories raise a clear :class:`TypeError`
|
|
62
|
+
rather than :class:`ImportError` when ``spatialdata`` isn't
|
|
63
|
+
installed.
|
|
64
|
+
"""
|
|
65
|
+
try:
|
|
66
|
+
from spatialdata import SpatialData
|
|
67
|
+
except ImportError:
|
|
68
|
+
return False
|
|
69
|
+
return isinstance(obj, SpatialData)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _supported_types_msg() -> str:
|
|
73
|
+
return (
|
|
74
|
+
"supported types: anndata.AnnData (→ DetectorIrregular / "
|
|
75
|
+
"ComparatorIrregular) or spatialdata.SpatialData (→ "
|
|
76
|
+
"DetectorGrid / ComparatorGrid)"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def Detector(data: Any, **kwargs: Any) -> Any: # noqa: N802 - factory mimics class names
|
|
81
|
+
"""Construct the right :class:`~sonic.Detector` for ``data``.
|
|
82
|
+
|
|
83
|
+
Dispatches on ``type(data)``:
|
|
84
|
+
|
|
85
|
+
- :class:`anndata.AnnData` → :class:`~sonic.DetectorIrregular`.
|
|
86
|
+
- :class:`spatialdata.SpatialData` → :class:`~sonic.DetectorGrid`.
|
|
87
|
+
|
|
88
|
+
The data itself is **not** passed to the constructor — the caller
|
|
89
|
+
is expected to chain ``.setup_data(data, ...)`` afterwards (the
|
|
90
|
+
factory only uses ``data``'s type to pick a class).
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
data : anndata.AnnData or spatialdata.SpatialData
|
|
95
|
+
The dataset whose type drives the dispatch.
|
|
96
|
+
**kwargs
|
|
97
|
+
Forwarded to the chosen class's ``__init__`` verbatim.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
DetectorIrregular or DetectorGrid
|
|
102
|
+
Constructed (but not yet set up) detector instance.
|
|
103
|
+
|
|
104
|
+
Raises
|
|
105
|
+
------
|
|
106
|
+
TypeError
|
|
107
|
+
If ``data`` is neither an ``AnnData`` nor a ``SpatialData``.
|
|
108
|
+
|
|
109
|
+
Examples
|
|
110
|
+
--------
|
|
111
|
+
>>> from sonic import Detector
|
|
112
|
+
>>> det = Detector(adata, kernel_method="gaussian", backend="matrix")
|
|
113
|
+
>>> det = det.setup_data(adata)
|
|
114
|
+
>>> df = det.compute_qstat()
|
|
115
|
+
"""
|
|
116
|
+
if _is_anndata(data):
|
|
117
|
+
return DetectorIrregular(**kwargs)
|
|
118
|
+
if _is_spatialdata(data):
|
|
119
|
+
return DetectorGrid(**kwargs)
|
|
120
|
+
raise TypeError(
|
|
121
|
+
f"Detector cannot dispatch on type {type(data).__name__!r}; " f"{_supported_types_msg()}."
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def Comparator( # noqa: N802 - factory mimics class names
|
|
126
|
+
data_list: Sequence[Any], **kwargs: Any
|
|
127
|
+
) -> Any:
|
|
128
|
+
"""Construct the right :class:`~sonic.Comparator` for ``data_list``.
|
|
129
|
+
|
|
130
|
+
Dispatches on the homogeneous element type:
|
|
131
|
+
|
|
132
|
+
- all :class:`anndata.AnnData` → :class:`~sonic.ComparatorIrregular`.
|
|
133
|
+
- all :class:`spatialdata.SpatialData` → :class:`~sonic.ComparatorGrid`.
|
|
134
|
+
- mixed types → :class:`TypeError`.
|
|
135
|
+
|
|
136
|
+
Unlike :func:`Detector`, the data list **is** forwarded as the
|
|
137
|
+
first positional arg to the chosen class (both comparator
|
|
138
|
+
constructors take ``samples`` as their first positional
|
|
139
|
+
parameter).
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
data_list : sequence of anndata.AnnData or sequence of spatialdata.SpatialData
|
|
144
|
+
Per-sample inputs. Must all be of the same type.
|
|
145
|
+
**kwargs
|
|
146
|
+
Forwarded to the chosen class's ``__init__`` verbatim
|
|
147
|
+
(e.g. ``gene_names=...``, ``feature_mode=...``, etc.). The
|
|
148
|
+
cross-sample contrast (``design``) is supplied later on
|
|
149
|
+
:meth:`test_diff_freq` / :meth:`test_diff_expr`, not here.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
ComparatorIrregular or ComparatorGrid
|
|
154
|
+
Constructed comparator instance.
|
|
155
|
+
|
|
156
|
+
Raises
|
|
157
|
+
------
|
|
158
|
+
TypeError
|
|
159
|
+
If ``data_list`` is empty or its elements aren't all the
|
|
160
|
+
same supported type.
|
|
161
|
+
|
|
162
|
+
Examples
|
|
163
|
+
--------
|
|
164
|
+
>>> from sonic import Comparator
|
|
165
|
+
>>> cmp = Comparator([a1, a2, a3]).compute_spectra()
|
|
166
|
+
>>> df = cmp.test_diff_freq(group_labels)
|
|
167
|
+
"""
|
|
168
|
+
items = list(data_list)
|
|
169
|
+
if len(items) == 0:
|
|
170
|
+
raise TypeError(
|
|
171
|
+
f"Comparator requires a non-empty list of samples; " f"{_supported_types_msg()}."
|
|
172
|
+
)
|
|
173
|
+
all_anndata = all(_is_anndata(x) for x in items)
|
|
174
|
+
all_spatialdata = all(_is_spatialdata(x) for x in items)
|
|
175
|
+
if all_anndata:
|
|
176
|
+
return ComparatorIrregular(items, **kwargs)
|
|
177
|
+
if all_spatialdata:
|
|
178
|
+
return ComparatorGrid(items, **kwargs)
|
|
179
|
+
raise TypeError(
|
|
180
|
+
f"Comparator received a list of mixed / unsupported types "
|
|
181
|
+
f"{[type(x).__name__ for x in items]}; {_supported_types_msg()}."
|
|
182
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
``sonic.comparators`` — cross-sample spatial-pattern comparison.
|
|
3
|
+
|
|
4
|
+
Subpackage grouping the layer-4 public classes:
|
|
5
|
+
|
|
6
|
+
- :class:`ComparatorIrregular` — wraps a sequence of
|
|
7
|
+
:class:`anndata.AnnData` (irregular spots, NUFFT backend).
|
|
8
|
+
- :class:`ComparatorGrid` — wraps a sequence of
|
|
9
|
+
:class:`spatialdata.SpatialData` (regular rasterized bins, FFT
|
|
10
|
+
backend).
|
|
11
|
+
|
|
12
|
+
Both classes share the same post-``compute_spectra`` surface
|
|
13
|
+
(``normalize_background``, ``normalize_covariates``,
|
|
14
|
+
``test_diff_freq``, ``test_diff_expr``) through
|
|
15
|
+
the private :class:`~sonic.comparators.base._ComparatorBase` mixin.
|
|
16
|
+
Cross-sample contrasts are supplied at test time via the ``design``
|
|
17
|
+
argument on the test methods — the comparator itself is
|
|
18
|
+
design-agnostic, so one fitted comparator can serve any number of
|
|
19
|
+
unrelated contrasts on the same spectra. The shape-only frequency
|
|
20
|
+
test is available via a ``normalize_shape: bool = False`` keyword on
|
|
21
|
+
:meth:`test_diff_freq` (forwarded to the standalone ``compare_*``
|
|
22
|
+
function).
|
|
23
|
+
|
|
24
|
+
The array-level spectral feature helpers live in
|
|
25
|
+
:mod:`sonic.comparators.features`; normalization primitives live in
|
|
26
|
+
:mod:`sonic.comparators.normalization`; statistical comparison
|
|
27
|
+
primitives live in :mod:`sonic.comparators.multisample`.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from sonic.comparators.grid import ComparatorGrid
|
|
31
|
+
from sonic.comparators.irregular import ComparatorIrregular
|
|
32
|
+
|
|
33
|
+
__all__ = ["ComparatorIrregular", "ComparatorGrid"]
|