data-browser / filter_engine.py
anapaulagomes's picture
Sync from GitHub via hub-sync
64775ab verified
Raw
History Blame Contribute Delete
34.1 kB
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "marimo>=0.23.8",
# "opensyndrome @ git+https://github.com/OpenSyndrome/open-syndrome-python.git@main",
# "plotly>=6.2.0",
# "polars>=1.38.1",
# ]
# ///
import marimo
__generated_with = "0.21.0"
app = marimo.App(
width="medium",
app_title="Open Syndrome Definition - Data Browser",
)
@app.cell
def _():
import marimo as mo
import json
import polars as pl
import plotly.graph_objects as go
import yaml
from opensyndrome.filter import OSDEngine, load_profile
from opensyndrome.artifacts import get_definition_dir
return (
OSDEngine,
get_definition_dir,
go,
json,
load_profile,
mo,
pl,
yaml,
)
@app.cell
def _(go, pl):
def plot_cases(
_df_filtered, definitions, date_column="date", date_format="%Y-%m-%d %H:%M:%S"
):
_definitions_columns_sum = [
pl.col(definition).sum().alias(definition) for definition in definitions
]
_agg_df = (
_df_filtered.with_columns(
pl.col(date_column)
.str.to_datetime(format=date_format, strict=False)
.cast(pl.Date)
.dt.truncate("1mo")
.alias("_month")
)
.group_by("_month")
.agg(_definitions_columns_sum)
.sort("_month")
)
_fig = go.Figure()
for definition in definitions:
_fig.add_trace(
go.Scatter(
x=_agg_df["_month"].to_list(),
y=_agg_df[definition].to_list(),
mode="lines+markers",
name=definition,
)
)
_fig.update_layout(yaxis=dict(tickformat="d", rangemode="tozero"))
return _fig
return (plot_cases,)
@app.cell
def _(go, pl):
def groupped_bar(_df_filtered, definitions, group_by_column="code", top_n=10):
_agg_df = (
_df_filtered.group_by(group_by_column)
.agg([pl.col(definition).sum() for definition in definitions])
.sort(group_by_column)
)
_agg_df = _agg_df.with_columns(
(sum([pl.col(definition) for definition in definitions])).alias("total")
)
_agg_df = _agg_df.sort("total", descending=True).head(
top_n
) # .sort(group_by_column)
_fig = go.Figure(
data=[
go.Bar(
name=definition,
x=_agg_df[group_by_column].to_list(),
y=_agg_df[definition].to_list(),
)
for definition in definitions
]
)
_fig.update_layout(barmode="group")
return _fig
return (groupped_bar,)
@app.cell
def _(mo):
mo.md(r"""
# Open Syndrome Definition 👩🏽‍🔬
""")
return
@app.cell
def _():
prompt = """
Role: Act as an expert in healthcare data engineering and the Open Syndrome Definition (OSD) framework.
Task: Generate two text files for testing data filtering and syndromic surveillance pipelines.
File 1: Synthetic Dataset (CSV Format)
Create a synthetic dataset of roughly 20 ambulatory care records.
The data must be in [Insert Language, e.g., Brazilian Portuguese, English, German].
Include the following columns: recording_ts (timestamp), icd_code (ICD-10 code), sex (encoded as [Insert Encoding, e.g., M/F/D]), age (integer), and chief_complaint (string of the symptoms).
Ensure the clinical presentation logically matches the ICD-10 code and age.
File 2: OSD Mapping File (YAML Format)
Create a YAML configuration file that maps the CSV columns to Open Syndrome Definition concepts.
Define a profile named ambulatory_care.
Include a value_encodings section that defines the mapping for the sex column.
Under columns, map each CSV column to its respective OSD concept (e.g., demographic_criteria, diagnosis), attribute (e.g., age, sex), and dtype (integer, string).
Please output the exact CSV and YAML code in clearly separated code blocks so I can copy them directly into my environment.
"""
return (prompt,)
@app.cell
def _(mo, prompt):
mo.callout(
mo.md(
f"""
This is a prototype for filtering your CSV data using definitions from the [Open Syndrome Initiative](https://opensyndrome.org/).
You can either provide a sample of your own data, up to 10 MB, or generate a toy dataset using your preferred GenAI tool.
<details>
<summary>Prompt</summary>
```
{prompt}
```
</details>
Next, you will need to create a map of your data and the Open Syndrome Definition concepts you want to filter on. Don't worry! We have an example ready for you.
**Please note that we do not store any data**.
"""
),
kind="neutral",
)
return
@app.cell
def _():
TOY_DATASET_CSV = """recording_ts,icd_code,sex,age,location
2025-04-21 07:27:48,K21,F,5,Frankfurt
2024-04-29 15:47:31,R10,F,51,Bochum
2025-02-13 03:35:35,M54,F,45,Leipzig
2025-05-26 21:38:55,J18,D,17,Frankfurt
2024-05-27 02:19:18,J45,M,79,Hanover
2023-08-05 20:58:57,M54,D,90,Hanover
2024-01-22 12:51:25,I25,M,39,Hamburg
2024-08-05 13:09:02,E11,D,42,Dortmund
2024-07-16 20:38:52,R10,M,45,Düsseldorf
2024-05-14 22:49:06,F32,D,81,Bochum
2025-06-17 15:25:39,J18,D,61,Dortmund
2025-03-05 05:21:49,R10,F,7,Hanover
2025-04-09 23:52:42,R10,M,11,Dresden
2024-02-26 00:27:29,K21,D,100,Bremen
2024-07-09 14:42:37,A90,D,63,Nuremberg
2024-04-08 12:49:23,F32,M,93,Stuttgart
2024-09-30 13:19:42,E11,M,72,Cologne
2025-05-28 00:03:30,J18,M,69,Dortmund
2025-06-09 18:45:01,E11,M,40,Bochum
2023-12-22 02:22:00,R10,F,13,Frankfurt
2024-07-31 10:20:38,R10,F,90,Hamburg
2023-10-21 14:32:57,R10,F,69,Cologne
2024-02-09 08:08:14,I25,D,75,Frankfurt
2023-10-21 23:20:57,N39,M,76,Hanover
2025-02-11 11:30:38,K21,F,73,Cologne
2023-09-17 02:04:21,M54,M,24,Nuremberg
2024-10-27 17:31:57,J45,M,78,Bremen
2025-03-17 08:14:35,M54,F,8,Hamburg
2024-01-16 00:04:32,J45,M,4,Nuremberg
2025-06-11 01:11:54,E11,D,69,Bremen
2024-08-22 02:00:17,K21,D,67,Frankfurt
2025-01-03 03:39:45,R10,M,27,Bochum
2025-03-25 17:50:35,I25,F,74,Frankfurt
2024-10-14 22:34:01,N39,F,84,Bremen
2025-06-05 03:53:29,F32,M,41,Leipzig
2023-10-27 13:51:29,E11,F,75,Bremen
2024-03-02 07:52:08,F32,M,31,Berlin
2023-09-20 03:22:52,M54,M,90,Cologne
2025-01-22 07:20:56,F32,M,42,Düsseldorf
2023-08-31 16:57:27,A90,M,100,Munich
2025-06-02 13:51:33,J18,M,73,Bremen
2025-04-26 00:16:49,R10,D,87,Hamburg
2024-12-17 16:41:01,A90,M,81,Cologne
2024-03-17 21:37:17,I25,D,15,Düsseldorf
2024-07-06 03:40:38,E11,F,14,Berlin
2024-09-12 05:58:57,I25,M,24,Munich
2023-09-21 15:30:20,E11,F,26,Dresden
2024-04-05 05:26:51,A90,D,2,Essen
2024-06-06 15:50:55,K21,D,12,Nuremberg
2024-03-07 00:37:58,M54,M,28,Hamburg
2024-10-21 22:03:27,M54,F,55,Munich
2024-11-13 20:39:23,A90,D,59,Berlin
2025-06-13 14:03:31,I25,M,89,Düsseldorf
2023-12-11 06:02:26,J18,F,45,Bochum
2024-09-06 14:05:13,N39,D,21,Dresden
2024-07-09 22:24:21,J18,M,100,Bremen
2024-06-13 06:42:05,J45,M,43,Essen
2025-05-07 12:50:43,M54,M,76,Bochum
2024-08-13 09:02:07,N39,D,22,Berlin
2024-01-23 18:13:40,N39,D,52,Bochum
2023-08-22 19:16:29,I25,D,39,Bremen
2025-03-21 17:06:19,F32,F,84,Frankfurt
2025-06-17 19:43:32,J45,D,88,Berlin
2024-09-03 14:47:43,N39,D,10,Stuttgart
2025-06-15 21:40:26,A90,D,35,Munich
2023-07-16 08:03:19,J18,F,45,Leipzig
2023-09-15 21:00:45,M54,D,45,Leipzig
2025-01-14 10:34:00,I25,M,91,Frankfurt
2025-04-17 22:44:04,K21,D,53,Nuremberg
2024-05-10 04:54:31,E11,M,76,Cologne
2025-01-07 02:22:57,F32,M,30,Cologne
2025-04-06 02:31:26,N39,F,90,Bochum
2025-03-06 04:39:00,I25,F,4,Düsseldorf
2024-12-05 09:34:39,I25,F,98,Bremen
2024-11-02 02:05:56,A90,M,57,Hamburg
2023-07-06 07:36:10,M54,D,20,Dortmund
2024-10-22 16:53:15,R10,F,71,Leipzig
2024-07-22 19:15:26,A90,M,63,Stuttgart
2025-04-08 14:31:02,M54,F,6,Hanover
2025-05-09 07:35:13,K21,M,70,Bremen
2024-03-20 04:23:17,E11,D,16,Berlin
2024-01-10 21:07:38,K21,D,53,Stuttgart
2025-01-22 15:40:42,A90,M,1,Dresden
2024-03-14 00:32:52,A90,D,67,Leipzig
2025-01-01 23:08:48,E11,M,15,Leipzig
2025-05-11 13:03:32,J18,F,35,Dresden
2023-08-23 08:24:40,J45,M,60,Nuremberg
2023-11-30 20:02:52,K21,D,10,Berlin
2025-06-16 16:46:18,M54,F,14,Nuremberg
2024-09-18 05:27:58,M54,M,83,Essen
2023-12-24 15:09:33,F32,M,19,Frankfurt
2024-01-06 18:25:20,A90,M,5,Cologne
2025-03-20 09:44:10,M54,D,40,Stuttgart
2023-10-24 02:35:13,I25,M,95,Dresden
2025-03-20 06:38:58,I25,D,63,Dresden
2024-08-30 04:21:56,N39,D,55,Stuttgart
2024-06-17 09:03:26,R10,M,26,Düsseldorf
2023-09-14 06:41:16,I25,F,1,Munich
2023-09-05 21:55:04,J45,F,42,Stuttgart
2024-03-10 00:32:57,F32,D,11,Stuttgart
2025-05-15 03:06:30,I25,M,5,Frankfurt
2024-08-02 22:59:56,J45,M,74,Frankfurt
2025-06-28 23:34:55,F32,F,70,Munich
2024-07-19 11:15:57,M54,M,61,Dresden
2023-09-28 03:17:05,J18,M,39,Munich
2024-02-24 13:40:28,R10,D,9,Frankfurt
2024-09-05 14:39:55,K21,F,38,Düsseldorf
2024-02-16 12:37:21,E11,M,71,Bochum
2025-01-04 05:33:30,N39,F,43,Nuremberg
2023-10-10 08:56:22,F32,M,61,Hamburg
2024-09-02 15:20:14,N39,F,4,Frankfurt
2024-03-19 21:13:05,F32,D,87,Bochum
2025-03-29 01:03:42,J45,M,80,Leipzig
2025-06-20 18:16:48,K21,D,11,Hamburg
2024-08-28 01:54:56,E11,M,95,Cologne
2023-12-10 06:15:22,A90,F,1,Hamburg
2025-03-17 08:42:02,K21,D,66,Frankfurt
2024-10-15 22:29:39,N39,F,100,Leipzig
2024-09-02 11:24:27,J18,F,10,Stuttgart
2024-10-03 20:16:30,J18,F,74,Hanover
2024-02-13 20:37:09,J45,F,24,Stuttgart
2024-06-15 01:29:45,E11,M,89,Berlin
2023-09-14 14:26:42,R10,F,96,Bremen
2024-10-10 13:53:30,J18,M,63,Düsseldorf
2025-03-16 04:53:09,M54,M,82,Berlin
2024-04-29 09:22:35,J18,D,18,Hamburg
2024-03-07 16:28:50,J18,F,48,Stuttgart
2024-09-24 13:12:42,R10,M,13,Leipzig
2024-01-09 11:30:13,N39,M,72,Düsseldorf
2024-02-15 22:26:00,K21,D,63,Bremen
2023-11-25 05:51:38,F32,F,63,Bremen
2023-11-29 12:48:33,J18,D,78,Bochum
2025-04-03 11:33:28,J18,M,43,Dresden
2023-11-27 11:11:23,F32,F,4,Essen
2023-07-31 00:56:58,J45,F,77,Hanover
2024-10-23 09:13:08,J45,F,74,Frankfurt
2024-11-26 11:19:02,N39,M,10,Essen
2024-01-23 10:05:53,A90,M,28,Munich
2024-07-09 13:28:50,A90,F,1,Hanover
2023-08-28 02:08:29,N39,F,20,Hanover
2023-09-13 04:44:47,J45,D,58,Stuttgart
2024-12-13 14:37:50,R10,F,67,Essen
2025-02-12 21:03:35,A90,D,11,Bremen
2023-10-14 13:51:31,R10,D,9,Dresden
2025-05-16 10:29:00,K21,M,37,Essen
2023-10-29 14:07:09,I25,F,61,Nuremberg
2025-06-21 15:22:08,K21,D,75,Cologne
2023-08-04 10:37:48,A90,D,0,Dresden
2025-04-19 18:53:45,J45,F,64,Leipzig
2023-09-05 18:14:10,M54,F,8,Dortmund
2025-06-02 01:27:34,M54,F,98,Düsseldorf
2024-12-29 14:37:15,K21,F,7,Munich
2025-06-21 09:48:10,J45,M,36,Dresden
2025-04-09 14:42:22,F32,M,4,Dortmund
2024-08-28 07:48:43,K21,M,62,Bochum
2024-12-17 07:37:57,I25,D,10,Bremen
2024-05-04 08:35:10,J45,F,52,Berlin
2025-04-16 05:14:20,I25,F,49,Dortmund
2025-01-03 05:44:04,A90,M,60,Hanover
2024-08-15 21:03:58,J45,M,4,Leipzig
2024-02-04 12:29:29,I25,M,80,Stuttgart
2024-08-13 17:10:17,E11,D,70,Bremen
2025-03-26 20:09:17,F32,M,49,Hanover
2024-01-04 08:22:10,N39,M,7,Leipzig
2025-04-25 05:51:55,N39,D,80,Bochum
2023-12-19 13:56:31,F32,D,15,Bremen
2025-05-30 15:02:05,I25,F,100,Nuremberg
2024-12-14 04:37:09,J45,F,37,Bochum
2024-10-05 12:59:24,E11,D,100,Cologne
2025-04-06 10:19:19,A90,F,56,Stuttgart
2024-05-26 04:54:54,J18,F,45,Hanover
2024-09-27 16:35:50,E11,M,5,Dortmund
2024-02-04 04:36:02,M54,M,66,Bremen
2024-06-19 09:24:15,I25,D,27,Cologne
2024-07-22 02:03:40,E11,D,99,Essen
2024-11-29 06:09:54,R10,F,64,Frankfurt
2024-11-14 11:04:27,E11,M,54,Bochum
2024-12-30 07:26:56,I25,F,10,Bochum
2025-06-16 15:19:20,E11,F,8,Hamburg
2025-03-12 14:57:02,K21,M,93,Berlin
2024-04-08 00:06:47,N39,F,87,Düsseldorf
2023-09-07 09:50:34,A90,F,41,Dresden
2024-03-13 08:09:08,M54,M,45,Hamburg
2024-10-23 09:24:15,E11,F,88,Berlin
2023-10-03 00:34:27,F32,F,22,Berlin
2024-07-17 06:16:34,J18,F,9,Leipzig
2024-10-03 10:09:53,J45,M,0,Cologne
2024-11-05 21:05:49,E11,D,0,Frankfurt
2024-03-21 20:11:37,F32,D,3,Bochum
2025-04-21 19:41:13,I25,M,18,Munich
2023-11-30 07:13:05,N39,M,61,Stuttgart
2024-01-10 04:48:41,M54,M,3,Cologne
2023-07-18 00:27:26,F32,F,60,Frankfurt
2025-01-23 14:14:47,M54,D,81,Stuttgart
2024-01-31 22:48:46,J45,D,10,Hamburg
2023-10-04 09:50:26,R10,D,39,Munich
2025-01-03 06:39:41,K21,M,16,Hanover
2023-12-23 15:58:53,J18,F,65,Cologne
2024-04-19 10:00:13,J18,M,37,Stuttgart
2025-03-13 14:23:57,K21,D,5,Nuremberg
2023-11-14 20:18:35,J45,D,2,Düsseldorf
2024-03-19 17:13:20,E11,D,9,Munich
2024-05-31 09:57:33,K21,F,70,Düsseldorf
2025-03-30 04:01:18,J45,D,54,Frankfurt
2023-08-22 17:39:02,F32,M,31,Dortmund
2023-09-21 13:45:33,F32,D,67,Berlin
2025-03-04 16:41:10,K21,F,1,Düsseldorf
2023-10-27 02:37:08,F32,F,26,Stuttgart
2025-04-29 18:40:06,M54,F,11,Munich
2024-12-28 07:49:21,E11,F,14,Essen
2023-12-22 08:32:02,I25,D,19,Hanover
2023-08-09 13:31:23,N39,F,23,Hanover
2025-03-31 02:31:32,K21,F,22,Cologne
2024-09-23 03:56:14,N39,F,66,Munich
2024-11-09 00:45:48,F32,F,80,Bremen
2025-06-11 06:13:37,E11,F,96,Cologne
2025-07-01 20:17:31,M54,M,89,Dortmund
2024-08-23 08:28:15,I25,F,0,Cologne
2024-10-15 03:34:14,M54,M,98,Bremen
2024-12-15 01:24:00,M54,D,77,Munich
2023-08-31 21:42:04,K21,D,96,Dortmund
2023-07-26 03:57:48,E11,D,63,Hanover
2023-10-10 02:05:53,J18,D,97,Düsseldorf
2024-11-09 15:33:19,M54,D,2,Hamburg
2023-11-28 20:34:41,M54,D,5,Berlin
2024-10-18 09:15:59,M54,F,67,Bochum
2025-04-10 04:13:34,I25,D,50,Dortmund
2024-09-24 18:50:25,E11,D,32,Stuttgart
2023-10-06 09:35:04,M54,D,25,Leipzig
2024-05-04 06:58:16,E11,M,9,Hanover
2023-09-14 12:34:35,M54,F,68,Stuttgart
2024-04-17 22:12:27,E11,D,31,Bochum
2025-04-13 02:17:09,J45,M,53,Nuremberg
2023-10-03 13:33:21,M54,F,66,Munich
2023-08-02 16:41:45,I25,D,80,Cologne
2024-10-17 17:42:54,R10,M,52,Bremen
2023-07-22 05:37:58,R10,F,94,Hanover
2023-12-03 13:44:14,M54,F,56,Stuttgart
2023-11-26 02:25:33,I25,D,17,Munich
2025-01-13 04:54:06,E11,D,15,Düsseldorf
2023-10-09 15:52:20,K21,D,59,Munich
2024-07-11 15:51:43,R10,D,38,Stuttgart
2023-12-15 23:43:47,N39,D,53,Cologne
2025-01-20 05:27:18,N39,F,88,Essen
2025-03-18 09:17:51,F32,F,83,Berlin
2023-08-21 21:00:14,N39,F,18,Dresden
2025-07-02 04:40:12,N39,M,79,Cologne
2024-12-14 02:14:55,A90,F,60,Düsseldorf
2023-07-23 02:59:49,A90,D,8,Bremen
2024-08-31 03:34:57,E11,D,94,Bochum
2024-05-31 00:24:33,K21,M,46,Berlin
2024-10-29 11:07:16,E11,D,0,Frankfurt
2023-09-22 06:24:01,M54,D,29,Munich
2025-04-14 16:39:14,I25,F,24,Hamburg
2024-01-23 07:33:25,K21,F,91,Stuttgart
2023-08-28 19:16:26,K21,M,42,Düsseldorf
2023-12-23 22:51:18,K21,M,57,Bochum
2023-08-30 07:56:55,J45,D,40,Munich
2024-11-18 21:52:07,J18,M,56,Stuttgart
2024-02-24 06:29:34,K21,F,62,Düsseldorf
2024-04-02 12:15:07,J18,M,56,Cologne
2024-06-08 03:12:28,I25,D,6,Bochum
2023-11-22 11:40:06,K21,M,29,Bremen
2023-08-21 20:12:45,E11,M,46,Berlin
2024-07-30 14:45:50,J45,M,78,Frankfurt
2024-07-02 06:15:23,I25,M,90,Nuremberg
2023-08-05 00:22:17,R10,F,98,Bochum
2024-10-10 17:35:02,F32,F,58,Berlin
2023-09-21 19:36:26,R10,D,83,Essen
2024-12-29 14:37:37,K21,D,58,Dortmund
2024-05-04 08:12:58,M54,D,60,Cologne
2023-12-07 06:33:37,F32,F,5,Berlin
2024-01-23 11:32:04,A90,M,44,Berlin
2024-04-08 22:15:15,M54,D,0,Munich
2025-06-06 21:30:41,E11,F,87,Cologne
2025-01-23 16:16:48,I25,F,71,Bochum
2024-07-04 15:45:49,J18,F,24,Stuttgart
2025-04-16 13:50:20,I25,M,77,Bochum
2025-06-05 06:28:08,E11,F,41,Essen
2025-06-17 20:02:44,N39,F,32,Berlin
2024-09-19 23:33:16,R10,M,24,Stuttgart
2023-11-14 00:36:09,E11,M,67,Stuttgart
2024-12-28 08:18:54,J18,M,32,Bremen
2024-12-08 21:13:41,M54,F,66,Nuremberg
2023-12-10 10:13:25,K21,F,61,Stuttgart
2025-02-20 10:42:32,J18,M,39,Bochum
2023-08-19 12:26:49,R10,M,1,Dortmund
2025-03-08 23:46:07,N39,D,56,Berlin
2024-12-11 15:36:50,K21,F,58,Dortmund
2023-11-05 07:31:18,E11,M,10,Cologne
2025-04-22 02:09:21,E11,M,52,Bochum
2023-11-08 05:20:30,J18,F,78,Hamburg
2024-03-27 07:28:02,K21,D,96,Bochum
2024-08-19 16:24:50,K21,M,23,Cologne
2024-01-16 03:26:59,N39,M,16,Nuremberg
2023-10-04 11:18:17,M54,F,40,Düsseldorf
2024-10-10 23:17:49,E11,D,36,Leipzig
2025-06-20 02:46:58,R10,M,91,Frankfurt
2024-06-12 23:37:49,N39,D,77,Dortmund
2024-12-03 10:05:27,R10,D,33,Frankfurt
2023-11-18 05:10:14,J18,M,15,Leipzig
2023-07-15 16:26:06,E11,M,93,Düsseldorf
2024-07-05 18:02:02,J18,M,36,Bochum
2024-12-15 14:17:29,A90,D,68,Essen
2024-05-18 19:29:22,K21,M,15,Düsseldorf
2025-06-03 13:20:34,M54,M,94,Leipzig
2024-09-19 11:19:46,F32,M,86,Dresden
2025-05-14 21:50:26,R10,D,36,Cologne
2024-08-03 11:17:33,J18,M,66,Frankfurt
2025-06-17 01:56:46,F32,M,47,Bremen
2024-03-03 08:04:24,N39,F,74,Munich
2024-11-20 11:17:46,J45,M,70,Essen
2024-04-07 20:05:20,F32,F,74,Bremen
2024-05-02 07:06:56,A90,M,50,Munich
2025-04-16 01:26:06,J45,D,9,Munich
2024-11-27 05:09:13,J18,F,72,Hanover
2024-01-16 08:01:23,J18,M,93,Munich
2023-11-01 14:07:13,J18,F,45,Leipzig
2024-09-12 20:38:40,I25,M,80,Dortmund
2024-12-23 00:10:07,E11,D,3,Essen
2023-07-15 02:07:44,I25,F,62,Dortmund
2024-06-25 03:11:03,M54,M,28,Essen
2025-01-31 10:14:51,J45,D,63,Hanover
2023-09-04 20:20:29,N39,D,40,Dresden
2024-03-22 08:14:15,E11,F,17,Leipzig
2025-01-29 10:33:29,K21,D,24,Nuremberg
2023-08-09 22:08:36,F32,F,49,Berlin
2024-08-31 05:09:00,J18,M,40,Dresden
2024-02-08 14:20:27,J18,F,56,Bremen
2023-10-18 03:51:15,J18,F,44,Bremen
2024-01-07 22:39:15,J45,F,2,Stuttgart
2025-02-16 10:06:55,I25,D,7,Dresden
2024-07-13 16:12:25,J45,F,2,Dortmund
2024-04-04 00:15:34,A90,M,30,Berlin
2024-10-21 08:03:07,A90,M,83,Stuttgart
2024-02-14 00:43:56,E11,M,44,Bremen
2024-12-09 11:26:58,K21,M,27,Dortmund
2024-04-09 10:17:41,K21,M,45,Frankfurt
2024-10-05 21:52:21,J45,D,42,Dresden
2025-05-28 05:19:54,K21,F,1,Düsseldorf
2024-11-08 16:12:55,M54,D,68,Hanover
2025-04-28 13:48:25,N39,M,72,Bochum
2024-10-29 20:00:38,E11,F,49,Munich
2023-10-16 05:22:31,A90,D,17,Leipzig
2025-01-11 06:24:38,R10,D,89,Munich
2024-03-02 10:39:55,E11,F,30,Nuremberg
2024-05-01 19:27:52,J45,M,2,Hanover
2025-02-05 19:05:14,J45,D,100,Nuremberg
2024-05-22 07:36:37,R10,M,91,Hamburg
2025-04-09 06:10:00,K21,D,13,Leipzig
2024-11-21 22:42:11,N39,D,19,Leipzig
2023-09-06 03:05:13,I25,M,32,Stuttgart
2023-07-06 14:42:45,K21,M,80,Bochum
2024-10-09 06:00:59,A90,F,11,Stuttgart
2023-12-01 19:12:31,M54,D,19,Dortmund
2024-12-29 00:49:27,J18,D,45,Munich
2024-03-21 03:59:54,K21,F,34,Hanover
2023-11-06 18:24:09,N39,F,1,Frankfurt
2024-01-07 09:20:10,R10,F,70,Dortmund
2023-12-25 17:08:38,A90,D,73,Essen
2024-11-11 12:17:06,M54,D,4,Dortmund
2024-06-17 12:08:49,K21,D,15,Düsseldorf
2024-04-24 12:48:38,F32,F,6,Berlin
2025-01-07 04:10:56,M54,D,4,Frankfurt
2025-05-15 09:22:26,I25,D,99,Bochum
2024-12-09 18:22:45,M54,D,97,Cologne
2024-09-18 17:24:33,R10,D,43,Düsseldorf
2025-05-14 16:51:45,M54,M,14,Leipzig
2024-05-22 07:23:39,F32,M,75,Bremen
2023-07-29 22:20:58,R10,D,45,Munich
2024-05-12 21:06:03,J45,F,95,Nuremberg
2025-05-12 11:44:41,A90,D,6,Leipzig
2024-12-31 13:21:05,J45,F,46,Frankfurt
2024-09-18 04:45:01,M54,F,63,Hanover
2024-05-25 06:36:25,K21,D,55,Munich
2025-02-24 04:53:03,A90,M,72,Berlin
2024-11-30 18:31:30,N39,M,43,Bochum
2025-01-06 03:07:46,A90,D,61,Bochum
2023-08-10 18:20:08,M54,D,78,Cologne
2023-11-11 02:42:16,E11,D,54,Frankfurt
2024-06-15 08:15:56,J45,D,21,Hamburg
2023-08-24 01:13:34,J45,D,14,Essen
2024-01-22 18:38:21,R10,D,49,Hanover
2024-12-31 07:30:30,K21,F,39,Frankfurt
2023-11-04 21:47:23,A90,F,99,Nuremberg
2024-06-16 03:08:25,M54,F,68,Essen
2024-08-18 04:58:30,R10,F,43,Cologne
2025-05-22 18:52:44,K21,M,0,Hanover
2024-07-17 21:35:17,R10,M,100,Bremen
2025-06-09 17:23:20,I25,F,46,Dortmund
2024-09-13 11:38:43,A90,D,52,Bremen
2024-10-16 13:15:13,I25,M,2,Stuttgart
2025-02-11 05:33:21,R10,M,87,Cologne
2023-07-05 11:35:18,F32,D,89,Dortmund
2025-05-21 22:55:34,A90,D,94,Cologne
2023-08-04 15:38:15,I25,M,35,Munich
2024-07-23 13:59:18,K21,M,73,Dortmund
2024-03-14 14:20:02,J18,D,91,Dortmund
2024-03-03 19:29:11,R10,D,12,Cologne
2025-04-16 02:50:44,J45,F,8,Bochum
2024-07-02 01:48:04,K21,D,50,Frankfurt
2023-08-13 03:42:03,M54,F,96,Hanover
2025-03-24 20:00:25,F32,D,41,Hamburg
2025-04-04 10:54:36,M54,M,63,Berlin
2025-05-15 01:47:08,M54,M,97,Düsseldorf
2025-03-27 10:48:40,K21,F,99,Bremen
2024-05-22 21:01:17,K21,D,4,Leipzig
2023-11-28 10:53:50,N39,F,72,Munich
2024-09-03 12:14:13,I25,D,35,Stuttgart
2024-11-08 03:55:44,A90,F,60,Bochum
2023-09-08 06:14:15,R10,M,5,Hamburg
2025-04-15 21:28:07,I25,F,46,Berlin
2025-01-18 23:36:45,E11,M,91,Hamburg
2023-10-14 19:24:03,R10,F,5,Stuttgart
2023-07-16 20:52:22,A90,F,50,Bochum
2024-05-12 12:42:27,J45,D,35,Düsseldorf
2024-12-13 10:44:08,J45,D,18,Düsseldorf
2024-05-24 16:47:06,M54,D,7,Munich
2024-03-07 00:16:05,J45,M,61,Dresden
2023-07-08 01:32:44,A90,D,66,Berlin
2023-12-18 06:41:14,R10,D,95,Dresden
2023-07-16 12:42:30,K21,M,44,Hanover
2025-01-12 14:11:25,I25,M,10,Essen
2025-02-10 15:55:48,J45,F,25,Hanover
2023-07-07 06:14:50,M54,F,89,Dresden
2025-04-04 11:07:27,M54,F,66,Bochum
2024-12-11 07:24:50,N39,M,96,Bochum
2024-08-18 19:22:55,N39,D,19,Berlin
2024-10-22 19:57:40,I25,M,82,Essen
2023-09-19 09:07:53,A90,F,9,Cologne
2023-11-30 08:43:46,N39,D,30,Hanover
2023-10-05 18:49:42,N39,D,20,Dresden
2024-10-19 22:56:41,F32,D,17,Dortmund
2024-11-20 17:29:02,R10,M,69,Hamburg
2023-12-06 14:54:45,R10,F,0,Nuremberg
2025-05-14 00:23:12,E11,M,54,Leipzig
2024-02-25 07:44:34,F32,D,57,Stuttgart
2024-02-07 21:33:20,K21,D,46,Nuremberg
2024-12-21 05:36:54,E11,M,40,Bochum
2023-11-23 23:08:51,A90,M,93,Munich
2023-09-21 05:48:09,A90,F,77,Cologne
2024-07-08 20:13:40,A90,F,82,Berlin
2025-04-28 16:51:33,M54,F,6,Leipzig
2025-06-21 03:58:25,J45,F,9,Düsseldorf
2024-05-08 13:15:06,A90,F,45,Leipzig
2024-11-03 22:20:24,I25,F,86,Frankfurt
2023-09-06 14:41:15,I25,F,52,Munich
2023-07-22 09:31:43,A90,F,33,Cologne
2024-02-03 19:20:10,K21,M,45,Hamburg
2025-06-14 06:16:40,E11,M,44,Berlin
2024-06-21 06:25:28,J45,F,78,Dresden
2025-03-17 16:06:34,A90,F,58,Hanover
2025-03-11 20:36:57,R10,D,88,Dortmund
2023-10-03 08:35:00,N39,M,6,Essen
2025-05-04 11:12:41,K21,F,3,Bremen
2024-01-20 15:35:47,R10,M,10,Stuttgart
2023-10-17 01:26:18,F32,M,60,Berlin
2024-11-24 01:40:15,J45,D,80,Hanover
2024-08-12 23:56:10,M54,M,0,Düsseldorf
2025-03-31 05:22:34,F32,M,70,Dresden
2024-11-21 21:46:40,J45,M,22,Hanover
2024-11-17 08:51:52,J45,D,87,Cologne
2024-03-30 23:50:10,I25,F,3,Dortmund
2023-10-02 20:05:34,K21,M,28,Cologne
2025-05-12 15:01:08,M54,F,21,Cologne
2023-11-02 09:16:19,F32,M,20,Bochum
2024-02-06 16:14:03,K21,F,46,Bochum
2025-04-26 14:33:29,I25,M,49,Leipzig
2023-07-19 20:32:59,A90,M,74,Berlin
2023-08-07 06:47:01,K21,D,22,Munich
2023-08-06 00:19:03,A90,M,41,Essen
2023-12-12 05:29:28,A90,M,6,Hanover
2024-12-15 08:59:56,E11,D,78,Munich
2024-01-23 02:53:14,J45,D,100,Düsseldorf
2024-09-11 02:48:16,A90,F,55,Leipzig
2024-03-05 20:58:44,F32,D,31,Bochum
2024-04-15 09:41:42,J45,F,65,Cologne
2025-07-03 08:03:58,R10,F,9,Munich
2024-09-18 04:39:55,K21,D,84,Stuttgart
2025-06-11 03:09:15,E11,F,55,Cologne
2025-04-25 04:58:02,N39,F,28,Bochum
2023-08-07 01:19:13,K21,M,82,Dortmund
2025-04-22 19:35:29,K21,D,8,Nuremberg
2025-02-06 07:11:03,M54,F,67,Stuttgart
2024-12-31 03:56:28,R10,M,77,Leipzig
2024-10-19 08:43:07,N39,M,35,Berlin
2024-11-25 11:07:47,I25,F,50,Bremen
2024-07-23 12:10:48,E11,D,6,Munich
2025-01-08 17:36:29,K21,M,98,Düsseldorf
2024-11-16 18:00:12,K21,F,13,Dresden
2025-06-05 14:02:09,N39,D,59,Munich
2024-06-25 16:25:21,J45,F,60,Düsseldorf
2024-11-13 15:23:45,J45,D,36,Hanover
2024-06-07 15:30:02,R10,M,47,Stuttgart
2024-04-19 17:15:23,J45,D,45,Hanover
2025-05-12 06:34:21,N39,D,66,Hanover
2024-08-26 06:01:06,A90,M,32,Munich
2023-11-20 21:50:03,I25,F,37,Düsseldorf
2023-12-13 20:47:38,A90,F,70,Düsseldorf
2024-04-22 03:35:51,A90,D,52,Frankfurt"""
return (TOY_DATASET_CSV,)
@app.cell
def _():
TOY_DATASET_MAPPING = "\n".join(
[
"profiles:",
"- name: ambulatory_care",
" value_encodings:",
" sex:",
' male: "M"',
' female: "F"',
' other: "O"',
" columns:",
" age:",
" concept: demographic_criteria",
" attribute: age",
" dtype: integer",
" sex:",
" concept: demographic_criteria",
" attribute: sex",
" dtype: string",
" icd_code:",
" concept: diagnosis",
" dtype: string",
"",
]
)
return (TOY_DATASET_MAPPING,)
@app.cell
def _(TOY_DATASET_CSV, TOY_DATASET_MAPPING):
EXAMPLE_DATASETS = {
"Toy dataset": {
"csv": TOY_DATASET_CSV,
"mapping": TOY_DATASET_MAPPING,
"date_column": "recording_ts",
},
}
return (EXAMPLE_DATASETS,)
@app.cell
def _(EXAMPLE_DATASETS, mo):
data_source = mo.ui.radio(
options=["Load example", "Upload your own"],
value="Load example",
)
_datasets = list(EXAMPLE_DATASETS.keys())
example_picker = mo.ui.dropdown(
options=_datasets,
value=_datasets[0] if _datasets else None,
label="Example dataset",
)
sample_file = mo.ui.file(kind="area", filetypes=[".csv"], max_size=10_000_000)
return data_source, example_picker, sample_file
@app.cell
def _(data_source, example_picker, mo, sample_file):
mo.vstack(
[
mo.md("## Load your data"),
data_source,
example_picker if data_source.value == "Load example" else sample_file,
]
)
return
@app.cell
def _(EXAMPLE_DATASETS, data_source, example_picker, pl, sample_file):
if data_source.value == "Load example":
df_selected = (
pl.read_csv(EXAMPLE_DATASETS[example_picker.value]["csv"].encode())
if example_picker.value
else None
)
else:
df_selected = pl.read_csv(sample_file.contents()) if sample_file.value else None
return (df_selected,)
@app.cell
def _(EXAMPLE_DATASETS, data_source, example_picker):
_default_yaml = """
profiles:
- name: my_dataset
# value_encodings: # optional — map OSD canonical values to dataset-specific ones
# sex:
# male: "M"
# female: "F"
columns:
# Rename the keys below to match your dataset column names.
# Available concepts: diagnosis, demographic_criteria, symptom,
# diagnostic_test, epidemiological_history
my_diagnosis_column:
concept: diagnosis
dtype: string
# my_age_column:
# concept: demographic_criteria
# attribute: age
# dtype: integer
"""
if data_source.value == "Load example" and example_picker.value:
_example = EXAMPLE_DATASETS[example_picker.value]
initial_yaml = _example["mapping"]
initial_date_column = _example["date_column"]
else:
initial_yaml = _default_yaml
initial_date_column = None
return initial_date_column, initial_yaml
@app.cell
def _(df_selected, initial_date_column, initial_yaml, mo):
mo.stop(df_selected is None)
yaml_editor = mo.ui.code_editor(
value=initial_yaml,
language="yaml",
).form(label="Data to OSD mapping", show_clear_button=True, bordered=True)
date_column_picker = mo.ui.dropdown(
options=df_selected.columns,
label="Date column",
value=initial_date_column,
)
date_format_input = mo.ui.text(
value="%Y-%m-%d %H:%M:%S",
label="Date format<sup>1</sup>",
)
date_block = mo.vstack(
[
date_format_input,
mo.md(
"[^1]: A Python date format code compatible with your data. See other date formats [here](https://strftime.org/)."
),
]
)
_cols_hint = "`, `".join(df_selected.columns)
mo.vstack(
[
mo.md("### Mapping your data to the format"),
mo.md(
"Edit the YAML below to map your dataset columns to OSD concepts, "
"then click **Submit**. "
"Select the date column separately for the time-series view.\n\n"
f"Your dataset columns: `{_cols_hint}`"
),
mo.hstack(
[yaml_editor, mo.vstack([date_column_picker, date_block])],
widths=[3, 1],
align="start",
),
]
)
return date_column_picker, date_format_input, yaml_editor
@app.cell
def _(df_selected, initial_yaml, load_profile, mo, yaml, yaml_editor):
_yaml_to_use = yaml_editor.value if yaml_editor.value is not None else initial_yaml
mo.stop(_yaml_to_use is None)
try:
_parsed = yaml.safe_load(_yaml_to_use)
except yaml.YAMLError as _e:
mo.stop(True, mo.callout(mo.md(f"**Invalid YAML:** {_e}"), kind="danger"))
if not _parsed["profiles"][0]["columns"]:
mo.stop(
True,
mo.callout(mo.md("You need to map **at least one column**"), kind="danger"),
)
not_found = []
for declared_column in _parsed["profiles"][0]["columns"]:
if declared_column not in df_selected.columns:
not_found.append(declared_column)
if not_found:
mo.stop(
True,
mo.callout(
mo.md(f"**Columns not found:** {', '.join(not_found)}"), kind="danger"
),
)
try:
_profile_name = _parsed["profiles"][0]["name"]
profile = load_profile(_parsed, _profile_name)
except (KeyError, IndexError, ValueError) as _e:
mo.stop(True, mo.callout(mo.md(f"**Profile error:** {_e}"), kind="danger"))
return (profile,)
@app.cell
def _(date_column_picker, mo, profile):
mo.stop(date_column_picker.value is None)
date_column = date_column_picker.value
_diagnosis_cols = [c.col_name for c in profile.columns if c.concept == "diagnosis"]
code_column = _diagnosis_cols[0] if _diagnosis_cols else None
return code_column, date_column
@app.cell
def _(get_definition_dir):
definition_options = {
filepath.name.replace(".json", ""): filepath
for filepath in get_definition_dir().glob("**/*.json")
}
return (definition_options,)
@app.cell
def _(definition_options, mo):
definitions_dropdown = mo.ui.multiselect(
label="Select Syndromic Indicators", options=sorted(definition_options.keys())
)
return (definitions_dropdown,)
@app.cell
def _(mo):
mo.md(r"""
### Data sample
""")
return
@app.cell
def _(df_selected, mo):
mo.stop(df_selected is None)
df_selected.sample(10)
return
@app.cell
def _(mo):
mo.md(r"""
---
""")
return
@app.cell
def _(mo):
mo.md(r"""
## Data & Definitions
""")
return
@app.cell
def _(definitions_dropdown, mo):
mo.hstack([mo.md("**::lucide:filter:: Filters:**"), definitions_dropdown])
return
@app.cell
def _(
OSDEngine,
definition_options,
definitions_dropdown,
df_selected,
json,
mo,
profile,
):
mo.stop(
df_selected is None or df_selected.is_empty() or not definitions_dropdown.value
)
definitions = definitions_dropdown.value
# skip criteria that can't be evaluated (e.g. professional_judgment)
engine = OSDEngine(profile, skip_unresolvable=True)
defs_dict = {
name: json.loads(definition_options[name].read_text()) for name in definitions
}
df_filtered = engine.label(df_selected, defs_dict)
return definitions, df_filtered
@app.cell
def _(definitions, df_filtered, df_selected, mo):
mo.stop(definitions is None or df_filtered is None)
_cards = [
mo.stat(
label="Syndromic Indicators",
value=len(definitions),
caption=", ".join([definition for definition in definitions]),
bordered=True,
),
mo.stat(
label="Rows",
value=df_selected.shape[0],
),
mo.stat(
label="Columns",
value=df_selected.shape[1],
),
]
mo.hstack(_cards, widths="equal", align="center")
return
@app.cell
def _(definition_options, json):
def load_definition(name: str) -> dict:
return json.loads(definition_options[name].read_text())
return (load_definition,)
@app.cell
def _(mo):
top_n = mo.ui.number(start=1, stop=10, label="Number of top codes", value=3, step=1)
return (top_n,)
@app.cell
def _(
code_column,
date_column,
date_format_input,
definitions,
df_filtered,
df_selected,
groupped_bar,
mo,
plot_cases,
top_n,
):
mo.stop(definitions is None or df_selected is None)
if code_column:
diagnosis_chart = [
mo.md("### Codes comparison per syndromic indicator"),
top_n.left(),
groupped_bar(
df_filtered,
definitions,
top_n=top_n.value or 3,
group_by_column=code_column,
),
]
else:
diagnosis_chart = []
timeseries = [
mo.md("### Time series"),
plot_cases(
df_filtered,
definitions,
date_column=date_column,
date_format=date_format_input.value,
),
]
mo.vstack(
[
mo.md("## Findings from the data 📊"),
*timeseries,
*diagnosis_chart,
]
)
return
@app.cell
def _(definitions, load_definition, mo):
mo.stop(definitions is None)
mo.vstack(
[
mo.md("### Definitions details"),
mo.md(
"Here the definitions used to filter the data. See here what criteria were applied. 🔎"
),
mo.accordion(
{
"JSONs": mo.accordion(
{
definition: mo.json(load_definition(definition))
for definition in definitions
}
),
},
),
]
)
return
if __name__ == "__main__":
app.run()