Metadata-Version: 2.4
Name: auroraomics
Version: 0.1.0.dev0
Summary: Virtual spatial transcriptomics from H&E histology: patch QC, tile packing and the .h5ad result contract.
Author: Kalin Nonchev
License-Expression: PolyForm-Noncommercial-1.0.0
Keywords: histopathology,spatial-transcriptomics,h5ad,anndata,whole-slide-image
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23
Requires-Dist: h5py>=3.9
Requires-Dist: opencv-python-headless>=4.5
Requires-Dist: pillow>=9
Provides-Extra: client
Requires-Dist: httpx>=0.27; extra == "client"
Requires-Dist: pydantic>=2; extra == "client"
Requires-Dist: anndata>=0.10; extra == "client"
Provides-Extra: deepspotm
Provides-Extra: slide
Requires-Dist: tifffile>=2023.7.10; extra == "slide"
Requires-Dist: imagecodecs>=2023.3.16; extra == "slide"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: setuptools>=77; extra == "dev"
Requires-Dist: wheel; extra == "dev"
Requires-Dist: anndata<0.12,>=0.10; extra == "dev"
Requires-Dist: tifffile>=2023.7.10; extra == "dev"
Requires-Dist: imagecodecs>=2023.3.16; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: numpy<2; extra == "dev"
Dynamic: license-file

# auroraomics

Virtual spatial transcriptomics from H&E histology.

This package holds the pieces of that pipeline that are pure Python, so the
same code runs on your laptop, in a GPU container and on the service:

- **`auroraomics.qc`** — the three patch-quality predicates (foreground, blur,
  stained tissue) applied to every candidate tile before a model sees it, and
  the short-circuiting cascade that combines them.
- **`auroraomics.pack`** — build the `patches` archive a prediction takes as
  input (`pack_tiles`), and validate one you have been handed (`read_archive`).
- **`auroraomics.h5ad`** — write the standard `.h5ad` result with `h5py`
  alone, streaming the expression matrix batch by batch so peak memory is one
  batch rather than the whole matrix.
- **`auroraomics.subsample`** — pick the densest contiguous square of spots
  when a slide yields more tiles than a run is allowed to spend.
- **`auroraomics.contracts`** — the shared contract values (container layout,
  input-kind caps, result layout) as data, so nothing here re-types a number
  the service also reads.

## Install

```
pip install auroraomics
```

The core needs only numpy, h5py, OpenCV and Pillow. Extras add the API client
(`client`), a local model runtime (`deepspotm`) and pyramidal slide reading
(`slide`).

## Pack tiles, then look at the report

```python
import auroraomics as ao

report = ao.pack_tiles(tiles, "sample.zip", mpp=0.499, thumbnail=thumb)
print(report.written, "tiles kept,", report.rejected, "dropped")
print(report.rejected_by_reason)          # {'foreground_ratio': 12, ...}
```

`tiles` is any iterable of `ao.Tile(image, x, y)`, where `image` is an RGB
`uint8` array and `x`/`y` are the tile's top-left position in full-resolution
pixels. Tiles are quality-checked as they stream past, and only the ones that
pass are written, so an iterable that reads a slide lazily never has to hold
more than one tile in memory.

## Validate an archive before trusting it

```python
archive = ao.read_archive("sample.zip")   # raises ArchiveError on anything odd
for tile in archive.tiles():              # decoded one at a time
    ...
```

`read_archive` checks the member names, the manifest, the tile geometry and the
declared sizes *before* decoding a single pixel, and refuses an archive whose
members do not match the container contract.

## Write a result

```python
ao.write_result(
    "result.h5ad",
    obs=obs,                    # per-spot columns, as plain arrays
    var=var,                    # per-gene columns, indexed by gene id
    spatial=coords,             # (n_spots, 2) array -> obsm["spatial"]
    x=batches,                  # an array, or an iterable of row batches
    uns={"model": {"id": "..."}},
    layers={"image_only": other_batches},
)
```

The file reads back as an ordinary `AnnData` in anndata 0.10 and 0.11. Passing
an iterable for `x` streams it: each batch is compressed into the file as it
arrives and then dropped, which is what makes a matrix larger than memory
writable.

## Typing

The package ships `py.typed`, so annotations are visible to type checkers in
your project.

## Licence

The code in this package is licensed under
[PolyForm Noncommercial 1.0.0](https://polyformproject.org/licenses/noncommercial/1.0.0),
which permits use for any purpose that is not commercial. It is the same licence the
model package this client is built for carries, so installing both puts you under one
rule rather than two.

The model weights are licensed separately by whoever publishes them, and access to them
may be gated. Read those terms before you use a model: they are not this licence, and a
permission granted here is not a permission granted there.

