Base

class emflow.assets.base.Asset(*, id: ~uuid.UUID = <factory>, name: str | None = None, timeseries: list[~timedatamodel.timeseries.TimeSeries] = <factory>, geometry: ~shapely.geometry.base.BaseGeometry | None = None, extra: dict = <factory>, lat: dataclasses.InitVar[float | None] = None, lon: dataclasses.InitVar[float | None] = None, commissioning_date: ~datetime.date | None = None)[source]

Bases: Element

Marker mixin for physical energy equipment.

Carries fields genuinely shared across every piece of equipment β€” independent of whether the equipment is shaped like a graph vertex (WindTurbine) or a graph edge (Line).

commissioning_date: date | None = None
add_child(obj) None

Attach a child. Override in subclasses that support children.

property centroid: Point | None

Centroid of geometry, or None if no geometry.

children() list

Child elements for tree walking. Override in subclasses with children.

classmethod from_json(data: dict) Element

Deserialize from a JSON-compatible dict.

geometry: BaseGeometry | None = None
geometry_to_geojson(geometry)
index()

Build a dict[UUID, Element] index of the subtree rooted at self.

Use to resolve Reference objects against this tree.

lat: InitVar[float | None] = None
property latitude: float | None

Latitude, if geometry is a shapely Point; else None.

lon: InitVar[float | None] = None
property longitude: float | None

Longitude, if geometry is a shapely Point; else None.

name: str | None = None
to_dataframe()
to_geojson(exclude_none: bool = True)
to_json(*, exclude_fields: set | None = None) dict

Serialize to a JSON-compatible dict.

to_properties() dict

Domain-specific fields as a dict (excludes infra + children fields).

to_tree() str

Return the hierarchy rendered as an indented tree string.

Use print(element.to_tree()) to display it. In a notebook, printing the element directly (element) also renders the tree via __repr__.

id: UUID
timeseries: list[TimeSeries]
extra: dict
class emflow.assets.base.TimeSeries(df: DataFrame | None = None, *, name: str, description: str | None = None, unit: str = 'dimensionless', timezone: str = 'UTC', frequency: Frequency | None = None, data_type: DataType | None = None, timeseries_type: TimeSeriesType = TimeSeriesType.FLAT)[source]

Bases: _TimeSeriesReprMixin

Polars-backed container for time series data with rich metadata.

The underlying df is optional. Construct with df=None to declare a series structure (name, unit, data type, …) before any data exists β€” useful for registering series in a catalog. Methods that need data (converters, head/tail, convert_unit, …) raise ValueError when no df is attached. Use has_df to check.

Parameters

df:

A polars.DataFrame whose columns conform to one of the recognised DataShape patterns, or None for a metadata-only instance. All timestamp columns must use pl.Datetime("us", time_zone="UTC").

name:

Series name (e.g. "wind_power", "electricity.supply").

description:

Human-readable description.

unit:

Canonical physical unit string (e.g. "MW", "dimensionless").

timezone:

IANA timezone string for display purposes. Internal data is always UTC; this is a metadata hint only.

frequency:

Pandas offset alias describing the expected data cadence.

data_type:

Semantic nature of the observations (DataType).

timeseries_type:

Storage/versioning model (TimeSeriesType).

property shape: DataShape | None

Which temporal columns are present (inferred from the DataFrame).

None for metadata-only instances.

property num_rows: int

Number of data rows. 0 for metadata-only instances.

property columns: list[str]

Column names present in the underlying Polars DataFrame.

Empty list for metadata-only instances.

property df: DataFrame | None

The underlying polars.DataFrame (read-only by convention).

None for metadata-only instances.

property has_df: bool

True when a DataFrame is attached.

property has_missing: bool

True if the value column contains any null values.

False for metadata-only instances.

classmethod from_polars(df: DataFrame, *, name: str, description: str | None = None, unit: str = 'dimensionless', timezone: str = 'UTC', frequency: Frequency | None = None, data_type: DataType | None = None, timeseries_type: TimeSeriesType = TimeSeriesType.FLAT) TimeSeries[source]

Create a TimeSeries directly from a polars.DataFrame.

All timestamp columns must already use pl.Datetime("us", time_zone="UTC").

