Skip to content

Commit 1b55e2e

Browse files
committed
plot_daily implemented
1 parent 5107db0 commit 1b55e2e

6 files changed

Lines changed: 377 additions & 2 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,11 @@ IGLU_PYTHON extends beyond the capabilities of the original IGLU-R package by of
9696

9797
| Function | Description |
9898
|-------------------|------------------------------------------|
99+
| **LOAD DATA FROM DEVICE SPECIFIC FILE**
99100
| load_libre() | Load Timeseries from Libre device file (CGM reading converted into mg/dL)
100101
| load_dexcom() | Load Timeseries from Dexcom device file (CGM reading converted into mg/dL)
102+
| **PLOT/VISUALISE CGM **
103+
| plot_daily() | Plot daily Glucose values for each day |
101104

102105
# Installation
103106

iglu_python/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from .ea1c import ea1c
1111
from .episode_calculation import episode_calculation
1212
from .extension.load_data import load_dexcom, load_libre
13+
from .extension.plots import plot_daily
1314
from .gmi import gmi
1415
from .grade import grade
1516
from .grade_eugly import grade_eugly
@@ -85,6 +86,7 @@
8586
"median_glu",
8687
"modd",
8788
"pgs",
89+
"plot_daily",
8890
"process_data",
8991
"quantile_glu",
9092
"range_glu",

iglu_python/extension/plots.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""
2+
This module implements various plots for the iglu_python package.
3+
"""
4+
5+
import matplotlib.pyplot as plt
6+
import pandas as pd
7+
8+
9+
def plot_daily(cgm_timeseries: pd.Series, lower: int = 70, upper: int = 140) -> plt.Figure:
10+
"""
11+
Plot daily Glucose values for each day separately
12+
13+
14+
15+
Args:
16+
- cgm_timeseries: pd.Series
17+
- lower: int, default=70, Lower bound used for hypoglycemia cutoff, in mg/dL
18+
- upper: int, default=140, Upper bound used for hyperglycemia cutoff, in mg/dL
19+
20+
Returns:
21+
plt.Figure object
22+
"""
23+
# divide cgm_timeseries into list of daily series
24+
cgm_daily_group = cgm_timeseries.resample("D")
25+
cgm_timeseries_daily = {day: cgm_daily_group.get_group(day) for day in cgm_daily_group.groups}
26+
27+
# plot each day separately
28+
# Create one figure with subplots for each day
29+
num_days = len(cgm_timeseries_daily)
30+
fig, axes = plt.subplots(num_days, 1, figsize=(12, 3 * num_days))
31+
32+
# If only one day, axes will be a single object, not an array
33+
if num_days == 1:
34+
axes = [axes]
35+
36+
for i, (day, cgm_one_day) in enumerate(cgm_timeseries_daily.items()):
37+
# Convert datetime index to time-only for x-axis display
38+
axes[i].plot(cgm_one_day.index, cgm_one_day.values)
39+
axes[i].set_title(f"Day: {day.strftime('%Y-%m-%d')}")
40+
axes[i].set_ylabel("Glucose (mg/dL)")
41+
axes[i].set_ylim(0, max(max(cgm_one_day.values), 300))
42+
43+
# Fill area above upper limit and plot it in orange
44+
upper_array = [upper] * len(cgm_one_day.values)
45+
area_over_upper = [
46+
cgm_one_day.values[i] if cgm_one_day.values[i] > upper else upper for i in range(len(cgm_one_day.values))
47+
]
48+
axes[i].fill_between(cgm_one_day.index, area_over_upper, upper_array, alpha=0.3, color="orange")
49+
axes[i].axhline(y=upper, color="orange", linestyle="--", alpha=0.7, label=f"Hyper threshold ({upper} mg/dL)")
50+
51+
# Fill area below lower limit and plot it in blue
52+
lower_array = [lower] * len(cgm_one_day.values)
53+
area_below_lower = [
54+
cgm_one_day.values[i] if cgm_one_day.values[i] < lower else lower for i in range(len(cgm_one_day.values))
55+
]
56+
axes[i].fill_between(cgm_one_day.index, lower_array, area_below_lower, alpha=0.3, color="blue")
57+
axes[i].axhline(y=lower, color="blue", linestyle="--", alpha=0.7, label=f"Hypo threshold ({lower} mg/dL)")
58+
59+
# on horisontal axis, show only time in hours
60+
axes[i].set_xlabel("Time (hours)")
61+
time_range = pd.date_range(start=day, periods=24, freq="1h")
62+
axes[i].set_xticks(time_range) # Show every hour from 0 to 24
63+
axes[i].set_xticklabels([f"{h.hour}" for h in time_range]) # Format as HH:00
64+
axes[i].grid(True, alpha=0.3, linestyle="--")
65+
axes[i].legend()
66+
67+
return fig

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ dependencies = [
2727
"numpy>=2.2.6",
2828
"pandas>=2.2.3",
2929
"tzlocal>=5.3.1",
30-
"openpyxl >= 3.1.5"
30+
"openpyxl >= 3.1.5",
31+
"matplotlib >= 3.10.0"
3132
]
3233

3334
[project.urls]

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pandas >= 2.2.3
22
numpy >= 2.2.6
33
tzlocal >= 5.3.1
4-
openpyxl >= 3.1.5
4+
openpyxl >= 3.1.5
5+
matplotlib >= 3.10.0

0 commit comments

Comments
 (0)