mikro
The Python client for mikro, the Arkitekt service for microscopy and
imaging data. mikro-server is a GraphQL server that keeps the metadata of your data (datasets,
folders, coordinate systems, scenes, and the relations between them), while the pixels live in
object storage as Zarr (and tables as Parquet). This client gives you both as
one: typed, validated Python objects built on rath and pydantic,
whose .data is a lazy xarray backed by dask. When you pass an array to a
mutation, mikro uploads it before the call runs, and when you read one back it downloads only the
chunks you touch.
Installation
pip install mikro
mikro requires Python 3.11+. Extras bring in the heavier wire formats only when you need them:
| Extra | Brings in |
|---|---|
table |
pyarrow, pandas and duckdb, for querying Parquet-backed tables |
mesh |
fabriks, for uploading meshes |
network |
konnektion, for uploading graphs |
sparse |
sporadik, for sparse datasets |
complete |
all of the above |
Inside an arkitekt app, pip install "arkitekt[rekuest,mikro]" installs mikro along with arkitekt and the runtime run(app) needs.
Usage
Every mikro operation is a method of the Mikro client. Each comes in a blocking and an
a-prefixed async flavour (mikro.create_folder(...), await mikro.acreate_folder(...)). An object
that a call returns remembers the client that fetched it, so later calls on it, such as .data, go
through the same client.
In an arkitekt app
Add mikro_service to your app and take the client by annotation. arkitekt injects it. Types from
mikro.arkitekt.specs such as Volume or Image are lenses over a mikro dataset. Each one declares
what an action needs, and the UI then offers only datasets that fit.
from arkitekt import App, Task, run
from mikro import Mikro, mikro_service
from mikro.arkitekt.specs import Volume, ensure
app = App("clip-volume", "0.1.0", services=[mikro_service])
@app.action
def clip(volume: Volume, mikro: Mikro, task: Task) -> Volume:
"""Clip Volume
Clips negative values and stores the result on the same grid.
"""
source = volume.data # a lazy xarray.DataArray
task.progress(30, f"Processing {source.shape}")
clipped = source.clip(min=0).compute()
result = mikro.create_array_dataset(
data=clipped,
scales=[],
name="clipped",
axes=volume.carried_axes(clipped.dims),
derived_from=[volume.derive_identity(value_relation="TRANSFORMED")],
)
return ensure(result.lens(), Volume)
if __name__ == "__main__":
run(app)
Datasets, tables, meshes, annotations, lenses, coordinate systems, scenes, folders and files travel
between actions by id (@mikro/arraydataset, @mikro/lens, @mikro/scene, ...), so an action can
take them and return them directly.
From a script
easy connects for you and returns the client:
import numpy as np
import xarray as xr
from arkitekt import easy
from mikro import dataset_arrays, mikro_service
volume = xr.DataArray(np.random.random((2, 10, 256, 256)), dims=("c", "z", "y", "x"))
with easy("my-script", mikro_service) as mikro:
folder = mikro.create_folder(name="examples")
# `data` is level 0; `scales` holds only the coarser levels
level_zero, scales = dataset_arrays(volume, levels=3)
dataset = mikro.create_array_dataset(
data=level_zero,
scales=scales,
name="random volume",
axes=["c", "z", "y", "x"],
folder=folder.id,
)
again = mikro.get_array_dataset(dataset.id)
peak = again.data.max().compute() # downloads only what it needs
Use async with aeasy(...) in async code, or interactive("notebook", mikro_service) in Jupyter.
Inside an async loop, remember that computing .data downloads the data in a blocking way on that
loop.
Declared axes are checked against the array before it is uploaded. For example, a rank mismatch
or a missing declaration raises ArrayDeclarationError (tables and sparse datasets have their own
errors) before any data is sent.
Working with data
data = dataset.data # level 0, a lazy dask-backed xarray.DataArray
coarse = dataset.level_data(2) # a coarser pyramid level
levels = dataset.multi_scale_data()
window = dataset.lens(z=(0, 5)) # a Lens: an immutable selection over the dataset
window.data
examples/ holds ten self-contained scripts. Each one simulates an imaging
modality (SMLM, calcium imaging, high-content screening, CLEM, MRI, tractography, ...) and composes
it into a mikro scene, and together they use every layer kind the API offers.
Standalone
Outside arkitekt, you build the client yourself from a MikroRath and a DataLayer, and you use it
as a context manager:
from mikro import Mikro
from mikro.datalayer import DataLayer
from mikro.rath import MikroRath
mikro = Mikro(rath=MikroRath(link=...), datalayer=DataLayer(...))
with mikro:
folder = mikro.create_folder(name="examples")
tests/conftest.py shows the complete wiring against a local deployment.
Prerequisites
mikro needs a running mikro-server to connect to. The easiest option is an
Arkitekt deployment. For a local test server,
tests/integration/docker-compose.yml starts mikro together with a database and S3-compatible
object storage.
Development
The generated API (mikro/api/schema.py) is produced by turms
from the schema and the documents in graphql/ (see graphql.config.yaml).
uv run pytest -m "not integration" # no server needed
uv run pytest -m integration # a real mikro deployment via dokker
See RELEASING.md for how versions are cut.
License
MIT, see LICENSE.
Metadata
Release files for mikro 6.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mikro-6.2.1.tar.gz | 373.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mikro-6.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 764.6 kB
Release files / mikro-6.2.1.tar.gz
| Download URL | mikro-6.2.1.tar.gz |
|---|---|
| Size | 373.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b69faa724192ccb41b3eec771a7a2da2d9b4c24cda022a9f3eeae729945ed501
|
|
BLAKE2b-256 checksum How to use checksums |
d1f955cdf6eb526e16841037bb71b66afdd75161878b9eaee8b5c551536218ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / mikro-6.2.1-py3-none-any.whl
| Download URL | mikro-6.2.1-py3-none-any.whl |
|---|---|
| Size | 391.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b2d80e4d8909d2eed1f1d0e5ee02d42976db75687bbbd2963e8a4aed1baeeb1e
|
|
BLAKE2b-256 checksum How to use checksums |
31798b50528aba523be4ba25e722d3cce4a321f63b9578028d44caff43e6d1cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|