Skip to content
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

Enable dim_order kwargs for direct image conversions #238

Merged
merged 14 commits into from
Feb 6, 2023
Merged
252 changes: 154 additions & 98 deletions doc/06-Working-with-Images.ipynb

Large diffs are not rendered by default.

23 changes: 12 additions & 11 deletions src/imagej/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ def sync_image(self, imp: "jc.ImagePlus" = None):
pixels = imp.getProcessor().getPixels()
stack.setPixels(pixels, imp.getCurrentSlice())

def to_dataset(self, data):
def to_dataset(self, data, dim_order=None):
"""Convert the data into an ImageJ2 Dataset.

Converts a Python image (e.g. xarray or numpy array) or Java image (e.g.
Expand All @@ -428,7 +428,6 @@ def to_dataset(self, data):
:param data: Image object to be converted to Dataset.
:return: A net.imagej.Dataset.
"""
dim_order = None
if sj.isjava(data):
if dim_order:
_logger.warning(
Expand All @@ -447,7 +446,7 @@ def to_dataset(self, data):

raise TypeError(f"Type not supported: {type(data)}")

def to_img(self, data):
def to_img(self, data, dim_order=None):
"""Convert the data into an ImgLib2 Img.

Converts a Python image (e.g. xarray or numpy array) or Java image (e.g.
Expand All @@ -456,7 +455,6 @@ def to_img(self, data):
:param data: Image object to be converted to Img.
:return: A net.imglib2.img.Img.
"""
dim_order = None
if sj.isjava(data):
if dim_order:
_logger.warning(
Expand Down Expand Up @@ -500,7 +498,7 @@ def to_java(self, data, **hints):

return sj.to_java(data, **hints)

def to_xarray(self, data):
def to_xarray(self, data, dim_order=None):
"""Convert the data into an ImgLib2 Img.

Converts a Python image (e.g. xarray or numpy array) or Java image (e.g.
Expand All @@ -509,21 +507,24 @@ def to_xarray(self, data):
:param data: Image object to be converted to xarray.DataArray.
:return: An xarray.DataArray.
"""
dim_order = None
if sj.isjava(data):
if dim_order:
_logger.warning(f"Conversion hints are not supported for {type(data)}.")
if isinstance(data, jc.ImagePlus):
data = convert.imageplus_to_imgplus(self._ij, data)
if convert.supports_java_to_xarray(self._ij, data):
if dim_order:
_logger.warning(
f"Conversion hints are not supported for {type(data)}."
)
return convert.java_to_xarray(self._ij, data)
if convert.supports_java_to_ndarray(self._ij, data):
return convert.ndarray_to_xarray(
convert.java_to_ndarray(self._ij, data)
)

if images.is_xarraylike(data):
return convert._rename_xarray_dims(data, dim_order)
if images.is_arraylike(data):
return convert.ndarray_to_xarray(data, dim_order)

return TypeError(f"Type not supported: {type(data)}.")
raise TypeError(f"Type not supported: {type(data)}.")

# -- Deprecated methods --

Expand Down
8 changes: 2 additions & 6 deletions src/imagej/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,7 @@ def ndarray_to_xarray(narr: np.ndarray, dim_order=None) -> xr.DataArray:
assert images.is_arraylike(narr)
if dim_order:
# check dim length
if narr.ndim != len(dim_order):
raise ValueError(
f"Expected {narr.ndim} dimensions but got {len(dim_order)}."
)
dim_order = dims._validate_dim_order(dim_order, narr.shape)
return xr.DataArray(narr, dims=dim_order)
return xr.DataArray(narr)

Expand Down Expand Up @@ -557,8 +554,7 @@ def _rename_xarray_dims(xarr, new_dims: Sequence[str]):
if not new_dims:
return xarr
# check dim length
if xarr.ndim != len(new_dims):
raise ValueError(f"Expected {xarr.ndim} dimensions but got {len(new_dims)}.")
new_dims = dims._validate_dim_order(new_dims, xarr.shape)
dim_map = {}
for i in range(xarr.ndim):
dim_map[curr_dims[i]] = new_dims[i]
Expand Down
29 changes: 28 additions & 1 deletion src/imagej/dims.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,13 @@ def _get_scale(axis):
:return: The scale for this axis or None if it is a non-numeric scale.
"""
try:
return axis.values[1] - axis.values[0]
# HACK: This axis length check is a work around for singleton dimensions.
# You can't calculate the slope of a singleton dimension.
# This section will be removed when axis-scale-logic is merged.
if len(axis) <= 1:
return 1
else:
return axis.values[1] - axis.values[0]
except TypeError:
return None

Expand Down Expand Up @@ -397,6 +403,27 @@ def _convert_dims(dimensions: List[str], direction: str) -> List[str]:
return dimensions


def _validate_dim_order(dim_order: List[str], shape: tuple) -> List[str]:
"""
Validate a List of dimensions. If the dimension list is smaller
fill the rest of the list with "dim_n" (following xarrray convention).

:param dim_order: List of dimensions (e.g. X, Y, Channel, Z, Time)
:param shape: Shape image for the dimension order.
:return: List with "dim_n" dimensions added to match shape length.
"""
dim_len = len(dim_order)
shape_len = len(shape)
if dim_len < shape_len:
d = shape_len - dim_len
for i in range(d):
dim_order.append(f"dim_{i}")
return dim_order
if dim_len > shape_len:
raise ValueError(f"Expected {shape_len} dimensions but got {dim_len}.")
return dim_order


def _has_axis(rai: "jc.RandomAccessibleInterval"):
"""Check if a RandomAccessibleInterval has axes."""
if sj.isjava(rai):
Expand Down
1 change: 0 additions & 1 deletion src/imagej/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ def rai_slice(rai, imin: Tuple, imax: Tuple, istep: Tuple):
dim_itr = range(len(shape))

for py_dim, j_dim in zip(dim_itr, dim_itr):

# Set minimum
if imin[py_dim] is None:
index = 0
Expand Down
Loading