Source code for autopilot.data.modeling.base

"""
Base classes for data models -- the ``Data`` class itself.
"""
import typing
from datetime import datetime
from typing import Optional, List
import pandas as pd

import tables

from autopilot.root import Autopilot_Type

[docs]class Data(Autopilot_Type): """ The top-level container for Data. Subtypes will define more specific formats and uses of data, but this is the most general form used to represent the type and meaning of data. The Data class is not intended to contain individual fields, but collections of data that are collected as a unit, whether that be a video frame along with its timestamp and encoding, or a single trial of behavioral data. This class is also generally not intended to be used for the literal transport of data when performance is necessary: this class by default does type validation on instantiation that takes time (see the `construct <https://pydantic-docs.helpmanual.io/usage/models/#creating-models-without-validation>`_ method for validation-less creation). It is usually more to specify the type, grouping, and annotation for a given unit of data -- though users should feel free to dump their data in a :class:`.Data` object if it is not particularly performance sensitive. """
[docs]class Table(Data): """ Tabular data: each field will have multiple values -- in particular an equal number across fields. Used for trialwise data, and can be used to create pytables descriptions. .. todo:: To make this usable as a live container of data, the fields need to be declared as Lists (eg. instead of just declaring something an ``int``, it must be specified as a ``List[int]`` to pass validation. We should expand this model to relax that constraint and effectively treat every field as containing a list of values. """
[docs] @classmethod def to_pytables_description(cls) -> typing.Type[tables.IsDescription]: """ Convert the fields of this table to a pytables description. See :func:`~.interfaces.tables.model_to_description` """ from autopilot.data.interfaces.tables import model_to_description return model_to_description(cls)
[docs] @classmethod def from_pytables_description(cls, description:typing.Type[tables.IsDescription]) -> 'Table': """ Create an instance of a table from a pytables description See :func:`~.interfaces.tables.description_to_model` Args: description (:class:`tables.IsDescription`): A Pytables description """ from autopilot.data.interfaces.tables import description_to_model return description_to_model(description, cls)
[docs] def to_df(self) -> pd.DataFrame: """ Create a dataframe from the lists of fields Returns: :class:`pandas.DataFrame` """ return pd.DataFrame(self.dict())
[docs]class Attributes(Data): """ A set of attributes that is intended to have a single representation per usage: eg. a subject has a single set of biographical information. Useful to specify a particular type of storage that doesn't need to include variable numbers of each field (eg. the tables interface stores attribute objects as metadata on a node, rather than as a table). """
[docs]class Schema(Autopilot_Type): """ A special type of type intended to be a representation of an abstract structure/schema of data, rather than a live container of data objects themselves. This class is used for constructing data containers, translating between formats, etc. rather than momentary data handling """
[docs]class Node(Autopilot_Type): """ Abstract representation of a Node in a treelike or linked data structure. This should be extended by interfaces when relevant and needed to implement an abstract representation of their structure. This class purposely lacks structure like a path or parents pending further usage in interfaces to see what would be the best means of implementing them. """
[docs]class Group(Autopilot_Type): """ A generic representation of a "Group" if present in a given interface. Useful for when, for example in a given container format you want to make an empty group that will be filled later, or one that has to be present for syntactic correctness. A children attribute is present because it is definitive of groups, but should be overridden by interfaces that use it. """ children: Optional[List[Node]] = None
BASE_TYPES = ( bool, int, float, str, bytes, datetime ) """ Base Python types that should be suppported by every interface """