-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
set-scale
utility
#228
Merged
talonchandler
merged 40 commits into
czbiohub-sf:main
from
aaronalvarezcz:update-scale-metadata-util
Sep 26, 2024
Merged
set-scale
utility
#228
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
9e0bc16
add update_scale_metadata.py
aaronalvarezcz 59ab2ac
add update-scale-metadata command to cli
aaronalvarezcz 6217bad
add zyx flags for update-scale-metadata utility
aaronalvarezcz 7bda4b3
add handling of missing zyx cli flags for update-scale-metadata
aaronalvarezcz 953b4b9
update order of params in update_scale_metadata to be passed as z, y, x
aaronalvarezcz 4e158d6
Merge branch 'main' into update-scale-metadata-util
talonchandler ea4dd73
black
talonchandler fdfca08
isort
talonchandler a5ec62f
flake8
talonchandler 826b250
Merge branch 'main' into update-scale-metadata-util
talonchandler e660042
update to `iohub.ngff.models`
talonchandler fcc408d
move parsing utilities to iohub
talonchandler c8816e5
move update_scale_metadata inside cli folder
talonchandler 2642a51
typo
talonchandler e0ff8e2
update import for refactor
talonchandler 7fac9f8
require -z, -y, -x flags
talonchandler de5c883
simplify interface and print statements
talonchandler 9d6492e
clean up print statement
talonchandler 387ac59
update the last three dimensions for OME compatibility
talonchandler 461dc65
fix tests
talonchandler dcb00a1
fix test
talonchandler 37add16
helper functions for axis names
talonchandler 6b4461d
set_scale API
talonchandler 353ab65
consolidate and clean CLI
talonchandler a900763
test get_axis_index
talonchandler b98381f
test_set_scale
talonchandler 74bdb7b
case insensitive axis name
talonchandler 6b857a9
tests don't overwrite data
talonchandler 9e6d676
save old metadata in a namespace
talonchandler 9df8007
test multiple inputs to cli
talonchandler e858dc6
handle empty current_transforms
talonchandler 75d2525
improved empty handling
talonchandler b46c5f3
unit test CLI plate expansion into positions
talonchandler d657c88
cleanup test
talonchandler 0e3ac36
test OptionEatAll
talonchandler e1a04cc
stronger plate-expansion test
talonchandler f678f44
fix bug when scale transform does not exist
ieivanov a551257
create "iohub" dict if it doesn't exist, and update it
talonchandler b49980e
test old_* metadata
talonchandler bb419b2
rename old_x to prior_x_scale
ieivanov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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,88 @@ | ||
from pathlib import Path | ||
from typing import Callable, List | ||
|
||
import click | ||
from natsort import natsorted | ||
|
||
from iohub.ngff import Plate, open_ome_zarr | ||
|
||
|
||
def _validate_and_process_paths( | ||
ctx: click.Context, opt: click.Option, value: List[str] | ||
) -> list[Path]: | ||
# Sort and validate the input paths, | ||
# expanding plates into lists of positions | ||
input_paths = [Path(path) for path in natsorted(value)] | ||
for path in input_paths: | ||
with open_ome_zarr(path, mode="r") as dataset: | ||
if isinstance(dataset, Plate): | ||
plate_path = input_paths.pop() | ||
for position in dataset.positions(): | ||
input_paths.append(plate_path / position[0]) | ||
|
||
return input_paths | ||
|
||
|
||
def input_position_dirpaths() -> Callable: | ||
def decorator(f: Callable) -> Callable: | ||
return click.option( | ||
"--input-position-dirpaths", | ||
"-i", | ||
cls=OptionEatAll, | ||
type=tuple, | ||
required=True, | ||
callback=_validate_and_process_paths, | ||
help=( | ||
"List of paths to input positions, " | ||
"each with the same TCZYX shape. " | ||
"Supports wildcards e.g. 'input.zarr/*/*/*'." | ||
), | ||
)(f) | ||
|
||
return decorator | ||
|
||
|
||
# Copied directly from https://stackoverflow.com/a/48394004 | ||
# Enables `-i ./input.zarr/*/*/*` | ||
class OptionEatAll(click.Option): | ||
def __init__(self, *args, **kwargs): | ||
self.save_other_options = kwargs.pop("save_other_options", True) | ||
nargs = kwargs.pop("nargs", -1) | ||
assert nargs == -1, "nargs, if set, must be -1 not {}".format(nargs) | ||
super(OptionEatAll, self).__init__(*args, **kwargs) | ||
self._previous_parser_process = None | ||
self._eat_all_parser = None | ||
|
||
def add_to_parser(self, parser, ctx): | ||
def parser_process(value, state): | ||
# method to hook to the parser.process | ||
done = False | ||
value = [value] | ||
if self.save_other_options: | ||
# grab everything up to the next option | ||
while state.rargs and not done: | ||
for prefix in self._eat_all_parser.prefixes: | ||
if state.rargs[0].startswith(prefix): | ||
done = True | ||
if not done: | ||
value.append(state.rargs.pop(0)) | ||
else: | ||
# grab everything remaining | ||
value += state.rargs | ||
state.rargs[:] = [] | ||
value = tuple(value) | ||
|
||
# call the actual process | ||
self._previous_parser_process(value, state) | ||
|
||
retval = super(OptionEatAll, self).add_to_parser(parser, ctx) | ||
for name in self.opts: | ||
our_parser = parser._long_opt.get(name) or parser._short_opt.get( | ||
name | ||
) | ||
if our_parser: | ||
self._eat_all_parser = our_parser | ||
self._previous_parser_process = our_parser.process | ||
our_parser.process = parser_process | ||
break | ||
return retval |
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ziw-liu our original line didn't update the metadata in the way we intended. My fault for not testing this.
@ziw-liu this is the simplest solution I could get to work, but it's a bit ugly. Should
.zattrs["iohub"]
be part of the pydantic models so that we can usedump_meta
?