-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #60 from thewtex/hatch
ENH: Migrate to hatch for packaging
- Loading branch information
Showing
6 changed files
with
191 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# SPDX-FileCopyrightText: 2022-present NumFOCUS <info@numfocus.org> | ||
# | ||
# SPDX-License-Identifier: MIT | ||
__version__ = '0.10.0' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
"""multiscale-spatial-image | ||
Generate a multiscale spatial image.""" | ||
|
||
|
||
__all__ = [ | ||
"MultiscaleSpatialImage", | ||
"Methods", | ||
"to_multiscale", | ||
"itk_image_to_multiscale", | ||
"__version__", | ||
] | ||
|
||
from .__about__ import __version__ | ||
from .multiscale_spatial_image import MultiscaleSpatialImage, Methods | ||
from .to_multiscale import to_multiscale, itk_image_to_multiscale |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
from typing import Union, List | ||
from enum import Enum | ||
|
||
import xarray as xr | ||
from datatree import DataTree | ||
from datatree.treenode import TreeNode | ||
import numpy as np | ||
|
||
|
||
class MultiscaleSpatialImage(DataTree): | ||
"""A multi-scale representation of a spatial image. | ||
This is an xarray DataTree, with content compatible with the Open Microscopy Environment- | ||
Next Generation File Format (OME-NGFF). | ||
The tree contains nodes in the form: `scale{scale}` where *scale* is the integer scale. | ||
Each node has a the same named `Dataset` that corresponds to to the NGFF dataset name. | ||
For example, a three-scale representation of a *cells* dataset would have `Dataset` nodes: | ||
scale0 | ||
scale1 | ||
scale2 | ||
""" | ||
|
||
def __init__( | ||
self, | ||
name: str = "multiscales", | ||
data: Union[xr.Dataset, xr.DataArray] = None, | ||
parent: TreeNode = None, | ||
children: List[TreeNode] = None, | ||
): | ||
"""DataTree with a root name of *multiscales*.""" | ||
super().__init__(data=data, name=name, parent=parent, children=children) | ||
|
||
def to_zarr(self, store, mode: str = "w", encoding=None, **kwargs): | ||
""" | ||
Write multi-scale spatial image contents to a Zarr store. | ||
Metadata is added according the OME-NGFF standard. | ||
store : MutableMapping, str or Path, optional | ||
Store or path to directory in file system | ||
mode : {{"w", "w-", "a", "r+", None}, default: "w" | ||
Persistence mode: “w” means create (overwrite if exists); “w-” means create (fail if exists); | ||
“a” means override existing variables (create if does not exist); “r+” means modify existing | ||
array values only (raise an error if any metadata or shapes would change). The default mode | ||
is “a” if append_dim is set. Otherwise, it is “r+” if region is set and w- otherwise. | ||
encoding : dict, optional | ||
Nested dictionary with variable names as keys and dictionaries of | ||
variable specific encodings as values, e.g., | ||
``{"scale0/image": {"my_variable": {"dtype": "int16", "scale_factor": 0.1}, ...}, ...}``. | ||
See ``xarray.Dataset.to_zarr`` for available options. | ||
kwargs : | ||
Additional keyword arguments to be passed to ``datatree.DataTree.to_zarr`` | ||
""" | ||
|
||
multiscales = [] | ||
scale0 = self[self.groups[1]] | ||
for name in scale0.ds.data_vars.keys(): | ||
|
||
ngff_datasets = [] | ||
for child in self.children: | ||
image = self[child].ds | ||
scale_transform = [] | ||
translate_transform = [] | ||
for dim in image.dims: | ||
if len(image.coords[dim]) > 1 and np.issubdtype(image.coords[dim].dtype, np.number): | ||
scale_transform.append( | ||
float(image.coords[dim][1] - image.coords[dim][0]) | ||
) | ||
else: | ||
scale_transform.append(1.0) | ||
if len(image.coords[dim]) > 0 and np.issubdtype(image.coords[dim].dtype, np.number): | ||
translate_transform.append(float(image.coords[dim][0])) | ||
else: | ||
translate_transform.append(0.0) | ||
|
||
ngff_datasets.append( | ||
{ | ||
"path": f"{self[child].name}/{name}", | ||
"coordinateTransformations": [ | ||
{ | ||
"type": "scale", | ||
"scale": scale_transform, | ||
}, | ||
{ | ||
"type": "translation", | ||
"translation": translate_transform, | ||
}, | ||
], | ||
} | ||
) | ||
|
||
image = scale0.ds | ||
axes = [] | ||
for axis in image.dims: | ||
if axis == "t": | ||
axes.append({"name": "t", "type": "time"}) | ||
elif axis == "c": | ||
axes.append({"name": "c", "type": "channel"}) | ||
else: | ||
axes.append({"name": axis, "type": "space"}) | ||
if "units" in image.coords[axis].attrs: | ||
axes[-1]["unit"] = image.coords[axis].attrs["units"] | ||
|
||
multiscales.append( | ||
{ | ||
"@type": "ngff:Image", | ||
"version": "0.4", | ||
"name": name, | ||
"axes": axes, | ||
"datasets": ngff_datasets, | ||
} | ||
) | ||
|
||
# NGFF v0.4 metadata | ||
ngff_metadata = {"multiscales": multiscales, "multiscaleSpatialImageVersion": 1} | ||
self.ds = self.ds.assign_attrs(**ngff_metadata) | ||
|
||
super().to_zarr(store, **kwargs) | ||
|
||
|
||
class Methods(Enum): | ||
XARRAY_COARSEN = "xarray.DataArray.coarsen" | ||
ITK_BIN_SHRINK = "itk.bin_shrink_image_filter" | ||
ITK_GAUSSIAN = "itk.discrete_gaussian_image_filter" | ||
ITK_LABEL_GAUSSIAN = "itk.discrete_gaussian_image_filter_label_interpolator" | ||
DASK_IMAGE_GAUSSIAN = "dask_image.ndfilters.gaussian_filter" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 0 additions & 1 deletion
1
test/test_multiscale_spatial_image.py → test/test_to_multiscale.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
from platform import processor | ||
import pytest | ||
|
||
from pathlib import Path | ||
|