from copy import copy
from typing import Optional
import numpy as np
from .help_types import ArrayLike, RealNumber
[docs]class ArrayAxis:
def __init__(self, start: RealNumber, end: RealNumber,
sample: RealNumber) -> None:
'''The representation of some array axis.
This is description of sequence. The start sequence. The end sequence.
And the sample spacing between elements.
Args:
start (RealNumber): is start of array.
end (RealNumber): is end of array.
sample (RealNumber): is sample of array.
'''
self._start = start
self._end = end
self._sample = sample
self._array: Optional[np.ndarray] = None
self._actual_sample: Optional[RealNumber] = None
[docs] def _reset_property(self) -> None:
self._array = None
self._actual_sample = None
@property
def array(self) -> np.ndarray:
'''Representation of array axis into np.ndarray
Returns:
np.ndarray: numpy array
'''
if self._array is None:
self._array = np.linspace(
self._start, self._end,
round(abs((self._end - self._start) / self._sample)) + 1
)
return self._array
@property
def start(self) -> RealNumber:
return self._start
@start.setter
def start(self, value: RealNumber) -> None:
self._start = value
self._reset_property()
@property
def end(self) -> RealNumber:
return self._end
@end.setter
def end(self, value: RealNumber) -> None:
self._end = value
self._reset_property()
@property
def actual_sample(self) -> RealNumber:
if self._actual_sample is None:
self._actual_sample = get_actual_sample(self.array)
return self._actual_sample
@property
def sample(self) -> RealNumber:
return self._sample
@sample.setter
def sample(self, value: RealNumber) -> None:
self._sample = value
self._reset_property()
@property
def size(self) -> int:
return self.array.size
[docs] def copy(self) -> 'ArrayAxis':
'''Copy of array axis.
Returns:
ArrayAxis: copy of array axis
'''
return copy(self)
[docs] def __str__(self):
result = f"start: {self._start}\n" \
f"end: {self._end}\n" \
f"sample: {self._sample}\n" \
f"size: {self.size}\n" \
f"calculated sample: {self.actual_sample}"
return result
[docs]def get_actual_sample(x: np.ndarray) -> RealNumber:
'''Calculate actual sample. Use for self-test. Problem with floating point
in Python (https://docs.python.org/3/tutorial/floatingpoint.html).
Args:
x (np.ndarray): array of numbers.
Returns:
RealNumber: an actual sample
'''
diff = np.min(np.diff(x))
values, counts = np.unique(diff, return_counts=True)
common_sample = values[np.argmax(counts)]
return common_sample
[docs]def get_array_axis_from_array(
x: ArrayLike, round_dx: bool = True) -> ArrayAxis:
'''Create instance of Axis from some array of numbers.
Args:
x (ArrayLike): input array_like of numbers.
round_dx (bool, optional): if True then round sample. Defaults to True.
Returns:
ArrayAxis: new ArrayAxis.
'''
x = np.array(x)
dx = get_actual_sample(x)
if round_dx and isinstance(dx, (int, float)):
dx = 1 / round(1 / dx) if dx < 1 else round(dx)
return ArrayAxis(start=x[0], end=x[-1], sample=dx)