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)