-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of dolomite's generics to read and save spatia…
…l objects (#1)
- Loading branch information
Showing
24 changed files
with
444 additions
and
197 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 |
---|---|---|
|
@@ -10,6 +10,11 @@ on: | |
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
id-token: write | ||
repository-projects: write | ||
contents: write | ||
pages: write | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
|
@@ -45,8 +50,6 @@ jobs: | |
run: | | ||
python -m tox -e clean,build | ||
- name: Publish package | ||
uses: pypa/[email protected] | ||
with: | ||
user: __token__ | ||
password: ${{ secrets.PYPI_API_TOKEN }} | ||
# This uses the trusted publisher workflow so no token is required. | ||
- name: Publish to PyPI | ||
uses: pypa/gh-action-pypi-publish@release/v1 |
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,7 +1,5 @@ | ||
# Changelog | ||
|
||
## Version 0.1 (development) | ||
## Version 0.1 | ||
|
||
- Feature A added | ||
- FIX: nasty bug #1729 fixed | ||
- add your changes here! | ||
- Initial version of the readers and writers for `SpatialExperiment`. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,17 +5,17 @@ | |
|
||
[metadata] | ||
name = dolomite-spatial | ||
description = Add a short description here! | ||
description = Read and write Spatial Experiments to takane representations | ||
author = Jayaram Kancherla | ||
author_email = [email protected] | ||
license = MIT | ||
license_files = LICENSE.txt | ||
long_description = file: README.md | ||
long_description_content_type = text/markdown; charset=UTF-8; variant=GFM | ||
url = https://github.com/pyscaffold/pyscaffold/ | ||
url = https://github.com/ArtifactDB/dolomite-spatial | ||
# Add here related links, for example: | ||
project_urls = | ||
Documentation = https://pyscaffold.org/ | ||
Documentation = https://github.com/ArtifactDB/dolomite-spatial | ||
# Source = https://github.com/pyscaffold/pyscaffold/ | ||
# Changelog = https://pyscaffold.org/en/latest/changelog.html | ||
# Tracker = https://github.com/pyscaffold/pyscaffold/issues | ||
|
@@ -41,14 +41,19 @@ package_dir = | |
=src | ||
|
||
# Require a min/specific Python version (comma-separated conditions) | ||
# python_requires = >=3.8 | ||
python_requires = >=3.9 | ||
|
||
# Add here dependencies of your project (line-separated), e.g. requests>=2.2,<3.0. | ||
# Version specifiers like >=2.2,<3.0 avoid problems due to API changes in | ||
# new major versions. This works if the required packages follow Semantic Versioning. | ||
# For more information, check out https://semver.org/. | ||
install_requires = | ||
importlib-metadata; python_version<"3.8" | ||
dolomite-base | ||
dolomite-sce | ||
dolomite-ranges>=0.2.1 | ||
spatialexperiment>=0.0.4 | ||
h5py | ||
|
||
|
||
[options.packages.find] | ||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import json | ||
import os | ||
|
||
import dolomite_base as dl | ||
import dolomite_sce as dlsce | ||
import h5py | ||
from biocframe import BiocFrame | ||
from dolomite_base.read_object import read_object_registry | ||
from spatialexperiment import SpatialExperiment, construct_spatial_image_class | ||
|
||
read_object_registry["spatial_experiment"] = "dolomite_spatial.read_spatial_experiment" | ||
|
||
|
||
def read_spatial_experiment(path: str, metadata: dict, **kwargs) -> SpatialExperiment: | ||
"""Load a | ||
:py:class:`~spatialexperiment.SpatialExperiment.SpatialExperiment` | ||
from its on-disk representation. | ||
This method should generally not be called directly but instead be invoked by | ||
:py:meth:`~dolomite_base.read_object.read_object`. | ||
Args: | ||
path: | ||
Path to the directory containing the object. | ||
metadata: | ||
Metadata for the object. | ||
kwargs: | ||
Further arguments. | ||
Returns: | ||
A | ||
:py:class:`~spatialexperiment.SpatialExperiment.SpatialExperiment` | ||
with file-backed arrays in the assays. | ||
""" | ||
sce = dlsce.read_single_cell_experiment(path, metadata=metadata, **kwargs) | ||
|
||
spe = SpatialExperiment( | ||
assays=sce.get_assays(), | ||
row_data=sce.get_row_data(), | ||
column_data=sce.get_column_data(), | ||
row_ranges=sce.get_row_ranges(), | ||
metadata=sce.get_metadata(), | ||
main_experiment_name=sce.get_main_experiment_name(), | ||
reduced_dims=sce.get_reduced_dims(), | ||
alternative_experiments=sce.get_alternative_experiments(), | ||
) | ||
|
||
_sp_coords_path = os.path.join(path, "coordinates") | ||
if os.path.exists(_sp_coords_path): | ||
_coords = dl.alt_read_object(_sp_coords_path, **kwargs) | ||
spe = spe.set_spatial_coordinates(_coords) | ||
else: | ||
raise FileNotFoundError(f"cannot find spatial coordinates at {path}.") | ||
|
||
_img_path = os.path.join(path, "images") | ||
if os.path.exists(_img_path): | ||
with h5py.File(os.path.join(_img_path, "mapping.h5"), "r") as handle: | ||
ghandle = handle["spatial_experiment"] | ||
|
||
sample_names = dl.load_vector_from_hdf5(ghandle["sample_names"], expected_type=str, report_1darray=True) | ||
column_samples = dl.load_vector_from_hdf5(ghandle["column_samples"], expected_type=int, report_1darray=True) | ||
|
||
image_samples = dl.load_vector_from_hdf5(ghandle["image_samples"], expected_type=int, report_1darray=True) | ||
|
||
image_ids = dl.load_vector_from_hdf5(ghandle["image_ids"], expected_type=str, report_1darray=True) | ||
image_formats = dl.load_vector_from_hdf5(ghandle["image_formats"], expected_type=str, report_1darray=True) | ||
|
||
image_scale_factors = dl.load_vector_from_hdf5( | ||
ghandle["image_scale_factors"], expected_type=float, report_1darray=True | ||
) | ||
|
||
# replace column names; just in case | ||
spe = spe.set_column_data(spe.get_column_data().set_column("sample_id", sample_names[column_samples])) | ||
|
||
image_data = [] | ||
if len(image_samples) > 0: | ||
for i, _ in enumerate(image_samples): | ||
# TODO: write reader for SpatialImage class | ||
image_data.append(construct_spatial_image_class(os.path.join(_img_path, f"{i}.{str(image_formats[i]).lower()}"))) | ||
|
||
_image_frame = BiocFrame( | ||
{ | ||
"sample_id": sample_names[image_samples], | ||
"image_id": image_ids, | ||
"data": image_data, | ||
"scale_factor": image_scale_factors, | ||
} | ||
) | ||
|
||
# add image data | ||
spe = spe.set_image_data(_image_frame) | ||
|
||
return spe |
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,46 @@ | ||
import os | ||
import shutil | ||
from typing import Optional | ||
|
||
from PIL import Image | ||
|
||
|
||
def save_image(src: str, directory: str, i: int) -> Optional[str]: | ||
"""Save an image file with proper format handling. | ||
Args: | ||
src: | ||
Source path of the image. | ||
directory: | ||
Directory to save the image to. | ||
i: | ||
Index of the image. | ||
Returns: | ||
Format of the image ('PNG' or 'TIFF') or None if format not supported. | ||
""" | ||
with Image.open(src) as img: | ||
format = img.format | ||
|
||
if format == "PNG": | ||
suffix = "png" | ||
elif format == "TIFF": | ||
suffix = "tif" | ||
else: | ||
return None | ||
|
||
dest = os.path.join(directory, f"{i}.{suffix}") | ||
|
||
try: | ||
# Try to create a hard link first | ||
os.link(src, dest) | ||
except OSError: | ||
# If linking fails, try to copy the file | ||
try: | ||
shutil.copy2(src, dest) | ||
except Exception as e: | ||
raise RuntimeError(f"failed to copy from '{src}' to '{dest}': {str(e)}") | ||
|
||
return format |
Oops, something went wrong.