Skip to content

Commit

Permalink
Refactor API for NGFF datasets (#31)
Browse files Browse the repository at this point in the history
* base class for ngff nodes

* fix typo

* sketch image container and position node

* create new image in position

* add docstrings

* combine ome-zarr reader and writer

* fix docstring length

* append channel method

* mixin class for file mode methods

* handle metadata parsing in node classes

* move ome-zarr-py and hypothesis to dev dependency

* move hypothesis to dev dependency

* match signature

* fix constructors

* fix metadata writing

* fix default chunking

* fix context manager

* fix channel axis check

* fix shape check

* update OMEZarr example

* rename ngff file

* rename imports

* showcase `ImageArray.numpy()`

* update docstring

* remove old writing code and add new well node

* update well constructor and docstring

* add row node

* update docstring

* elevate iterator

* dummy metadata parsing for the row node

* update docstrings

* update example introduction

* clarify read-only example

* fix hcs metadata

* add back dump metadata method as placeholder

* plate node

* fix typo

* init plate meta in its own method

* update docstring

* replace old HCSWriter with a wrapper of plate node

* remove reader adaptor

* remove OMEZarrReader

* update deprecation message

* update docstring

* rename example files

* rearrange metadata attributes

* fix plate metadata

* fix metadata loading

* update hcs example

* fix omero metadata

* rename test directory

* rename test file

* change error type

* test util functions

* fix linting and formatting

* test OMEZarr

* warning against invalid plate metadata

* warn -> warning

* warning against channel name not found

* test `HCSZarr.open()`

* handle missing axes and channel names

* load axes from metadata if possible

* fix check attribute logic

* fix typo

* test HCSZarr

* return early if position is not found

* match error type

* restrict example count and loosen deadline

* combine pytest commands

* fix fixture call

* remove unused import

* update example comment

* fix linting

* fix linting

* fix linting

* Merge branch 'main' into ngff-dataset

* Revert "Merge branch 'main' into ngff-dataset"

This reverts commit c17b81e.

* isort

* remove empty files from merging

* fix linting

* simple refactors and an example that fails

* revert wrong example changes

* fix linting and formatting

* simplify code

* revert to conditional operator

* use string as array key in examples

* rename OMEZarr to OMEZarrFOV

* Update docstrings

* test append channel

* check image shape with test

* test create position

* test well metadata

* updated hcs_zarr example

* move open store function to top level

* rename open_store to aid auto-completion

* wrap zarr.Group.tree() for ngff nodes

* remove mixin and container classes

* test against new api

* update examples

* refined examples and delete_channel stub

* rename (ome_zarr -> singleFOV_zarr)

* proposal for simplified API for tiled acquisition

* Revert 3 commits

This reverts commits 6d0ba4c,
b9516b1, 61237f9.

* rename single fov example file

* modify example store path and array name

* edit HCS example

* rename hcs example file

---------

Co-authored-by: Shalin Mehta <2934183+mattersoflight@users.noreply.github.com>
  • Loading branch information
ziw-liu and mattersoflight committed Feb 13, 2023
1 parent d8521e0 commit 4a9e6fc
Show file tree
Hide file tree
Showing 25 changed files with 1,862 additions and 1,446 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ jobs:
python -m pip install --upgrade pip
pip install flake8
- name: Check code with Flake8
# E203 conflicts with black
run: |
flake8 iohub
flake8 iohub --extend-ignore=E203
isort:
name: isort Check
Expand All @@ -72,7 +73,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install isort
- name: Check code with Flake8
- name: Check code with isort
run: |
isort --check iohub
Expand Down
75 changes: 0 additions & 75 deletions examples/hcs_ome_zarr_writer.py

This file was deleted.

61 changes: 61 additions & 0 deletions examples/multi_fov_hcs_ome_zarr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# %%
# This script writes a high content screening (HCS) OME-Zarr dataset
# with a single FOV and a single scaling level per well,
# and adds an extra well-position to an existing dataset.
# It can be run as a plain Python script, or as interactive cells in some IDEs.

import os

import numpy as np

from iohub.ngff import open_ome_zarr

# %%
# Set storage path

store_path = f'{os.path.expanduser("~/")}hcs.zarr'

# %%
# Write 5D data to multiple wells.
# Integer path names will be automatically converted to strings.
# While the NGFF specification (and iohub) allows for arbitrary names,
# the ome-zarr-py library and the napari-ome-zarr viewer
# can only load positions and arrays with name '0' for the whole plate.

position_list = (
("A", "1", "0"),
("H", 1, "0"),
("H", "12", "CannotVisualize"),
("Control", "Blank", 0),
)

with open_ome_zarr(
store_path,
layout="hcs",
mode="w-",
channel_names=["DAPI", "GFP", "Brightfield"],
) as dataset:
# Create and write to positions
# This affects the tile arrangement in visualization
for row, col, fov in position_list:
position = dataset.create_position(row, col, fov)
position["0"] = np.random.randint(
0, np.iinfo(np.uint16).max, size=(5, 3, 2, 32, 32), dtype=np.uint16
)
# Print dataset summary
dataset.print_tree()

# %%
# Append a channel to all the positions

with open_ome_zarr(store_path, mode="r+") as dataset:
for name, position in dataset.positions():
print(f"Appending a channel to position: {name}")
position.append_channel("Segmentation", resize_arrays=True)
position["0"][:, 3] = np.random.randint(
0, np.iinfo(np.uint16).max, size=(5, 2, 32, 32), dtype=np.uint16
)
dataset.print_tree()

# %%
# Try viewing the images with napari-ome-zarr
70 changes: 0 additions & 70 deletions examples/ome_zarr_writer.py

This file was deleted.

70 changes: 70 additions & 0 deletions examples/single_fov_ome_zarr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# %%
# This script shows how to create a single-FOV, single-scale OME-Zarr dataset,
# read data in read-only mode,
# append an extra time point to an existing dataset,
# and adding a new channel to an existing dataset.
# It can be run as a plain Python script,
# or as interactive cells in some IDEs.

import os

import numpy as np

from iohub.ngff import open_ome_zarr

# %%
# Set storage path

store_path = f'{os.path.expanduser("~/")}hcs.zarr'

# %%
# Write 5D data to a new Zarr store

tczyx = np.random.randint(
0, np.iinfo(np.uint16).max, size=(5, 2, 3, 32, 32), dtype=np.uint16
)

with open_ome_zarr(
store_path, layout="fov", mode="a", channel_names=["DAPI", "GFP"]
) as dataset:
dataset["img"] = tczyx

# %%
# Opening in read-only mode prevents writing

with open_ome_zarr(store_path, layout="auto", mode="r") as dataset:
img = dataset["img"]
print(img)
print(img.numpy())
try:
img[0, 0, 0, 0, 0] = 0
except Exception as e:
print(f"Writing was rejected: {e}")

# %%
# Append a new timepoint to an existing dataset

new_1czyx = np.random.randint(
0, np.iinfo(np.uint16).max, size=(1, 2, 3, 32, 32), dtype=np.uint16
)

with open_ome_zarr(store_path, layout="fov", mode="r+") as dataset:
img = dataset["img"]
print(img.shape)
img.append(new_1czyx, axis=0)
print(img.shape)

# %%
# Add a new channel and write a Z-stack

new_zyx = np.random.randint(
0, np.iinfo(np.uint16).max, size=(3, 32, 32), dtype=np.uint16
)

dataset = open_ome_zarr(store_path, mode="r+")
dataset.append_channel("New", resize_arrays=True)
dataset["img"][0, 2] = new_zyx
dataset.close()

# %%
# Try viewing the images with napari-ome-zarr
7 changes: 5 additions & 2 deletions iohub/lf_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ def channel_display_settings(
clim: Tuple[float, float, float, float] = None,
first_chan: bool = False,
):
"""This will create a dictionary used for OME-zarr metadata. Allows custom contrast limits and channel
"""This will create a dictionary used for OME-zarr metadata.
Allows custom contrast limits and channel.
names for display. Defaults everything to grayscale.
Parameters
Expand All @@ -22,7 +23,9 @@ def channel_display_settings(
clim : Tuple[float, float, float, float], optional
Contrast limits (start, end, min, max)
first_chan : bool, optional
Whether or not this is the first channel of the dataset (display will be set to active), by default False
Whether or not this is the first channel of the dataset
(display will be set to active),
by default False
Returns
-------
Expand Down
Loading

0 comments on commit 4a9e6fc

Please sign in to comment.