Skip to content

Patient Timelines

OMOP Alchemy includes a lightweight timeline layer that projects OMOP CDM ORM objects into a unified, time-ordered event stream per patient.

It is primarily intended for feature construction and exploratory analysis — not for production query pipelines where raw SQLAlchemy queries are more appropriate.


Core concepts

EventTime

A canonical temporal representation. Every clinical event has a start datetime; an end datetime is optional. The kind property returns "point" or "interval".

Canonical temporal representation for an event.


EventValue

The value associated with a clinical event — numeric, concept, string, or none.


EventMapping

Declares which ORM fields supply the concept, start/end datetimes, and value for a particular CDM table. Subclasses of ClinicalEvent set _mapping to an EventMapping instance at class level.


The ClinicalEvent mixin

ClinicalEvent is a mixin that adds timeline behaviour to any CDM ORM class. It reads _mapping to implement event_time, event_value, event_metadata, to_dict, and to_json.


Concrete event classes

Three CDM tables are pre-wired with EventMappings:

Class CDM table Concept field Value fields
Condition_Event condition_occurrence condition_concept_id
Measurement_Event measurement measurement_concept_id value_as_number, value_as_concept_id, value_as_string
Drug_Exposure_Event drug_exposure drug_concept_id quantity

Bases: Condition_Occurrence, ClinicalEvent

Bases: ClinicalEvent, Measurement

Bases: Drug_Exposure, ClinicalEvent


Person_Timeline

Extends the Person ORM class with .events and .timeline properties. Requires an active SQLAlchemy session (i.e. the object must have been loaded from a session, not constructed in memory).

Bases: Person


Usage example

from sqlalchemy.orm import Session
from omop_alchemy.cdm.handlers.timeline import Person_Timeline

with Session(engine) as session:
    person = session.get(Person_Timeline, 42)
    for event in person.timeline:   # sorted by event_time.start
        print(event)
        print(event.to_dict())

Extending to new tables

To add a new CDM table to the timeline, subclass both ClinicalEvent and the target ORM class and set _mapping:

from omop_alchemy.cdm.handlers.timeline.event_timeline import ClinicalEvent, EventMapping
from omop_alchemy.cdm.model.clinical import Procedure_Occurrence

class Procedure_Event(Procedure_Occurrence, ClinicalEvent):
    _mapping = EventMapping(
        concept_field="procedure_concept_id",
        start_date_field="procedure_date",
        start_datetime_field="procedure_datetime",
    )