quadsv.api
==========

.. py:module:: quadsv.api

.. autoapi-nested-parse::

   Top-level factory entry points: :func:`Detector` and :func:`Comparator`.

   Thin one-liner discovery face on top of the four explicit classes
   (:class:`DetectorIrregular`, :class:`DetectorGrid`,
   :class:`ComparatorIrregular`, :class:`ComparatorGrid`). Dispatches on
   the runtime type of the input data so users don't have to know the
   ``Irregular`` / ``Grid`` split:

   >>> det = Detector(adata)             # → DetectorIrregular
   >>> det = Detector(sdata)             # → DetectorGrid
   >>> cmp = Comparator([adata, ...])    # → ComparatorIrregular
   >>> cmp = Comparator([sdata, ...])    # → ComparatorGrid

   The factories only check ``isinstance`` to pick the right class, then
   forward kwargs verbatim. Asymmetry between the two:

   - :func:`Detector` does **not** pass the data argument to the
     constructor — the caller chains ``.setup_data(data)`` afterwards
     (matching the explicit-class flow).
   - :func:`Comparator` **does** pass the sample list as the first
     positional argument, since both comparator constructors take
     ``samples`` there. Cross-sample contrasts (``design``) are
     supplied later, at test time, on
     :meth:`~quadsv.ComparatorIrregular.test_diff_freq` /
     :meth:`~quadsv.ComparatorIrregular.test_diff_expr`.

   For advanced use (custom kernel selection, sample-list inputs that
   mix two backends intentionally) prefer the explicit class names —
   the factories deliberately reject mixed-type lists with a
   :class:`TypeError`.



Functions
---------

.. autoapisummary::

   quadsv.api.Comparator
   quadsv.api.Detector


Module Contents
---------------

.. py:function:: Comparator(data_list, **kwargs)

   Construct the right :class:`~quadsv.Comparator` for ``data_list``.

   Dispatches on the homogeneous element type:

   - all :class:`anndata.AnnData` → :class:`~quadsv.ComparatorIrregular`.
   - all :class:`spatialdata.SpatialData` → :class:`~quadsv.ComparatorGrid`.
   - mixed types → :class:`TypeError`.

   Unlike :func:`Detector`, the data list **is** forwarded as the
   first positional arg to the chosen class (both comparator
   constructors take ``samples`` as their first positional
   parameter).

   :param data_list: Per-sample inputs. Must all be of the same type.
   :type data_list: sequence of anndata.AnnData or sequence of spatialdata.SpatialData
   :param \*\*kwargs: Forwarded to the chosen class's ``__init__`` verbatim
                      (e.g. ``gene_names=...``, ``feature_mode=...``, etc.). The
                      cross-sample contrast (``design``) is supplied later on
                      :meth:`test_diff_freq` / :meth:`test_diff_expr`, not here.

   :returns: Constructed comparator instance.
   :rtype: ComparatorIrregular or ComparatorGrid

   :raises TypeError: If ``data_list`` is empty or its elements aren't all the
       same supported type.

   .. rubric:: Examples

   >>> from quadsv import Comparator
   >>> cmp = Comparator([a1, a2, a3]).compute_spectra()
   >>> df = cmp.test_diff_freq(group_labels)


.. py:function:: Detector(data, **kwargs)

   Construct the right :class:`~quadsv.Detector` for ``data``.

   Dispatches on ``type(data)``:

   - :class:`anndata.AnnData` → :class:`~quadsv.DetectorIrregular`.
   - :class:`spatialdata.SpatialData` → :class:`~quadsv.DetectorGrid`.

   The data itself is **not** passed to the constructor — the caller
   is expected to chain ``.setup_data(data, ...)`` afterwards (the
   factory only uses ``data``'s type to pick a class).

   :param data: The dataset whose type drives the dispatch.
   :type data: anndata.AnnData or spatialdata.SpatialData
   :param \*\*kwargs: Forwarded to the chosen class's ``__init__`` verbatim.

   :returns: Constructed (but not yet set up) detector instance.
   :rtype: DetectorIrregular or DetectorGrid

   :raises TypeError: If ``data`` is neither an ``AnnData`` nor a ``SpatialData``.

   .. rubric:: Examples

   >>> from quadsv import Detector
   >>> det = Detector(adata, kernel_method="gaussian", backend="matrix")
   >>> det = det.setup_data(adata)
   >>> df = det.compute_qstat()


