Skip to content

Instantly share code, notes, and snippets.

@minrk
Created October 31, 2025 22:05
Show Gist options
  • Save minrk/879d0b762db8aef120ddebb30464a144 to your computer and use it in GitHub Desktop.
Save minrk/879d0b762db8aef120ddebb30464a144 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "23f36510-9eca-4004-a553-363ac29108e2",
"metadata": {},
"outputs": [],
"source": [
"patient_id = 40079\n",
"study_id = 30017"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ce72d503-b209-419e-a94c-61b199becd36",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'uuid': '0a5a5276-039d-4400-bd63-2f8413964032',\n",
" 'schema_id': {'namespace': 'omh', 'name': 'blood-glucose', 'version': '4.0'},\n",
" 'source_creation_date_time': '2025-10-29T20:16:53Z',\n",
" 'modality': 'sensed',\n",
" 'acquisition_rate': {'number_of_times': 1,\n",
" 'time_window': {'value': 5, 'unit': 'min'}},\n",
" 'external_datasheets': [{'datasheet_type': 'data source',\n",
" 'datasheet_reference': 'https://www.libreview.com/'},\n",
" {'datasheet_type': 'measuring device',\n",
" 'datasheet_reference': 'https://www.freestyle.abbott/us-en/products/freestyle-libre-3.html'}]}"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import json\n",
"\n",
"with open(\"blood_glucose.json\") as f:\n",
" cgm_records = json.load(f)\n",
"cgm_records[\"header\"]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "311b7613-0511-40ef-bc5e-de9baddb888a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'uuid': 'b27411f4-358b-44ed-8f0c-1b40a3120858',\n",
" 'schema_id': {'namespace': 'ieee', 'name': 'food-entry', 'version': '0.1'},\n",
" 'source_creation_date_time': '2025-10-29T20:16:53Z',\n",
" 'modality': 'self-reported',\n",
" 'external_datasheets': [{'datasheet_type': 'recording app',\n",
" 'datasheet_reference': 'https://cronometer.com/index.html'}]}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"with open(\"food_entry.json\") as f:\n",
" food_entry = json.load(f)\n",
"food_entry['header']"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "d9b94b69-03da-4cf9-8512-1500c72966a9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'uuid': '1c4e7a5d-2c1e-4fae-a7fc-b497c7595e94',\n",
" 'schema_id': {'namespace': 'ieee',\n",
" 'name': 'sleep-stage-summary',\n",
" 'version': '1.0'},\n",
" 'source_creation_date_time': '2025-10-29T20:16:53Z',\n",
" 'modality': 'sensed',\n",
" 'external_datasheets': [{'datasheet_type': 'data aggregator',\n",
" 'datasheet_reference': 'https://www.fitabase.com/media/2126/fitabase-fitbit-data-dictionary-as-of-05162025.pdf'},\n",
" {'datasheet_type': 'measuring device',\n",
" 'datasheet_reference': 'https://store.google.com/us/product/fitbit_sense_2?hl=en-US&pli=1'},\n",
" {'datasheet_type': 'processing algorithm', 'datasheet_reference': ''},\n",
" {'datasheet_type': 'manufacturer',\n",
" 'datasheet_reference': 'https://store.google.com/category/watches_trackers?hl=en-US'}]}"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"with open(\"sleep_stage_summary.json\") as f:\n",
" sleep_stage = json.load(f)\n",
"sleep_stage['header']"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "772c9874-b7a5-4aae-96be-ecede9ecfbd5",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'74bb39f0-5fa3-58c0-b88f-f96d03bf7513'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import uuid\n",
"from datetime import UTC, datetime\n",
"\n",
"epoch = datetime(1900, 1, 1, tzinfo=UTC)\n",
"ns_uuid = uuid.UUID('d15785047be14c68b5a21c30e8e15c91')\n",
"ns_uuid\n",
"def uuid_for_reading(reading):\n",
" # dt = datetime.fromisoformat(reading['effective_time_frame']['date_time'])\n",
" # clock_seq = int((dt - epoch).total_seconds())\n",
" return str(uuid.uuid5(ns_uuid, json.dumps(reading)))\n",
"\n",
"uuid_for_reading(cgm_records[\"body\"][2])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "72839c14-4d70-4444-a03a-6d34a5645d5b",
"metadata": {},
"outputs": [],
"source": [
"from jupyterhealth_client import JupyterHealthClient\n",
"\n",
"jhc = JupyterHealthClient()"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "249283f2-b7a9-4c6b-b95b-48dcafdf1162",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'studyScopeConsents': [{'id': 94,\n",
" 'studyPatient': {'id': 78, 'study': 30017, 'patient': 40079},\n",
" 'scopeCode': {'id': 50001,\n",
" 'codingSystem': 'https://w3id.org/openmhealth',\n",
" 'codingCode': 'omh:blood-glucose:4.0',\n",
" 'text': 'Blood glucose'},\n",
" 'consented': True,\n",
" 'consentedTime': '2025-10-31T04:40:58.012671Z'},\n",
" {'id': 95,\n",
" 'studyPatient': {'id': 78, 'study': 30017, 'patient': 40079},\n",
" 'scopeCode': {'id': 50006,\n",
" 'codingSystem': 'https://w3id.org/openmhealth',\n",
" 'codingCode': 'ieee:sleep-stage-summary:1.0',\n",
" 'text': 'Sleep Stage Summary'},\n",
" 'consented': True,\n",
" 'consentedTime': '2025-10-31T04:40:58.012671Z'},\n",
" {'id': 96,\n",
" 'studyPatient': {'id': 78, 'study': 30017, 'patient': 40079},\n",
" 'scopeCode': {'id': 50007,\n",
" 'codingSystem': 'https://w3id.org/openmhealth',\n",
" 'codingCode': 'ieee:food-entry:0.1',\n",
" 'text': 'Food Entry'},\n",
" 'consented': True,\n",
" 'consentedTime': '2025-10-31T04:40:58.012671Z'}]}"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"jhc._api_request(\n",
" f\"patients/{patient_id}/consents\",\n",
" method=\"POST\",\n",
" json={\n",
" \"studyScopeConsents\": [\n",
" {\n",
" \"studyId\": study_id,\n",
" \"scopeConsents\": [\n",
" {\n",
" \"codingSystem\": \"https://w3id.org/openmhealth\",\n",
" \"codingCode\": \"omh:blood-glucose:4.0\",\n",
" \"consented\": True,\n",
" },\n",
" {\n",
" \"codingSystem\": \"https://w3id.org/openmhealth\",\n",
" \"codingCode\": \"ieee:sleep-stage-summary:1.0\",\n",
" \"consented\": True,\n",
" },\n",
" {\n",
" \"codingSystem\": \"https://w3id.org/openmhealth\",\n",
" \"codingCode\": \"ieee:food-entry:0.1\",\n",
" \"consented\": True,\n",
" },\n",
" ],\n",
" }\n",
" ]\n",
" },\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "c7fc40b9-1b56-4ed1-8872-b14c066461ab",
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"import base64\n",
"import json\n",
"from tqdm.notebook import tqdm\n",
"\n",
"\n",
"def upload_records(header, readings, device_id, patient_id, chunk_size=100):\n",
" schema_id = header['schema_id']\n",
" coding = [\n",
" {\"system\": \"https://w3id.org/openmhealth\",\n",
" \"code\": f\"{schema_id['namespace']}:{schema_id['name']}:{schema_id['version']}\",\n",
" }\n",
" ]\n",
"\n",
" for i in tqdm(range(0, len(readings), chunk_size)):\n",
" readings_chunk = readings[i:i + chunk_size]\n",
" entries = []\n",
" for reading in readings[i:i + chunk_size]:\n",
"\n",
" reading_header = header.copy()\n",
" reading_header['uuid'] = uuid_for_reading(reading)\n",
" # reading_header['source_creation_date_time'] = reading['effective_time_frame']['date_time']\n",
" record = dict(\n",
" header=reading_header,\n",
" body=reading,\n",
" )\n",
" entry = {\n",
" \"resource\": {\n",
" \"resourceType\": \"Observation\",\n",
" \"status\": \"final\",\n",
" \"code\": {\n",
" \"coding\": coding,\n",
" },\n",
" \"subject\": {\"reference\": f\"Patient/{patient_id}\"},\n",
" \"device\": {\"reference\": f\"Device/{device_id}\"},\n",
" \"valueAttachment\": {\n",
" \"contentType\": \"application/json\",\n",
" \"data\": base64.b64encode(json.dumps(record).encode()).decode(),\n",
" },\n",
" },\n",
" \"request\": {\"method\": \"POST\", \"url\": \"Observation\"},\n",
" }\n",
" entries.append(entry)\n",
"\n",
" request_payload = {\n",
" \"resourceType\": \"Bundle\",\n",
" \"type\": \"batch\",\n",
" \"entry\": entries,\n",
" }\n",
"\n",
" r = jhc._api_request(\"\", method=\"POST\", fhir=True, json=request_payload)\n",
" for entry in r['entry']:\n",
" if 'outcome' in entry['response']:\n",
" for issue in entry['response']['outcome']['issue']:\n",
" print(issue['diagnostics'])\n",
" raise ValueError(\"error!\")"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "f42921dc-5b53-406c-a482-066c0de335e5",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "59be4e96e4174f93a6df68462fc9aba7",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/41 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"upload_records(cgm_records[\"header\"], cgm_records[\"body\"], patient_id=patient_id, device_id=70005)"
]
},
{
"cell_type": "code",
"execution_count": 46,
"id": "6b633416-35cf-46a6-9006-3025e90fbb9f",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "456a9849bc274987a497a8860335b73c",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/1 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"upload_records(food_entry['header'], food_entry['body'], patient_id=patient_id, device_id=70003)"
]
},
{
"cell_type": "code",
"execution_count": 47,
"id": "2e682bcf-825f-4b19-a5e8-04e59b3f9208",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "abc6569b3e3d41cf883b3b3136c639b6",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
" 0%| | 0/1 [00:00<?, ?it/s]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"upload_records(sleep_stage['header'], sleep_stage['body'], patient_id=patient_id, device_id=70004)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "6bccdad2-a12f-4b00-aef1-d62438834fcd",
"metadata": {},
"outputs": [],
"source": [
"from jupyterhealth_client import Code, JupyterHealthClient"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "8af976ce-e68a-4b17-a11e-53056d6a1658",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<Code.SLEEP_STAGE_SUMMARY: 'ieee:sleep-stage-summary:1.0'>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Code.SLEEP_STAGE_SUMMARY"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "cbeaa140-47c0-4746-9a54-7065f3b210ef",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4018"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = jhc.list_observations_df(patient_id=patient_id, study_id=study_id, code=Code.BLOOD_GLUCOSE.value, limit=10_000)\n",
"len(df)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "ddd2f1ca-43cf-468f-b764-75d07e4d08a3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"64"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = jhc.list_observations_df(patient_id=patient_id, study_id=study_id, code=Code.FOOD_ENTRY.value)\n",
"len(df)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "40ed59b0-d9a8-4d2d-834d-ca51c95200bc",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"14"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = jhc.list_observations_df(patient_id=patient_id, study_id=study_id, code=Code.SLEEP_STAGE_SUMMARY.value)\n",
"len(df)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "79a77c74-ecdd-4771-8bcb-739ab9e1bcc5",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment