goatpy.bin
==========

.. py:module:: goatpy.bin

.. autoapi-nested-parse::

   binning.py
   ==========
   Data-driven m/z binning for MALDI imzML files.

   Instead of loading a pre-defined peak list, this module reads every spectrum
   in the imzML file, discovers all m/z values that appear across the dataset,
   and bins them into a uniform grid.

   Key concepts
   ------------
   - **bin width (tolerance)**: all m/z values within `tolerance` Da of a bin
     centre are summed into that bin. A common starting point is 0.05–0.1 Da
     for unit-resolution MALDI instruments; use 0.005–0.02 for high-resolution.
   - **bin centres**: derived from the observed m/z range across all spectra so
     no prior knowledge is required.
   - **reduce function**: defaults to ``max`` (intensity of the tallest peak
     within the bin window), matching pyimzml's ``getionimage`` convention.
     ``sum`` is also supported and can improve SNR on dense spectra.

   Usage
   -----
   >>> import goatpy as gp
   >>> sdata = gp.bin_and_load(
   ...     imzml_path = "sample.imzML",
   ...     he_path    = "sample.svs",    # optional H&E
   ...     tolerance  = 0.05,
   ...     mz_range   = (900, 3600),     # optional subset
   ... )

   Or just build the binned matrix without H&E registration:

   >>> from goatpy.binning import bin_imzml
   >>> sdata = bin_imzml("sample.imzML", tolerance=0.05)



Functions
---------

.. autoapisummary::

   goatpy.bin.bin_imzml
   goatpy.bin.bin_and_align


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

.. py:function:: bin_imzml(imzml_path: str, tolerance: float = 0.05, mz_range: Optional[Tuple[float, float]] = None, reduce: Literal['max', 'sum'] = 'max', min_frequency: float = 0.0, min_intensity: float = 0.0, sample_fraction: float = 1.0, chunk_size: int = 500) -> spatialdata.SpatialData

   Load a MALDI imzML file and bin all spectra onto a uniform m/z grid.

   This replaces the manual peak-list workflow (``glyco_spatialdata`` / the
   bundled PEAKS.csv) with a data-driven approach that retains every
   detectable signal. The result is a SpatialData object compatible with all
   other goatpy functions.

   :param imzml_path: Path to the .imzML file.
   :type imzml_path: str
   :param tolerance: Half-width of each m/z bin in Da.  All peaks within
                     ``[centre - tolerance, centre + tolerance]`` are collapsed to one bin.

                     Recommended values:
                     - Low-resolution (unit-res) MALDI:  0.1 – 0.5 Da
                     - Medium-resolution:                0.02 – 0.1 Da
                     - High-resolution (Orbitrap/FT):    0.002 – 0.01 Da
   :type tolerance: float, default 0.05
   :param mz_range: Restrict the output to this m/z window, e.g. ``(900.0, 3600.0)``.
                    ``None`` uses the full range found in the file.
   :type mz_range: (lo, hi) or None
   :param reduce: How to combine multiple peaks within one bin.

                  - ``"max"``  — tallest peak wins  (matches pyimzml ``getionimage``)
                  - ``"sum"``  — integrate all peaks (better SNR for dense spectra)
   :type reduce: "max" | "sum", default "max"
   :param min_frequency: After binning, drop m/z bins detected in fewer than this fraction of
                         pixels (0.0 = keep all).  E.g. ``0.01`` drops bins present in < 1 % of
                         pixels.
   :type min_frequency: float, default 0.0
   :param min_intensity: Drop m/z bins whose maximum intensity across all pixels is below this
                         value.
   :type min_intensity: float, default 0.0
   :param sample_fraction: Fraction of spectra to scan when discovering the m/z range.  Values
                           < 1 speed up the range-discovery step on large files but may miss
                           rare m/z values.
   :type sample_fraction: float, default 1.0
   :param chunk_size: Progress is logged every ``chunk_size`` spectra.
   :type chunk_size: int, default 500

   :returns: shapes["pixels"]        — one square per MALDI pixel
             points["centroids"]     — centroid of each pixel
             tables["maldi_adata"]   — AnnData, rows = pixels, columns = m/z bins
   :rtype: SpatialData with

   .. rubric:: Examples

   >>> from goatpy.binning import bin_imzml
   >>> sdata = bin_imzml("sample.imzML", tolerance=0.05, mz_range=(900, 3600))
   >>> sdata["maldi_adata"].shape
   (4200, 13500)   # depends on your data

   # Then normalise, reduce, cluster as usual:
   >>> import goatpy as gp
   >>> sdata = gp.normalize_spatialdata(sdata, table_name="maldi_adata")
   >>> sdata = gp.graphpca_spatialdata(sdata, n_components=30)
   >>> sdata = gp.get_kmean_clusters(sdata, n_clusters=8)

   # Or pass directly to load_and_align for H&E registration — just supply
   # the pre-binned sdata instead of using the imzml_path loading path.
   # (H&E registration still runs on the TIC image built from the binned matrix.)


.. py:function:: bin_and_align(imzml_path: str, he_path: str, tolerance: float = 0.05, mz_range: Optional[Tuple[float, float]] = None, reduce: Literal['max', 'sum'] = 'max', min_frequency: float = 0.0, min_intensity: float = 0.0, geojson_path: Optional[str] = None, maldi_pixel_um: Optional[float] = None, he_pixel_um: Optional[float] = None, img_upscaling: int = 10, buffer_px: int = 150, coarse_rotation_step: int = 15, fine_rotation_range: float = 5.0, fine_rotation_step: float = 1.0, **kwargs) -> spatialdata.SpatialData

   Bin all spectra from an imzML file and register against an H&E image.

   This is the data-driven equivalent of ``load_and_align``:  instead of
   loading a fixed peak list it bins the entire spectral space first, then
   passes the binned TIC image to the registration engine.

   :param imzml_path: Paths to imzML and H&E files.
   :type imzml_path: str
   :param he_path: Paths to imzML and H&E files.
   :type he_path: str
   :param tolerance: Bin half-width in Da — see ``bin_imzml`` for guidance.
   :type tolerance: float
   :param mz_range: Restrict to this m/z window before registration.
   :type mz_range: (lo, hi) or None
   :param reduce: Bin reduction function.
   :type reduce: "max" | "sum"
   :param min_frequency: Post-binning quality filters — see ``bin_imzml``.
   :type min_frequency: float
   :param min_intensity: Post-binning quality filters — see ``bin_imzml``.
   :type min_intensity: float
   :param geojson_path: Optional QuPath annotation export.
   :type geojson_path: str or None
   :param maldi_pixel_um: Physical pixel sizes.  Auto-detected when None.
   :type maldi_pixel_um: float or None
   :param he_pixel_um: Physical pixel sizes.  Auto-detected when None.
   :type he_pixel_um: float or None
   :param img_upscaling: Upscaling factor for the output canvas.
   :type img_upscaling: int
   :param buffer_px: Canvas padding at registration resolution.
   :type buffer_px: int
   :param coarse_rotation_step: Registration search parameters.
   :type coarse_rotation_step: float
   :param fine_rotation_range: Registration search parameters.
   :type fine_rotation_range: float
   :param fine_rotation_step: Registration search parameters.
   :type fine_rotation_step: float

   :returns: Same structure as ``load_and_align`` output.
   :rtype: SpatialData


