from datetime import datetime
from typing import Optional, Union, Iterable
from xml.etree.ElementTree import Element
import numpy as np
from SDF.data_model._helper_functions import pop_child_element, pop_element_attribute, element_is_empty
from SDF.data_model.array_data_1d import ArrayData1D
from SDF.data_model.comment import Comment
from SDF.data_model.dataset import Dataset
from SDF.data_model.date import Date
from SDF.data_model.instrument import Instrument
from SDF.data_model.name import NameElement
from SDF.data_model.owner import Owner
from SDF.data_model.parameter import ParameterType
from SDF.data_model.sample import Sample
[docs]class ArrayDataset1D(Dataset):
"""Represents an SDF <dataset> element"""
def __init__(self, name: Union[str, NameElement],
data: Union[ArrayData1D, np.ndarray], *,
unit: Optional[str] = None,
owner: Optional[Union[str, Owner]] = None,
date: Optional[Union[datetime, Date]] = None,
comment: Optional[Union[str, Comment]] = None,
samples: Optional[Iterable[Sample]] = None,
parameters: Optional[Iterable[ParameterType]] = None,
instruments: Optional[Iterable[Instrument]] = None):
super().__init__(name=name, owner=owner, date=date, comment=comment, samples=samples, parameters=parameters,
instruments=instruments)
if isinstance(data, ArrayData1D):
self.__data = data
elif isinstance(data, np.ndarray):
self.__data = ArrayData1D(data=data)
else:
raise TypeError(f"Expected ArrayData1D or np.ndarray, got {type(data)}")
self.unit = unit
@property
def data(self) -> np.ndarray:
"""Data array"""
return self.__data.data
@property
def unit(self) -> Optional[str]:
"""Unit of data"""
return self.__unit
@unit.setter
def unit(self, _unit: Optional[str]) -> None:
if _unit is None or isinstance(_unit, str):
self.__unit = _unit
else:
raise TypeError(f"Expected a string or None, got {type(_unit)}")
[docs] def to_xml_element(self) -> Element:
element = Element("dataset", dict(type=self.__data.type_for_xml))
super()._to_partial_xml_element(element)
if self.unit is not None:
element.append(Element("unit", attrib=dict(value=self.unit)))
element.append(self.__data.to_xml_element())
return element
[docs] @classmethod
def from_xml_element(cls, element: Element) -> "ArrayDataset1D":
if element.tag != "dataset":
raise ValueError(f"Expected a <dataset> element, got {element.tag}")
ds_type = pop_element_attribute(element, "type")
if ds_type != "sc":
raise ValueError(f"Expected type 'sc', got {ds_type}")
# first: name
name = NameElement.from_xml_element(pop_child_element(element, 0))
# last: data
data = ArrayData1D.from_xml_element(pop_child_element(element, -1))
# create Dataset
ret = cls(name=name, data=data)
ret._from_partial_xml_element(element)
# optional children
if len(element) and element[-1].tag == "unit":
unit_element = pop_child_element(element, -1)
ret.unit = pop_element_attribute(unit_element, "value")
if not element_is_empty(unit_element):
raise ValueError("Unit element is not empty")
if not element_is_empty(element):
raise ValueError("Element is not empty")
return ret
def __repr__(self):
return f"{self.__class__.__name__}({self.name!r}, data={self.data!r}, unit={self.unit!r}, " \
f"owner={self.owner!r}, date={self.date!r}, comment={self.comment!r}, samples={self.samples!r}, " \
f"parameters={self.parameters!r}, instruments={self.instruments!r})"
def __eq__(self, other):
if isinstance(other, ArrayDataset1D):
return super().__eq__(other) and self.__data == other.__data and self.__unit == other.__unit
return False