classmethod from_list(data: dict[str, list], *, name: str, description: str | None = None, unit: str = 'dimensionless', timezone: str = 'UTC', frequency: Frequency | None = None, data_type: DataType | None = None, timeseries_type: TimeSeriesType = TimeSeriesType.FLAT) TimeSeries[source]

Create a TimeSeries from a column-oriented dict of lists.

Accepts the format returned by to_list(). Timestamp columns are normalised to UTC automatically.

classmethod from_numpy(data: dict[str, np.ndarray], *, name: str, description: str | None = None, unit: str = 'dimensionless', timezone: str = 'UTC', frequency: Frequency | None = None, data_type: DataType | None = None, timeseries_type: TimeSeriesType = TimeSeriesType.FLAT) TimeSeries[source]

Create a TimeSeries from a column-oriented dict of NumPy arrays.

Accepts the format returned by to_numpy(). Timestamp columns (numpy.datetime64, always timezone-naive) are localised to UTC.

Requires numpy.

classmethod from_pyarrow(table: pa.Table, *, name: str, description: str | None = None, unit: str = 'dimensionless', timezone: str = 'UTC', frequency: Frequency | None = None, data_type: DataType | None = None, timeseries_type: TimeSeriesType = TimeSeriesType.FLAT) TimeSeries[source]

Create a TimeSeries from a PyArrow Table.

Accepts the format returned by to_pyarrow(). Arrow timestamp[us, UTC] columns are converted automatically.

Requires pyarrow.

classmethod from_pandas(df: DataFrame, *, name: str, description: str | None = None, unit: str = 'dimensionless', timezone: str = 'UTC', frequency: Frequency | None = None, data_type: DataType | None = None, timeseries_type: TimeSeriesType = TimeSeriesType.FLAT) TimeSeries[source]

Create a TimeSeries from a pandas.DataFrame.

Only SIMPLE and VERSIONED shapes can be constructed via from_pandas. AUDIT and CORRECTED shapes (which require a change_time column) are read-only results from the database layer.

The data shape is inferred from the column names (and MultiIndex levels if the DataFrame uses an index).

Raises

ValueError

If the DataFrame contains a change_time column.

validate_for_insert() tuple[DataFrame, DataShape][source]

Validate that this TimeSeries can be inserted and return the underlying DataFrame with its shape.

Only DataShape.SIMPLE and DataShape.VERSIONED are supported for insert.

Returns

Tuple[pl.DataFrame, DataShape]

Raises

ValueError

If shape is DataShape.AUDIT or DataShape.CORRECTED.

to_pandas() DataFrame[source]

Convert to a pandas.DataFrame.

Restores the conventional index:

  • SIMPLE β€” valid_time as index.

  • VERSIONED β€” (knowledge_time, valid_time) MultiIndex.

  • AUDIT β€” (knowledge_time, change_time, valid_time) MultiIndex.

  • CORRECTED β€” (valid_time, change_time) MultiIndex.

to_polars() DataFrame[source]

Return the underlying polars.DataFrame.

to_list() dict[source]

Return the series as a column-oriented dict of lists.

Each key is a column name; each value is a Python list of that column’s values. Timestamps are Python datetime objects; null values are None.

Example:

{"valid_time": [datetime(...), ...], "value": [1.0, None, 3.0, ...]}
to_numpy() dict[str, np.ndarray][source]

Return the series as a dictionary of NumPy arrays.

Each column maps to a 1-D numpy.ndarray. Timestamp columns become numpy.datetime64[us] values; null values become NaN or NaT.

Requires numpy. Install with: pip install numpy.

to_pyarrow() pa.Table[source]

Return the series as a pyarrow.Table.

All timestamp columns are Arrow timestamp[us, UTC].

Requires pyarrow. Install with: pip install pyarrow.

coverage_bar() CoverageBar[source]

Return a CoverageBar showing value coverage.

True = value present, False = null/missing. In Jupyter the coverage bar renders as an SVG.

head(n: int = 5) TimeSeries[source]

Return the first n rows as a new TimeSeries.

tail(n: int = 5) TimeSeries[source]

Return the last n rows as a new TimeSeries.

convert_unit(target_unit: str) TimeSeries[source]

Return a new TimeSeries with values converted to target_unit.

Uses the pint library for unit conversion. The unit metadata field is updated to target_unit.

Parameters

target_unit:

Target unit string understood by pint (e.g. "km/h", "kW").

