objects
objects ¤
Object detection — turn identifier-bearing timeseries signals into OCEL 2.0 objects, relations, and time-varying attributes.
The event packs answer "what happened?". This module answers "to which things?" — the batches, serials, coils, recipes, tools, materials, drums, bundles, families, customer part-numbers (and any other object out there) that events refer to.
It is deliberately one generic, declarative layer, not another family of
detector classes: you describe which signals carry which object type with an
:class:ObjectSpec (or discover them from metadata), and a run-length kernel
(the same value-change segmentation that powers batch/traceability detection)
extracts every object's presence interval. New object types are added by data /
config, never by code.
Three steps, all feeding the OCEL 2.0 tables on :class:~ts_shape.eventlog.model.EventLog:
- :func:
object_intervals— segment id signals into(oid, type, start, end)presence intervals (an id is present until the next id on the same signal). - :func:
detect_objects— build theobjects/o2o/object_changestables.part_ofis asserted only along a declaredhierarchy(it cannot be inferred from time alone); other overlaps are reported asco_occurs. - :func:
attach_objects— link an existing event log's events to the detected objects by temporal containment, so the output of every event detector gains rich object references with no per-detector changes.
When you already hold the two lists — an event list and an object list (intervals) — the relationship derivation is automated and needs no raw signals:
- :func:
link_events_to_objects— all event-to-object (E2O) relations, by temporal containment and/or directkey_columnsmatching. - :func:
derive_o2o— all object-to-object (O2O) relations (declaredpart_ofhierarchy or symmetricco_occurs). - :func:
relate— assemble both, plus objects andobject_changes, into one validated :class:EventLogready to ingest into an OCEL 2.0 database.
ObjectSpec
dataclass
¤
ObjectSpec(
uuid: str,
object_type: str,
value_column: str = "value_string",
min_duration: str | None = None,
id_template: str = "{value}",
attributes: Mapping[str, str] = dict(),
)
Declares that one signal carries the identity of one object type.
Attributes:
| Name | Type | Description |
|---|---|---|
uuid |
str
|
The signal ( |
object_type |
str
|
OCEL object type, e.g. |
value_column |
str
|
Column carrying the id ( |
min_duration |
str | None
|
Optional minimum presence (e.g. |
id_template |
str
|
How to render the object id from the raw value. Supports
|
attributes |
Mapping[str, str]
|
|
object_intervals ¤
object_intervals(
df: DataFrame,
specs: Sequence[ObjectSpec],
*,
uuid_column: str = "uuid",
time_column: str = "systime"
) -> pd.DataFrame
Extract one presence interval per object instance from id signals.
Returns a tidy frame with columns oid, type, start, end plus
one column per captured attribute. Each id signal is run-length encoded into
contiguous constant-value segments.
detect_objects ¤
detect_objects(
df: DataFrame,
specs: Sequence[ObjectSpec],
*,
uuid_column: str = "uuid",
time_column: str = "systime",
hierarchy: Mapping[str, str] | None = None,
infer_o2o: bool = True,
validate: bool = True
) -> EventLog
Detect object instances and build their OCEL 2.0 tables.
Produces an :class:EventLog with no events — only objects, o2o
(object-to-object relations), and object_changes (presence lifecycle +
captured attributes). Compose it with event-detector logs via
:func:~ts_shape.eventlog.concat.concat.
hierarchy maps a child object type to its parent type
(e.g. {"serial": "batch", "batch": "work_order"}). A compositional
part_of relation is asserted only along these declared edges, when a
child's presence overlaps a parent's — because part_of cannot be inferred
from time alone (a long-running tool temporally contains every batch
without owning it). Without a declared hierarchy, overlapping objects of
different types get the honest, symmetric co_occurs qualifier instead.
Set infer_o2o=False to skip object-to-object relations entirely.
attach_objects ¤
attach_objects(
event_log: EventLog,
df: DataFrame,
specs: Sequence[ObjectSpec],
*,
qualifiers: Mapping[str, str] | None = None,
uuid_column: str = "uuid",
time_column: str = "systime",
hierarchy: Mapping[str, str] | None = None,
infer_o2o: bool = True,
validate: bool = True
) -> EventLog
Link an existing event log to detected objects by temporal containment.
For every event, any object whose presence interval contains the event
timestamp is linked with an event-to-object (E2O) relation. The detected
objects, o2o and object_changes are merged in. This enriches the
output of any event detector — no per-detector changes required. See
:func:detect_objects for hierarchy (declared part_of edges).
This is a convenience over :func:relate: it first segments df into an
object-interval table via :func:object_intervals, then relates the events
to it. When you already hold an interval/object table, call :func:relate
directly and skip the raw signals.
relate ¤
relate(
event_log: EventLog,
intervals: DataFrame,
*,
hierarchy: Mapping[str, str] | None = None,
qualifiers: Mapping[str, str] | None = None,
key_columns: Sequence[str] | None = None,
infer_o2o: bool = True,
validate: bool = True
) -> EventLog
Assemble a full OCEL 2.0 log from an event list and an object list.
This is the automated relationship step: given an existing event_log
(with events) and an intervals table describing objects -- columns
oid, type and, for temporal linking, start / end (plus any
attribute columns) -- it derives all relations and returns a validated
:class:EventLog whose five tables are ready to ingest into an OCEL 2.0
database:
objectsfrom the distinct(oid, type)pairs,relations(E2O) via :func:link_events_to_objects(temporal containment, plus optionalkey_columnsmatching),o2ovia :func:derive_o2o(declaredpart_ofhierarchyor symmetricco_occurs),object_changes(lifecycle + captured attributes).
Unlike :func:attach_objects, no raw signals or :class:ObjectSpec are
needed -- you bring the two lists, ts-shape derives the relationships.
derive_o2o ¤
derive_o2o(
intervals: DataFrame,
*,
hierarchy: Mapping[str, str] | None = None
) -> pd.DataFrame
Derive object-to-object (O2O) relations from an interval table.
Public entry point over the overlap kernel: a declared hierarchy
(child type -> parent type) yields part_of along overlapping presence
intervals; without one, overlapping objects of different types get the
symmetric co_occurs qualifier. Returns the OCEL 2.0 o2o table.
object_specs_from_metadata ¤
object_specs_from_metadata(
metadata: DataFrame,
*,
type_field: str = "object_type",
value_column_field: str = "object_value_column",
uuid_column: str = "uuid"
) -> list[ObjectSpec]
Build :class:ObjectSpec list from per-signal metadata tags.
Scans a metadata table (e.g. MetadataJsonLoader.to_df()) for a column
naming the object type per signal — so new object types are onboarded by
tagging metadata, not by writing code. The uuid may be the index or a
column; the type/value-column fields are matched directly or with a
config_ / config. prefix (mkdocs metadata flattening).
link_events_to_objects ¤
link_events_to_objects(
events: DataFrame,
intervals: DataFrame,
*,
qualifiers: Mapping[str, str] | None = None,
key_columns: Sequence[str] | None = None,
contain: bool = True
) -> pd.DataFrame
Derive all event-to-object (E2O) relations from two lists.
Takes an OCEL events table and an object/interval table (oid,
type and, for temporal linking, start / end) and returns the
OCEL 2.0 relations table -- with no access to the raw signals. Two
complementary strategies are unioned and de-duplicated:
- temporal containment (
contain, default on): link an event to every object whose presence interval[start, end]contains the event timestamp. Requiresstart/endcolumns. - key match (opt-in via
key_columns): link an event to the object whoseoidequals the value in one of the event'skey_columns-- for events that already name their object (e.g. abatchattribute).
qualifiers maps an object type to the relation qualifier to stamp
(e.g. {"batch": "processed_in"}); unmapped types get <NA>.