Source code for deepfield.field.base_spatial

"""SpatialComponent class."""
from copy import deepcopy
import numpy as np
import skimage
from skimage.transform import rescale, resize
import scipy

from .base_component import BaseComponent
from .decorators import apply_to_each_input, add_actions, extract_actions, TEMPLATE_DOCSTRING

ACTIONS_DICT = {
    "pad": (np.pad, "numpy.pad", "padded array"),
    "flip": (np.flip, "numpy.flip", "reversed order of elements in an array along the given axis"),
    "clip": (np.clip, "numpy.clip", "array of cliped values"),
    "rot90": (np.rot90, "numpy.rot90", "rotated an array by 90 degrees in the plane specified by axes"),
    "gradient": (np.gradient, "numpy.gradient", "gradient"),
    "resize": (resize, "skimage.transform.resize", "resize"),
    "rescale": (rescale, "skimage.transform.rescale", "rescale"),
    "crop": (skimage.util.crop, "crop", "cropped array by crop_width along each dimension"),
    "random_noise": (skimage.util.random_noise, "random_noise",
                     "array with added random noise of various types"),
}

[docs] @add_actions(extract_actions(scipy.ndimage), TEMPLATE_DOCSTRING) @add_actions(ACTIONS_DICT, TEMPLATE_DOCSTRING) class SpatialComponent(BaseComponent): """Base component for spatial-type attributes.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.init_state(spatial=None)
[docs] def sample_crops(self, attr, shape, size=1): """Sample random crops of fixed shape. Parameters ---------- attr : str, array-like Attributes to sample crops from. If None, use all attributes. shape : tuple Shape of crops. size : int, optional Number of crops to sample. Default to 1. Returns ------- crops : ndarray Sampled crops. """ is_list = True if isinstance(attr, str): attr = [attr] is_list = False if attr is None: attr = self.attributes data_shape = np.array(getattr(self, attr[0]).shape) valid_range = data_shape - np.array(shape) before = np.array([np.random.randint(0, d, size=size) for d in valid_range]).T after = valid_range - before res = [self.crop(attr=attr, crop_width=list(zip(before[i], after[i]))) for i in range(size)] res = np.swapaxes(res, 0, 1) return res[0] if is_list else res
[docs] def ravel(self, attr=None, inplace=True, **kwargs): """Brings component to ravel state. If not inplace returns ravel representation for attributes with pre-defined ravel transformation. Parameters ---------- attr : str, array of str Attribute to ravel. inplace : bool Modify сomponent inplace. kwargs : misc Additional named arguments. Returns ------- out : component if inplace else raveled attribute. """ if attr is not None and inplace: raise ValueError('`attr` should be None for inplace operation.') res = self._ravel(attr=attr, inplace=inplace, **kwargs) if not inplace: return res self.set_state(spatial=False) return self
def _ravel(self, attr, inplace, **kwargs): """Ravel transformations.""" return super().ravel(attr=attr, inplace=inplace, **kwargs)
[docs] def to_spatial(self, attr=None, inplace=True, **kwargs): """Bring component to spatial state. If not inplace returns spatial representation for attributes with pre-defined spatial transformation. Parameters ---------- attr : str, array of str Attribute to ravel. inplace : bool Modify сomponent inplace. kwargs : misc Additional named arguments. Returns ------- out : сomponent if inplace else raveled attribute. """ if attr is not None and inplace: raise ValueError('`attr` should be None for inplace operation.') self.pad_na(attr=attr) res = self._to_spatial(attr=attr, inplace=inplace, **kwargs) if not inplace: return res self.set_state(spatial=True) return self
@apply_to_each_input def _to_spatial(self, attr, inplace, **kwargs): """Spatial transformations.""" _ = attr, inplace, kwargs raise NotImplementedError() def _make_data_dump(self, attr, fmt=None, **kwargs): _ = fmt, kwargs return self.ravel(attr=attr, order='F', inplace=False)
[docs] def load(self, path_or_buffer, **kwargs): self.set_state(spatial=False) super().load(path_or_buffer, **kwargs) self.to_spatial()
[docs] def copy_attribute(self, attr1, attr2, box=None): """Copy attribute values to another atribute. Parameters ---------- attr1 : str Attribute to be copied. attr2 : str Destination attribute box : Sequence[int, int, int, int, int, int] or None, optional (i1, i2, j1, j2, k1, k2) - Box in which attribute values should be copied (`attr2[i1:i2, j1:j2, k1:k2]) = attr1[i1:i2, j1:j2, k1:k2]`), by default None. Returns ------- self.__class__ self """ if box is not None: getattr(self, attr2)[box[0]:box[1], box[2]:box[3], box[4]:box[5]] = getattr( self, attr1)[box[0]:box[1], box[2]:box[3], box[4]:box[5]] setattr(self, attr2, deepcopy(getattr(self, attr1))) return self
[docs] def multiply_attribute(self, attr, multiplier, box): """Multiply attribute by a constant. Parameters ---------- attr : str Attribute to be modfied. multiplier : float Multiplier. box : Sequence[int, int, int, int, int, int] (i1, i2, j1, j2, k1, k2) - Box in which attribute values should be multiplyed by a constant (`attr[i1:i2, j1:j2, k1:k2]) = attr[i1:i2, j1:j2, k1:k2]*multiplier`). Returns ------- self.__class__ self """ getattr(self, attr)[box[0]:box[1], box[2]:box[3], box[4]:box[5]] *= multiplier return self
[docs] def equals_attribute(self, attr, val, box=None, dtype=None, create=False): """Set attribute values to a constant. Parameters ---------- attr : str Attribute to be modified. multiplier : float Multiplier. box : Sequence[int, int, int, int, int, int] (i1, i2, j1, j2, k1, k2) - Box in which attribute values should be set to a constant (`attr[i1:i2, j1:j2, k1:k2]) = val`), by default None. dtype: type Type of created array. create: bool If `create==True` attribute is created, in case it does not exist. Returns ------- self.__class__ self """ dimens = self.field.grid.dimens if attr not in self.attributes and create: dtype = float if dtype is None else dtype setattr(self, attr, np.zeros(dimens, dtype=dtype)) if box is None: box = (0, dimens[0], 0, dimens[1], 0, dimens[2]) getattr(self, attr)[box[0]:box[1], box[2]:box[3], box[4]:box[5]] = val
[docs] def add_to_attribute(self, attr, addition, box): """Add a constant to an attribute. Parameters ---------- attr : str Attribute to be modfied. addition : float Addition. box : Sequence[int, int, int, int, int, int] (i1, i2, j1, j2, k1, k2) - Box in which a constant should be added to an attribute (`attr[i1:i2, j1:j2, k1:k2]) = attr[i1:i2, j1:j2, k1:k2] + addition`). Returns ------- self.__class__ self """ getattr(self, attr)[box[0]:box[1], box[2]:box[3], box[4]:box[5]] += addition return self
[docs] @apply_to_each_input def pad_na(self, attr, fill_na=0., inplace=True): """Add dummy cells into the state vector in the positions of non-active cells if necessary. Parameters ---------- attr: str, array-like Attributes to be padded with non-active cells. actnum: array-like of type bool Vector representing a mask of active and non-active cells. fill_na: float Value to be used as filler. inplace: bool Modify сomponent inplace. Returns ------- output : component if inplace else padded attribute. """ raise NotImplementedError