Source code for vivarium.engine.framework.lookup.interface

"""
=====================
LookupTable Interface
=====================

This module provides an interface to the :class:`LookupTableManager <vivarium.engine.framework.lookup.manager.LookupTableManager>`.

"""

from __future__ import annotations

import warnings
from collections.abc import Mapping
from typing import Any, overload

import pandas as pd

from vivarium.engine.framework.lookup.manager import LookupTableManager
from vivarium.engine.framework.lookup.table import (
    FLAT_DATAFRAME_DEPRECATION_MESSAGE,
    MAPPING_INPUT_DEPRECATION_MESSAGE,
    LookupTable,
)
from vivarium.engine.manager import Interface
from vivarium.engine.types import (
    DataFrameMapping,
    LookupTableData,
    ScalarValue,
    has_named_row_index,
)

_ScalarOrListData = ScalarValue | list[ScalarValue] | tuple[ScalarValue, ...]


[docs] class LookupTableInterface(Interface): """The interface to the lookup table management system. Simulations tend to require a large quantity of data to run. ``vivarium`` provides the :class:`Lookup Table <vivarium.engine.framework.lookup.table.LookupTable>` abstraction to ensure that accurate data can be retrieved when it's needed. For more information, see :ref:`here <lookup_concept>`. """ def __init__(self, manager: LookupTableManager): self._manager = manager @overload def build_table( self, data: pd.Series[Any], name: str = "", value_columns: None = None, ) -> LookupTable[pd.Series[Any]]: ... @overload def build_table( self, data: pd.DataFrame, name: str = "", value_columns: list[str] | tuple[str, ...] = ..., ) -> LookupTable[pd.DataFrame]: ... @overload def build_table( self, data: pd.DataFrame, name: str = "", value_columns: str = ..., ) -> LookupTable[pd.Series[Any]]: ... @overload def build_table( self, data: pd.DataFrame, name: str = "", value_columns: None = None, ) -> LookupTable[pd.DataFrame]: ... @overload def build_table( self, data: ScalarValue, name: str = "", value_columns: str | None = None, ) -> LookupTable[pd.Series[Any]]: ... @overload def build_table( self, data: list[ScalarValue] | tuple[ScalarValue, ...], name: str = "", value_columns: list[str] | tuple[str, ...] = ..., ) -> LookupTable[pd.DataFrame]: ... @overload def build_table( self, data: DataFrameMapping, name: str = "", value_columns: str | None = None, ) -> LookupTable[pd.Series[Any]]: ... @overload def build_table( self, data: DataFrameMapping, name: str = "", value_columns: list[str] | tuple[str, ...] = ..., ) -> LookupTable[pd.DataFrame]: ... @overload def build_table( self, data: LookupTableData, name: str = "", value_columns: list[str] | tuple[str, ...] | str | None = None, ) -> LookupTable[pd.Series[Any]] | LookupTable[pd.DataFrame]: ...
[docs] def build_table( self, data: LookupTableData, name: str = "", value_columns: list[str] | tuple[str, ...] | str | None = None, ) -> LookupTable[pd.Series[Any]] | LookupTable[pd.DataFrame]: """Construct and register a :class:`LookupTable <vivarium.engine.framework.lookup.table.LookupTable>` from input data. Data can be provided as a :class:`pandas.DataFrame`, a :class:`pandas.Series`, a scalar, or a list/tuple of scalars. The form of the input data determines what form the result of calling the resulting lookup table will take. If a scalar or list/tuple is provided, that result will be broadcast over the calling index. Scalars will return a Series, whereas a list/tuple will return a DataFrame. If a DataFrame or Series is provided, the returned columns will be in exactly the form of the input data. Row-index level names that follow the ``<name>_start`` / ``<name>_end`` convention are treated as continuous binned ranges and interpolated using order 0 (step function) interpolation; other row-index level names are treated as exact-match categorical columns. For indexed :class:`pandas.DataFrame` / :class:`pandas.Series` inputs (lookup attributes on the row index), ``value_columns`` must be ``None`` because value columns are inferred from the DataFrame columns or the Series name. For flat DataFrame inputs (deprecated), ``value_columns`` selects which column(s) are returned. For list/tuple inputs, value columns are required to name the resulting DataFrame columns. For scalar inputs, value columns can be provided to name the resulting Series column; if not provided, the resulting Series is named ``"value"``. .. deprecated:: 4.2.0 Passing a Mapping or a flat :class:`pandas.DataFrame` (one whose row index is the default :class:`pandas.RangeIndex`) is deprecated. Construct your DataFrame (or :class:`pandas.Series`) with parameter/key columns on a named ``Index`` or ``MultiIndex`` and value columns as the DataFrame columns. Scalars and lists/tuples remain fully supported. Parameters ---------- data The source data which will be used to build the resulting :class:`Lookup Table <vivarium.engine.framework.lookup.table.LookupTable>`. name The name of the table. Defaults to ``""``; when empty, the manager assigns a generic ``"lookup_table_<n>"`` name. The stored table is keyed as ``"<component_name>.<name>"`` so an empty ``name`` produces a trailing dot in that key. value_columns Names of the value column(s) of the resulting lookup table. Should only be provided for scalar or list/tuple input data. Returns ------- LookupTable Raises ------ ValueError If ``value_columns`` is provided alongside an indexed ``pandas.DataFrame`` or ``pandas.Series``. """ if isinstance(data, pd.DataFrame) and not has_named_row_index(data): warnings.warn( FLAT_DATAFRAME_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2, ) if isinstance(data, Mapping): warnings.warn( MAPPING_INPUT_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=2, ) return self._manager.build_table(data, name, value_columns)