Observation Effect
The Observation effect provides a unified way to create and update clinical observations within the Canvas platform. Observations can include vitals (blood pressure, temperature, etc.), lab results, and other clinical measurements. The effect supports structured coding using standard terminologies (LOINC, SNOMED), components for multi-part measurements, and value codings for interpretation.
Attributes #
| Name | Type | Description |
|---|---|---|
observation_id | str or UUID or None | Unique identifier of an existing observation. Must be unset when creating; required when updating. |
patient_id | str or None | ID of the patient for this observation. Required when creating. |
is_member_of_id | str or UUID or None | Reference to a parent observation (for grouping related observations). |
category | str or list[str] or None | Category of observation (e.g., “vital-signs”, “laboratory”, “imaging”). Can be a single category or a list of categories. |
units | str or None | Unit of measure for the observation value (e.g., “mmHg”, “mg/dL”). |
value | str or None | The observation value as a string. |
note_id | int or None | ID of the note associated with this observation. |
name | str or None | Human-readable name for the observation. Required when creating. |
effective_datetime | datetime or None | Date and time when the observation was taken. Required when creating. |
codings | list[CodingData] or None | List of standardized codes identifying this observation (e.g., LOINC codes). |
components | list[ObservationComponentData] or None | List of components for multi-part observations (e.g., systolic and diastolic BP). |
value_codings | list[CodingData] or None | List of coded values for interpretation (e.g., “normal”, “abnormal”). |
Helper Classes #
CodingData #
Represents a standardized code from a terminology system (LOINC, SNOMED, etc.).
| Name | Type | Description |
|---|---|---|
code | str | The code value from the terminology system. |
display | str | Human-readable display text for the code. |
system | str | URI identifying the terminology system (e.g., “http://loinc.org”). |
version | str | Version of the terminology system. Defaults to empty string. |
user_selected | bool | Whether this code was explicitly selected by the user. Defaults to False. |
ObservationComponentData #
Represents a component of a multi-part observation (e.g., systolic and diastolic blood pressure).
| Name | Type | Description |
|---|---|---|
value_quantity | str | The numeric value of this component. |
value_quantity_unit | str | Unit of measure for this component value. |
name | str | Name of this component. |
codings | list[CodingData] or None | Standardized codes identifying this component. |
Methods #
The examples below share this setup:
import datetime
from canvas_sdk.effects.observation import Observation, CodingData, ObservationComponentData
from canvas_sdk.v1.data.observation import Observation as ObservationModel
from canvas_sdk.v1.data.patient import Patient
patient = Patient.objects.first()
create() → Effect #
Create a new observation record.
- Effect Type:
CREATE_OBSERVATION - Payload:
{ "data": { patient_id, name, effective_datetime, ... } }
Validation #
observation_idmust not be set (will be generated by the system)patient_idis requirednameis requiredeffective_datetimeis required- If
is_member_of_idis provided, the parent observation must exist
Example: Blood Pressure Observation #
# Create a blood pressure observation with components and codings
bp_observation = Observation(
patient_id=patient.id,
name="Blood Pressure",
category="vital-signs",
value="120/80",
units="mmHg",
effective_datetime=datetime.datetime.now(),
codings=[
CodingData(
code="85354-9",
display="Blood pressure panel with all children optional",
system="http://loinc.org",
version="2.73",
user_selected=True,
)
],
components=[
ObservationComponentData(
value_quantity="120",
value_quantity_unit="mmHg",
name="Systolic Blood Pressure",
codings=[
CodingData(
code="8480-6",
display="Systolic blood pressure",
system="http://loinc.org",
)
],
),
ObservationComponentData(
value_quantity="80",
value_quantity_unit="mmHg",
name="Diastolic Blood Pressure",
codings=[
CodingData(
code="8462-4",
display="Diastolic blood pressure",
system="http://loinc.org",
)
],
),
],
value_codings=[
CodingData(
code="normal",
display="Normal",
system="http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
)
],
)
effect_create = bp_observation.create()
Example: Simple Lab Result #
# Create a simple lab observation
glucose = Observation(
patient_id=patient.id,
name="Glucose",
category="laboratory",
value="95",
units="mg/dL",
effective_datetime=datetime.datetime.now(),
codings=[
CodingData(
code="2339-0",
display="Glucose [Mass/volume] in Blood",
system="http://loinc.org",
)
],
)
effect_create_lab = glucose.create()
Example: Multiple Categories #
# Create an observation that belongs to multiple categories
comprehensive_assessment = Observation(
patient_id=patient.id,
name="Comprehensive Physical Assessment",
category=["vital-signs", "exam"], # Multiple categories
value="Normal",
effective_datetime=datetime.datetime.now(),
codings=[
CodingData(
code="29545-1",
display="Physical examination",
system="http://loinc.org",
)
],
)
effect_create_multi = comprehensive_assessment.create()
update() → Effect #
Update an existing observation.
- Effect Type:
UPDATE_OBSERVATION - Payload:
{ "data": { observation_id, <dirty_fields> } } - Only fields marked dirty (modified on the model) are included in the update.
Validation #
observation_idis required and must reference an existing observation- All other fields are optional; only dirty (modified) fields are updated
- If
is_member_of_idis provided, the parent observation must exist
Example #
# Find an existing observation
existing_obs = ObservationModel.objects.filter(patient_id=patient.id).first()
# Update the blood pressure values
updated_bp = Observation(
observation_id=existing_obs.id,
value="130/85",
units="mmHg",
components=[
ObservationComponentData(
value_quantity="130",
value_quantity_unit="mmHg",
name="Systolic Blood Pressure",
codings=[
CodingData(
code="8480-6",
display="Systolic blood pressure",
system="http://loinc.org",
)
],
),
ObservationComponentData(
value_quantity="85",
value_quantity_unit="mmHg",
name="Diastolic Blood Pressure",
codings=[
CodingData(
code="8462-4",
display="Diastolic blood pressure",
system="http://loinc.org",
)
],
),
],
)
effect_update = updated_bp.update()
enter_in_error() → Effect #
Marks an existing observation as entered in error. Use this when an observation was recorded incorrectly and should be flagged rather than deleted.
- Effect Type:
ENTER_IN_ERROR_OBSERVATION - Payload:
{ "data": { observation_id } } - Only
observation_idis allowed; setting any other field will raise a validation error.
Validation #
observation_idis required and must reference an existing observation- All other fields must not be set (only
observation_idis allowed) - The observation must not already be entered in error
- The observation must not belong to a locked note
Example #
# Find an observation that was recorded incorrectly
erroneous_obs = ObservationModel.objects.filter(patient_id=patient.id).first()
# Mark it as entered in error
error_observation = Observation(observation_id=erroneous_obs.id)
effect_error = error_observation.enter_in_error()