Skip to main content

GlycoSignal

PyPI version Python versions Tests License: MIT

GlycoSignal

Python library for CGM data analysis — individually callable glycemic metrics, day/sliding-window segmentation, and ML-ready feature matrices.

pip install GlycoSignal

Quick start

import glycosignal as gs

df = gs.load_csv("cgm.csv")
df = gs.clean_cgm(df)

# Individual metrics
gs.mean_glucose(df)                             # 138.5
gs.time_in_range_percent(df, low=70, high=180)  # 93.1

# Segment → feature matrix  (the standard pipeline)
segs = gs.create_day_segments(df)               # 24 h, midnight anchor
X    = gs.build_feature_map(segs.windows)       # 32 features × n_days

Input format

Two required columns; everything else is auto-detected (case-insensitive).

Column Required Recognized aliases
Timestamp Yes time, datetime, date_time, date
Glucose Yes Glucose Value (mg/dL), gl, sgv, glucose_mg_dl, bg
subject Multi-subject only id, ptid, patient_id, subjectid
# Override auto-detection
df = gs.load_csv("data.csv", timestamp_col="time_utc", glucose_col="bg_mg_dl")

# Multiple subjects — one file with subject column
df = gs.io.load_cgm_file("all.csv", subject_col="ptid")

# Multiple subjects — one CSV per subject in a folder
df = gs.io.load_cgm_folder("data/subjects/")

Data segmentation

Both functions return WindowResult(windows, metadata). The windows DataFrame flows directly into build_feature_map().

Daily segments

from glycosignal import windows

segs = windows.create_day_segments(df)                    # midnight–midnight (default)
segs = windows.create_day_segments(df, anchor_time="08:00")             # 8 AM–8 AM
segs = windows.create_day_segments(df, anchor_time="08:00",
                                   min_fraction=0.7,      # drop days < 70 % coverage
                                   group_col="subject")   # multi-subject

print(segs.metadata)
# {'n_groups': 1, 'n_valid_windows': 7, 'n_discarded_partial_days': 0, ...}

Sliding windows

result = windows.create_sliding_windows(df, window_hours=6, step_hours=1)
result = windows.create_sliding_windows(df, window_hours=12, step_hours=12,
                                        anchor_time="08:00")
result = windows.create_sliding_windows(df, window_hours=24, overlap_hours=12)
result = windows.create_sliding_windows(df, window_hours=24, step_hours=6,
                                        group_col="subject")

Key parameters: window_hours, step_hours, anchor_time, min_fraction (default 0.0 — keep all windows), group_col, interpolate, max_gap_points.

Output

The windows DataFrame is long-format — one row per (window, time-point):

window_id subject date Timestamp Glucose
S01_2023-01-02 S01 2023-01-02 2023-01-02 00:00 112.4

Non-midnight anchors append _HHMM to the window ID (e.g. S01_2023-01-02_0800).

Saving as wide-format CSV

wide = windows.pivot_windows_wide(segs.windows)
wide.to_csv("segments.csv", index=False)
# → columns: date | subject | 00:00 | 00:05 | … | 23:55
# For non-midnight anchor (e.g. "08:00"): 08:00 | … | 23:55 | 00:00 | … | 07:55

Glycemic metrics

Every metric is a standalone function. See the full metric reference for all formulas.

from glycosignal import metrics

# Core
metrics.mean_glucose(df)                              # 138.5
metrics.median_glucose(df)
metrics.std_glucose(df)
metrics.cv(df)                                        # 17.7 %
metrics.time_in_range_percent(df, low=70, high=180)   # 93.1 %
metrics.time_above_range(df, threshold=180)
metrics.time_below_range(df, threshold=70)

# Variability
metrics.mage(df)                                      # 27.0
metrics.j_index(df)
metrics.conga(df)
metrics.modd(df)
metrics.grade(df)

# Risk indices
metrics.lbgi(df)
metrics.hbgi(df)
metrics.adrr(df)
metrics.gri(df)                                       # 7.2

# Grouped helpers — return dicts
metrics.basic_stats(df)          # mean, median, min, max, q1, q3
metrics.variability_metrics(df)  # sd, cv, j_index, mage
metrics.risk_indices(df)         # lbgi, hbgi, adrr, gri
metrics.summary_dict(df)         # all of the above combined

Performance tip — call prepare() once when computing many metrics on the same data:

from glycosignal.schemas import prepare
p = prepare(df)
metrics.mean_glucose(p); metrics.cv(p); metrics.lbgi(p)

Feature matrices

from glycosignal import windows, features

segs = windows.create_day_segments(df)
X = features.build_feature_map(segs.windows)           # 32 features × n_windows

# Subset
X = features.build_feature_map(segs.windows,
    feature_names=["mean_glucose", "cv", "tir_70_180_pct", "mage", "lbgi"])

# Single window → dict
features.build_feature_vector(window_df, feature_names=["mean_glucose", "cv"])

# List of DataFrames (one per subject)
features.build_feature_table([df_s01, df_s02], record_ids=["S01", "S02"])

Feature registry

gs.list_features()                      # all 32 names
gs.list_features(category="risk")       # ['adrr', 'gri', 'hbgi', 'lbgi']
gs.get_feature_metadata()               # DataFrame: name | description | category
gs.get_feature("gri").description       # 'Glucose Risk Index (Klonoff et al. 2023)'

# Register a custom feature
from glycosignal.registry import DEFAULT_REGISTRY
DEFAULT_REGISTRY.register(name="my_metric", func=my_fn,
                           description="...", category="variability")

Preprocessing

from glycosignal import preprocessing

df     = preprocessing.clean_cgm(df)                              # drop NaN, sort, enforce positive
report = preprocessing.validate_cgm(df)                           # structured quality report
gaps   = preprocessing.detect_gaps(df)                            # DataFrame of gap intervals
df     = preprocessing.resample_cgm(df, freq="5min")              # regular grid
df     = preprocessing.interpolate_cgm(df, method="pchip",
                                        max_gap_points=12)
df     = preprocessing.convert_units(df, from_unit="mmol/L",
                                      to_unit="mg/dL")

Event detection

Returns a DataFrame with start_time, end_time, duration_minutes, event_type.

from glycosignal import detect

detect.detect_hypoglycemia(df, threshold=70, min_duration_minutes=15)
detect.detect_hyperglycemia(df, threshold=180, min_duration_minutes=15)
detect.detect_nocturnal_events(df, start_hour=0, end_hour=6)
detect.detect_postprandial_excursions(df, rise_threshold=50)

Plotting

All functions return (fig, ax) and never call plt.show().

from glycosignal import plotting

fig, ax = plotting.plot_glucose_timeseries(df, subject="P001")
fig, ax = plotting.plot_daily_overlay(df)
fig, ax = plotting.plot_agp(df)
fig, ax = plotting.plot_histogram(df)
fig.savefig("output.png", dpi=150)

CLI

glycosignal summary data.csv
glycosignal windows data.csv --window-hours 24 --overlap-hours 0 --output windows.csv
glycosignal features windows.csv --output features.csv
glycosignal features windows.csv --features mean_glucose,cv,lbgi,gri
glycosignal list-features
glycosignal list-features --category risk

License

MIT. Copyright (c) 2024 Jiafeng Song. See LICENSE.

Metadata

Release files for GlycoSignal 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for GlycoSignal 0.2.0
File Size Uploaded
glycosignal-0.2.0.tar.gz 75.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for GlycoSignal 0.2.0
File Interpreter ABI Platform
glycosignal-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 125.7 kB

Release files / glycosignal-0.2.0.tar.gz

Download URL glycosignal-0.2.0.tar.gz
Size 75.4 kB
Tags Source
SHA-256 checksum
How to use checksums
b890fc22d1d79d191621786c53c573243775cd3691cdef594ad69ba4f447677d
BLAKE2b-256 checksum
How to use checksums
192c8f733a755043f04c77edebc6fef4d54ac79b7abc5e5d6f576b742a31e0fc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / glycosignal-0.2.0-py3-none-any.whl

Download URL glycosignal-0.2.0-py3-none-any.whl
Size 50.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
601a17d884c2f0397e14bae3a48f6cb16012333dd5d9524805eee62caf620b11
BLAKE2b-256 checksum
How to use checksums
3fd0a1431638a646b779a277e86db23676834cdeaa57ac92e223c24781fc3534
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page