-
Notifications
You must be signed in to change notification settings - Fork 68
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
ImageStack select on Physical Coordinates #1147
Changes from all commits
b1cd92f
b643423
68aed0a
864ce5d
7c54c17
30edb89
1d22d23
52cb9c4
b845fdc
96026c3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -356,7 +356,7 @@ def sel(self, indexers: Mapping[Axes, Union[int, tuple]]): | |
Parameters | ||
---------- | ||
indexers : Dict[Axes, (int/tuple)] | ||
indexers : Mapping[Axes, Union[int, tuple]] | ||
A dictionary of dim:index where index is the value or range to index the dimension | ||
Examples | ||
|
@@ -382,14 +382,67 @@ def sel(self, indexers: Mapping[Axes, Union[int, tuple]]): | |
ImageStack : | ||
a new image stack indexed by given value or range. | ||
""" | ||
|
||
# convert indexers to Dict[str, (int/slice)] format | ||
# TODO shanaxel42 check if this can be changed to xarray.copy(deep=false) | ||
stack = deepcopy(self) | ||
selector = indexing_utils.convert_to_selector(indexers) | ||
stack._data._data = indexing_utils.index_keep_dimensions(self.xarray, selector) | ||
return stack | ||
|
||
def isel(self, indexers: Mapping[Axes, Union[int, tuple]]): | ||
"""Given a dictionary mapping the index name to either a value or a range represented as a | ||
tuple, return an Imagestack with each dimension indexed by position accordingly | ||
Parameters | ||
---------- | ||
indexers : Dict[Axes, (int/tuple)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is inconsistent with the typing in your function declaration. |
||
A dictionary of dim:index where index is the value or range to index the dimension | ||
Examples | ||
-------- | ||
Create an Imagestack using the ``synthetic_stack`` method | ||
>>> from starfish import ImageStack | ||
>>> from starfish.types import Axes | ||
>>> stack = ImageStack.synthetic_stack(5, 5, 15, 200, 200) | ||
>>> stack | ||
<starfish.ImageStack (r: 5, c: 5, z: 15, y: 200, x: 200)> | ||
>>> stack.isel({Axes.ROUND: (1, None), Axes.CH: 0, Axes.ZPLANE: 0}) | ||
<starfish.ImageStack (r: 4, c: 1, z: 1, y: 200, x: 200)> | ||
>>> stack.isel({Axes.ROUND: 0, Axes.CH: 0, Axes.ZPLANE: 1, | ||
...Axes.Y: 100, Axes.X: (None, 100)}) | ||
<starfish.ImageStack (r: 1, c: 1, z: 1, y: 1, x: 100)> | ||
and the imagestack's physical coordinates | ||
xarray also indexed and recalculated according to the x,y slicing. | ||
Returns | ||
------- | ||
ImageStack : | ||
a new image stack indexed by given value or range. | ||
""" | ||
stack = deepcopy(self) | ||
selector = indexing_utils.convert_to_selector(indexers) | ||
stack._data._data = indexing_utils.index_keep_dimensions(self.xarray, selector, by_pos=True) | ||
return stack | ||
|
||
def sel_by_physical_coords( | ||
self, indexers: Mapping[Coordinates, Union[Number, Tuple[Number, Number]]]): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you find yourself repeating yourself a ton about |
||
""" | ||
Given a dictionary mapping the coordinate name to either a value or a range represented as a | ||
tuple, return an Imagestack with each the Coordinate dimension indexed accordingly. | ||
Parameters | ||
---------- | ||
indexers : Mapping[Coordinates, Union[Number, Tuple[Number, Number]]]: | ||
A dictionary of coord:index where index is the value or range to index the coordinate | ||
dimension. | ||
Returns | ||
------- | ||
ImageStack : | ||
a new image stack indexed by given value or range. | ||
""" | ||
new_indexers = indexing_utils.convert_coords_to_indices(self.xarray, indexers) | ||
return self.isel(new_indexers) | ||
|
||
def get_slice( | ||
self, | ||
selector: Mapping[Axes, Union[int, slice]] | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,8 +1,9 @@ | ||||||
from typing import Mapping, MutableMapping, Union | ||||||
from typing import Dict, Mapping, MutableMapping, Tuple, Union | ||||||
|
||||||
import numpy as np | ||||||
import xarray as xr | ||||||
|
||||||
from starfish.types import Axes | ||||||
from starfish.types import Axes, Coordinates, Number | ||||||
|
||||||
|
||||||
def convert_to_selector( | ||||||
|
@@ -26,16 +27,83 @@ def convert_to_selector( | |||||
return return_dict | ||||||
|
||||||
|
||||||
def index_keep_dimensions( | ||||||
data: xr.DataArray, indexers: Mapping[str, Union[int, slice]]) -> xr.DataArray: | ||||||
def convert_coords_to_indices(array: xr.DataArray, | ||||||
indexers: Mapping[Coordinates, Union[Number, Tuple[Number, Number]]] | ||||||
) -> Dict[Axes, Union[int, Tuple[Number, Number]]]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. out of curiosity why do you prefer Mapping to Dict? Mapping always give me a lot of lint troubles |
||||||
""" | ||||||
Convert mapping of physical coordinates to value or range to mapping of corresponding Axes and | ||||||
positional coordinates. | ||||||
Parameters | ||||||
---------- | ||||||
array : xr.DataArray | ||||||
The xarray with both physical and positional coordinates. | ||||||
indexers: Mapping[Coordinates, Union[Number, Tuple[Number, Number]]] | ||||||
Mapping of physical coordinates to value or range | ||||||
Returns | ||||||
------- | ||||||
Mapping[Axes, Union[int, Tuple[Number, Number]]]: | ||||||
Mapping of Axes and positional indices that correspond to the given physical indices. | ||||||
""" | ||||||
axes_indexers: Dict[Axes, Union[int, Tuple[Number, Number]]] = dict() | ||||||
if Coordinates.X in indexers: | ||||||
idx_x = find_nearest(array[Coordinates.X.value], indexers[Coordinates.X]) | ||||||
axes_indexers[Axes.X] = idx_x | ||||||
if Coordinates.Y in indexers: | ||||||
idx_y = find_nearest(array[Coordinates.Y.value], indexers[Coordinates.Y]) | ||||||
axes_indexers[Axes.Y] = idx_y | ||||||
if Coordinates.Z in indexers: | ||||||
ttung marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
idx_z = find_nearest(array[Coordinates.Z.value], indexers[Coordinates.Z]) | ||||||
axes_indexers[Axes.ZPLANE] = idx_z | ||||||
return axes_indexers | ||||||
|
||||||
|
||||||
def index_keep_dimensions(data: xr.DataArray, | ||||||
indexers: Mapping[str, Union[int, slice]], | ||||||
by_pos: bool=False | ||||||
) -> xr.DataArray: | ||||||
"""Takes an xarray and key to index it. Indexes then adds back in lost dimensions""" | ||||||
# store original dims | ||||||
original_dims = data.dims | ||||||
# index | ||||||
data = data.sel(indexers) | ||||||
if by_pos: | ||||||
data = data.isel(indexers) | ||||||
else: | ||||||
data = data.sel(indexers) | ||||||
# find missing dims | ||||||
missing_dims = set(original_dims) - set(data.dims) | ||||||
# Add back in missing dims | ||||||
data = data.expand_dims(tuple(missing_dims)) | ||||||
# Reorder to correct format | ||||||
return data.transpose(*original_dims) | ||||||
|
||||||
|
||||||
def find_nearest(array: xr.DataArray, | ||||||
value: Union[Number, Tuple[Number, Number]] | ||||||
) -> Union[int, Tuple[int, int]]: | ||||||
""" | ||||||
Given an xarray and value or tuple range return the indices of the closest corresponding | ||||||
value/values in the array. | ||||||
Parameters | ||||||
---------- | ||||||
array: xr.DataArray | ||||||
The array to do lookups in. | ||||||
value : Union[Number, Tuple[Number, Number]] | ||||||
The value or values to lookup. | ||||||
Returns | ||||||
------- | ||||||
Union[int, Tuple[int, int]]: | ||||||
The index or indicies of the entries closest to the given values in the array. | ||||||
""" | ||||||
array = np.asarray(array) | ||||||
if isinstance(value, tuple): | ||||||
idx1 = (np.abs(array - value[0])).argmin() | ||||||
idx2 = (np.abs(array - value[1])).argmin() | ||||||
return idx1, idx2 | ||||||
idx = (np.abs(array - value)).argmin() | ||||||
return idx |
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.
Checked, cannot do regular copy get an xarray error.