Raises

ImportError

If pint is not installed.

pint.DimensionalityError

If the current unit and target_unit are dimensionally incompatible.

metadata_dict() dict[source]

Return all metadata fields as a plain dict.

class emflow.assets.base.Sensor(*, id: ~uuid.UUID = <factory>, name: str | None = None, timeseries: list[~timedatamodel.timeseries.TimeSeries] = <factory>, geometry: ~shapely.geometry.base.BaseGeometry | None = None, extra: dict = <factory>, lat: dataclasses.InitVar[float | None] = None, lon: dataclasses.InitVar[float | None] = None, commissioning_date: ~datetime.date | None = None, members: list[~energydatamodel.element.Element] = <factory>, tz: ~datetime.tzinfo | None = None, height: float | None = None)[source]

Bases: NodeAsset

A measurement instrument that observes an environmental variable.

Concrete sensor subclasses (TemperatureSensor, WindSpeedSensor, …) inherit height from here and add no new fields.

height: float | None = None
add_child(obj: Element) None

Attach a child. Override in subclasses that support children.

property centroid: Point | None

Centroid of geometry, or None if no geometry.

children() list

Child elements for tree walking. Override in subclasses with children.

commissioning_date: date | None = None
classmethod from_json(data: dict) Element

Deserialize from a JSON-compatible dict.

geometry: BaseGeometry | None = None
geometry_to_geojson(geometry)
index()

Build a dict[UUID, Element] index of the subtree rooted at self.

Use to resolve Reference objects against this tree.

lat: InitVar[float | None] = None
property latitude: float | None

Latitude, if geometry is a shapely Point; else None.

lon: InitVar[float | None] = None
property longitude: float | None

Longitude, if geometry is a shapely Point; else None.

name: str | None = None
to_dataframe()
to_geojson(exclude_none: bool = True)
to_json(*, exclude_fields: set | None = None) dict

Serialize to a JSON-compatible dict.

to_properties() dict

Domain-specific fields as a dict (excludes infra + children fields).

to_tree() str

Return the hierarchy rendered as an indented tree string.

Use print(element.to_tree()) to display it. In a notebook, printing the element directly (element) also renders the tree via __repr__.

tz: datetime.tzinfo | None = None
members: list[Element]
id: UUID
timeseries: list[TimeSeries]
extra: dict
class emflow.assets.base.Collection(*, id: ~uuid.UUID = <factory>, name: str | None = None, timeseries: list[~timedatamodel.timeseries.TimeSeries] = <factory>, geometry: ~shapely.geometry.base.BaseGeometry | None = None, extra: dict = <factory>, lat: dataclasses.InitVar[float | None] = None, lon: dataclasses.InitVar[float | None] = None, members: list[~energydatamodel.element.Element] = <factory>, tz: ~datetime.tzinfo | None = None)[source]

Bases: Element

An Element whose primary purpose is grouping other Elements.

Not a Node β€” collections are organizational groupings, not graph vertices. Carries members and tz (same shape as Node, different semantics).

members: list[Element]
tz: tzinfo | None = None
children() list[source]

Child elements for tree walking. Override in subclasses with children.

add_child(obj: Element) None[source]

Attach a child. Override in subclasses that support children.

property centroid: Point | None

Centroid of geometry, or None if no geometry.

classmethod from_json(data: dict) Element

Deserialize from a JSON-compatible dict.

geometry: BaseGeometry | None = None
geometry_to_geojson(geometry)
index()

Build a dict[UUID, Element] index of the subtree rooted at self.

Use to resolve Reference objects against this tree.

lat: InitVar[float | None] = None
property latitude: float | None

Latitude, if geometry is a shapely Point; else None.

lon: InitVar[float | None] = None
property longitude: float | None

Longitude, if geometry is a shapely Point; else None.

name: str | None = None
to_dataframe()
to_geojson(exclude_none: bool = True)
to_json(*, exclude_fields: set | None = None) dict

Serialize to a JSON-compatible dict.

to_properties() dict

Domain-specific fields as a dict (excludes infra + children fields).

to_tree() str

Return the hierarchy rendered as an indented tree string.

Use print(element.to_tree()) to display it. In a notebook, printing the element directly (element) also renders the tree via __repr__.

id: UUID
timeseries: list[TimeSeries]
extra: dict