Skip to content

Context Enricher Demo¤

Demonstrates context enrichment: value mapping for categorical codes to human-readable labels.

Run it: python examples/context_enricher_demo.py

Modules demonstrated: ContextEnricher, ValueMapping

Related guides: Data Acquisition


"""Context Enricher Demo

Demonstrates how to enrich timeseries data with contextual metadata:
descriptions, units, tolerance limits, and value mappings.

Run: python examples/context_enricher_demo.py
"""

import pandas as pd
import numpy as np

from ts_shape.loader.context.context_enricher import ContextEnricher


def create_sample_data():
    """Create sample timeseries, metadata, tolerances, and mappings."""
    np.random.seed(42)
    base = pd.Timestamp("2024-01-01")

    # Timeseries data
    timeseries = pd.DataFrame({
        "systime": (
            [base + pd.Timedelta(minutes=i) for i in range(20)] +
            [base + pd.Timedelta(minutes=i) for i in range(20)] +
            [base + pd.Timedelta(minutes=i) for i in range(20)]
        ),
        "uuid": (
            ["temp:zone_a"] * 20 +
            ["press:zone_a"] * 20 +
            ["state:machine1"] * 20
        ),
        "value_double": (
            list(np.random.normal(85, 3, 20)) +
            list(np.random.normal(2.1, 0.2, 20)) +
            [None] * 20
        ),
        "value_string": (
            [None] * 40 +
            list(np.random.choice(["0", "1", "2"], 20))
        ),
        "is_delta": [True] * 60,
    })

    # Metadata
    metadata = pd.DataFrame({
        "uuid": ["temp:zone_a", "press:zone_a", "state:machine1"],
        "description": ["Zone A Temperature", "Zone A Pressure", "Machine 1 State"],
        "unit": ["°C", "bar", "code"],
        "area": ["production_hall", "production_hall", "assembly"],
    })

    # Tolerances
    tolerances = pd.DataFrame({
        "uuid": ["temp:zone_a", "press:zone_a"],
        "low_limit": [75.0, 1.5],
        "high_limit": [95.0, 3.0],
    })

    # Value mappings
    mappings = pd.DataFrame({
        "uuid": ["state:machine1"] * 3,
        "raw_value": ["0", "1", "2"],
        "mapped_value": ["idle", "running", "error"],
    })

    return timeseries, metadata, tolerances, mappings


if __name__ == "__main__":
    print("=" * 70)
    print("CONTEXT ENRICHER DEMO")
    print("=" * 70)

    ts, meta, tol, maps = create_sample_data()
    print(f"\nTimeseries: {len(ts)} rows, {ts['uuid'].nunique()} signals")
    print(f"Metadata: {len(meta)} signal descriptions")
    print(f"Tolerances: {len(tol)} tolerance entries")
    print(f"Mappings: {len(maps)} value mappings")

    # -----------------------------------------------------------------------
    # 1. Enrich with metadata
    # -----------------------------------------------------------------------
    print("\n" + "-" * 70)
    print("1. ENRICH WITH METADATA")
    print("-" * 70)

    enricher = ContextEnricher(ts)
    enriched = enricher.enrich_with_metadata(meta)
    print(f"\nColumns after metadata enrichment: {list(enriched.columns)}")
    print(f"\nSample (temp:zone_a with metadata):")
    print(enriched[enriched["uuid"] == "temp:zone_a"][
        ["systime", "uuid", "value_double", "description", "unit", "area"]
    ].head())

    # -----------------------------------------------------------------------
    # 2. Enrich with tolerances
    # -----------------------------------------------------------------------
    print("\n" + "-" * 70)
    print("2. ENRICH WITH TOLERANCES")
    print("-" * 70)

    enricher2 = ContextEnricher(ts)
    with_tol = enricher2.enrich_with_tolerances(tol)
    print(f"\nColumns after tolerance enrichment: {list(with_tol.columns)}")
    temp_with_tol = with_tol[with_tol["uuid"] == "temp:zone_a"][
        ["systime", "uuid", "value_double", "low_limit", "high_limit"]
    ]
    print(f"\nTemperature with tolerance limits:")
    print(temp_with_tol.head())

    # Check which values are outside tolerance
    out_of_tol = temp_with_tol[
        (temp_with_tol["value_double"] < temp_with_tol["low_limit"]) |
        (temp_with_tol["value_double"] > temp_with_tol["high_limit"])
    ]
    print(f"\nOut-of-tolerance readings: {len(out_of_tol)} of {len(temp_with_tol)}")

    # -----------------------------------------------------------------------
    # 3. Enrich with value mappings
    # -----------------------------------------------------------------------
    print("\n" + "-" * 70)
    print("3. ENRICH WITH VALUE MAPPINGS")
    print("-" * 70)

    enricher3 = ContextEnricher(ts)
    with_maps = enricher3.enrich_with_mapping(maps)
    state_rows = with_maps[with_maps["uuid"] == "state:machine1"][
        ["systime", "uuid", "value_string", "mapped_value"]
    ]
    print(f"\nMachine state with mapped values:")
    print(state_rows.head(10))

    print("\n" + "=" * 70)
    print("Demo complete.")
    print("=" * 70)