Source code for imagedata.axis

"""Axis defines a dimension of an images Series.
"""

from abc import ABCMeta  # , abstractmethod, abstractproperty
import sys
import logging
import numbers
import numpy as np


logger = logging.getLogger(__name__)


class Axis(object, metaclass=ABCMeta):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return ("{0}({1})".format(self.__class__.__name__, self.name))

    def __str__(self):
        return "{0.name!s}".format(self)


[docs] class UniformAxis(Axis): """Define axis by giving start, stop and step (optional). Start, stop and step are given in actual values Examples: >>> ax = UniformAxis('row', 0, 128) """ def __init__(self, name, start, stop, step=1): super(UniformAxis, self).__init__(name) self.start = start self.stop = stop self.step = step def __getitem__(self, item): start, stop, step = 0, None, 1 # logger.debug('UniformAxis: item %s' % type(item)) if type(item) is Ellipsis: # logger.debug('UniformAxis: Ellipsis') return self elif isinstance(item, slice): # logger.debug('UniformAxis: slice') start = self.start + (item.start or 0) * self.step stop = self.stop if item.stop is not None: stop = self.start + (item.stop * self.step) stop = min(self.stop, stop) step = (item.step or 1) * self.step elif isinstance(item, int): _value = self.start + item * self.step if _value < self.stop: return _value raise StopIteration else: raise ValueError('Cannot slice axis with {}'.format(type(item))) # logger.debug('UniformAxis: slice %d,%d,%d' % (start,stop,step)) return UniformAxis(self.name, start, stop, step) def __len__(self): try: return abs(int((self.stop - self.start) / self.step)) except ValueError: return sys.maxsize except Exception: raise def __next__(self): _value = self.start while _value < self.stop: yield _value _value += self.step @property def slice(self): return self.start, self.stop, self.step def __repr__(self): return "{0}({1.name!s},{1.start!s},{1.stop!s},{1.step!s})".format( self.__class__.__name__, self ) def __str__(self): return "{0.name!s}: {0.start!s}:{0.stop!s}:{0.step!s}".format(self)
[docs] class UniformLengthAxis(UniformAxis): """Define axis by giving start, length and step (optional). Start and step are given in actual values. Examples: >>> ax = UniformLengthAxis('row', 0, 128) """ def __init__(self, name, start, n, step=1): super(UniformLengthAxis, self).__init__(name, start, start + n * step, step) self.n = n def __getitem__(self, item): start, n, step = self.start, self.n, self.step # logger.debug('UniformLengthAxis: item %s' % type(item)) if type(item) is Ellipsis: # logger.debug('UniformLengthAxis: Ellipsis') return self elif isinstance(item, slice): # logger.debug('UniformLengthAxis: slice') start = self.start + (item.start or 0) * self.step stop = self.start + (item.stop or self.n) * self.step step = (item.step or 1) * self.step try: n = int(round((stop - start) / step)) except ValueError: n = sys.maxsize except Exception: raise n = min(self.n, n) elif isinstance(item, int): if item < n: return self.start + item * self.step raise StopIteration else: raise ValueError('Cannot slice axis with {}'.format(type(item))) # logger.debug('UniformLengthAxis: slice %d,%d,%d' % (start,stop,step)) return UniformLengthAxis(self.name, start, n, step) def __len__(self): return self.n def __next__(self): _value = self.start for _ in range(self.n): yield _value _value += self.step def __repr__(self): return "{0}({1.name!s},{1.start!s},{1.n!s},{1.step!s})".format( self.__class__.__name__, self ) def __str__(self): return "{0.name!s}: {0.n!s}*({0.start!s}:{0.step!s})".format(self)
[docs] class VariableAxis(Axis): """Define axis by giving an array of values. values are actual values. Examples: >>> ax = VariableAxis('time', [0, 1, 4, 9, 11, 13]) """ def __init__(self, name, values): super(VariableAxis, self).__init__(name) self.values = np.array(values) if len(values) < 2: self.step = 1 elif not isinstance(values[0], numbers.Number): self.step = None else: ds = values[1] - values[0] for i in range(2, len(values)): d = values[i] - values[i - 1] if abs(d - ds) / ds > 1e-4: ds = None break self.step = ds def __getitem__(self, item): """Slice the axis - item: tuple of slice indices """ start, stop, step = 0, None, 1 # logger.debug('VariableAxis: item %s' % type(item)) if type(item) is Ellipsis: # logger.debug('VariableAxis: Ellipsis') return self elif isinstance(item, slice): # logger.debug('VariableAxis: slice') start = item.start or 0 stop = item.stop or len(self.values) stop = min(len(self.values), stop) step = item.step or 1 elif isinstance(item, int): return self.values[item] else: raise ValueError('Cannot slice axis with {}'.format(type(item))) return VariableAxis(self.name, self.values[start:stop:step]) def __len__(self): return len(self.values) def __next__(self): for _ in self.values: yield _ def __repr__(self): return "{0}({1.name!s},{1.values!r})".format( self.__class__.__name__, self ) def __str__(self): return "{0.name!s}: {0.values!s}".format(self)