Visual field analysis for glaucoma without R dependencies
Project description
PyGlaucoMetrics
PyGlaucoMetrics is an open-source, pure-Python package for glaucoma detection and visual field (VF) analysis — no R or rpy2 dependency required. It accepts Humphrey Field Analyzer (HFA) 24-2 test patterns and provides a full pipeline from raw VF data to ensemble glaucoma classification, severity staging, and progression analysis, with an interactive GUI.
Overview
PyGlaucoMetrics is designed as an accessible GUI application and Python library that implements selected visual field analysis components from PyVisualFields. It integrates glaucoma classification criteria, HAP2 severity staging, progression analysis, and an interactive visualization interface.
Note: PyVisualFields is the underlying developer-facing library. PyGlaucoMetrics builds upon it to provide an end-user GUI and glaucoma-specific classification pipeline.
Features
- Pure Python — all computations via
numpy,scipy, andpandas; no R required - Automatic column standardization — any CSV with any column naming convention is accepted; columns are automatically mapped to canonical names (
patientid,eyeid,l1–l54,td*,pd*, etc.) - Missing block computation — if TD, PD, TDP, or PDP values are missing, they are computed automatically from sensitivity data
- Dataset summary popup — on load, a summary window shows which data blocks and global indices are present or missing
- Demo dataset — download the UW HVF dataset directly from within the GUI (no manual download needed)
- Five glaucoma classifiers with GL/Non-GL labels and human-readable reasons:
- HAP2 (Part 1: classification + Part 2: Early/Moderate/Severe staging)
- UKGTS
- LoGTS
- Foster (requires GHT column)
- Kang's
- AUC-weighted ensemble decision (weights from published Table 2, Moradi et al. 2025)
- Six-panel VF visualization — Sensitivity, TD Probability, PD Probability (row 1) + Sensitivity dB, TD Deviation, PD Deviation (row 2)
- Progression analysis — CIGTS, PLR Nouri 2012, VFI, Schell 2014, AGIS, Global Linear Regression (GLR), Pointwise Linear Regression (PLR)
- Save results — exports classifier CSVs, HAP2 severity bar chart, ensemble bar chart, and VF plots
Installation
Windows:
pip install PyGlaucoMetrics[windows]
Linux / macOS:
pip install PyGlaucoMetrics
Quick Start
Launch the GUI
Option 1 — Console script (recommended):
pyglaucometrics-gui
Option 2 — From Python:
from PyVisualFields.gui_pygl import main
main()
Option 3 — Run the script directly:
python gui_pygl.py
Note on import: PyGlaucoMetrics is accessed as a submodule of PyVisualFields:
from PyVisualFields import PyGlaucoMetrics
Use classifiers in Python
import pandas as pd
from PyVisualFields import visualFields, vfprogression
from PyVisualFields import PyGlaucoMetrics
from PyVisualFields.utils import (
canonicalize_vf_df, compute_missing_blocks,
vf_blocks, missing_blocks, print_vf_summary
)
# 1. Load and standardize (any column naming convention accepted)
df = pd.read_csv('VF_Data.csv')
df = canonicalize_vf_df(df) # standardize column names
# Check what blocks are present
print(vf_blocks(df)) # e.g. {'sens': True, 'td': True, ...}
print(missing_blocks(df)) # e.g. ['tdp', 'pdp']
print_vf_summary(df) # human-readable summary with ✓/✗
# 2. Compute missing blocks (TD, PD, TDP, PDP) and global indices
df = compute_missing_blocks(df)
df_gi = visualFields.getgl(df) # MD, PSD, VFI, GH, etc.
combined = pd.concat([df, df_gi], axis=1)
final_df = combined.loc[:, ~combined.columns.duplicated()]
# 3. Run classifiers
df_hap2 = PyGlaucoMetrics.Fn_HAP2(final_df)
df_hap2 = PyGlaucoMetrics.Fn_HAP2_part2(df_hap2)
df_ukgts = PyGlaucoMetrics.Fn_UKGTS(final_df)
df_logts = PyGlaucoMetrics.Fn_LoGTS(final_df)
df_foster = PyGlaucoMetrics.Fn_Foster(final_df) # requires GHT column
df_kangs = PyGlaucoMetrics.Fn_Kangs(final_df)
# 4. View results
print(df_hap2[['l1', 'l2', 'HAP2_clf', 'HAP2_reason']].head())
# Output:
# l1 l2 HAP2_clf HAP2_reason
# 0 26 28 Non-GL
# 3 24 25 GL GHT outside; cluster of 3 PDP points < 5% with...
print(df_hap2[['l1', 'l2', 'HAP2_clf', 'severity(HAP2_part2)']].head())
# Output:
# l1 l2 HAP2_clf severity(HAP2_part2)
# 0 26 28 Non-GL Early
# 3 24 25 GL Early
print(df_ukgts[['l1', 'l2', 'UKGTS_clf', 'UKGTS_reason']].head())
# Output:
# l1 l2 UKGTS_clf UKGTS_reason
# 3 24 25 GL Cluster of 2 TDP points < 1%; Cluster of 3 TDP...
print(df_foster[['l1', 'l2', 'Foster_clf', 'Foster_reason']].head())
# Output:
# l1 l2 Foster_clf Foster_reason
# 3 24 25 GL GHT outside AND cluster of 3 PDP points < 5%
print(df_kangs[['l1', 'l2', 'Kangs_clf', 'Kangs_reason']].head())
# Output:
# l1 l2 Kangs_clf Kangs_reason
# 4 26 26 GL Cluster of 3 points with TD < -5 dB
GUI Workflow
- Click Load Dataset — choose between:
- 📥 Use UW Demo Dataset — downloads automatically from the UW HVF repository
- 📂 Load My Own CSV — select any CSV file from disk
- A Dataset Summary popup shows which blocks (sensitivity, TD, PD, TDP, PDP) and global indices (MD, PSD, GHT, VFI, etc.) are present or missing
- Missing blocks are computed automatically
- Enter an index (row number) to view VF plots and classifier predictions
- Click 💾 Save Results to export all outputs
Input Format
Any CSV is accepted. Column names are automatically standardized. The following aliases are recognized:
| Canonical name | Accepted aliases |
|---|---|
patientid |
id, patient_id, mrn, subjectid, pid |
eyeid |
eye, eye_id, laterality |
date |
examdate, testdate, vfdate |
l1–l54 |
s1–s54, sens1–sens54, sensitivity1–sensitivity54 |
td1–td54 |
td1–td54 |
pdp1–pdp54 |
pdp1–pdp54 |
md |
mtd |
ght |
ght |
Eye values (OD/OS) are also normalized from right/left, R/L, 1/0.
Classifiers
| Classifier | Input | Criterion | Output columns |
|---|---|---|---|
| HAP2 Part 1 | PD probabilities | Cluster of 3 PDP points < 5% with ≥1 < 1%; or GHT outside; or PSD p < 5% | HAP2_clf, HAP2_reason |
| HAP2 Part 2 | Sensitivity + PDP + MD | Early / Moderate / Severe per HAP2 reference criteria (applied to all rows; Non-GL rows receive a severity based on their field characteristics) | severity(HAP2_part2) |
| UKGTS | TD probabilities + TD values | ≥2 TDP points < 1%; or ≥3 < 5%; or nasal step ≥10 dB | UKGTS_clf, UKGTS_reason |
| LoGTS | TD values | Cluster of 2 TD < −10 dB; or 3 TD < −8 dB | LoGTS_clf, LoGTS_reason |
| Foster | PD probabilities + GHT | GHT outside normal limits AND cluster of 3 PDP < 5% | Foster_clf, Foster_reason |
| Kang's | TD values | Cluster of 3 TD < −5 dB; or 2 TD < −10 dB | Kangs_clf, Kangs_reason |
Ensemble Decision
Final GL/Non-GL label uses an AUC-weighted ensemble combining all five classifiers:
| Classifier | AUC weight |
|---|---|
| UKGTS | 0.815 |
| LoGTS | 0.821 |
| Foster | 0.675 |
| Kang's | 0.815 |
| HAP2 | 0.735 |
HAP2 Severity Staging (Part II)
Based on Hodapp-Anderson-Parrish 2 (Clinical Decisions in Glaucoma):
| Stage | Criteria (all must be met for Early; any for Severe) |
|---|---|
| Early | MD > −6 dB AND no central 5° point < 15 dB AND ≤12 PDP points < 5% AND ≤4 PDP points < 1% |
| Severe | MD < −12 dB OR any central 5° point = 0 dB OR central < 15 dB in both hemifields OR ≥27 PDP points < 5% OR ≥14 PDP points < 1% |
| Moderate | Neither Early nor Severe |
Central 5° points: locations 23, 24, 32, 33 (1-based 24-2 HFA grid).
Progression Analysis
| Method | Function | Min visits | Required columns |
|---|---|---|---|
| CIGTS | progression_cigts() |
5 | tdp1–tdp54, eyeid |
| PLR Nouri 2012 | progression_plrnouri2012() |
3 | td1–td54, eyeid |
| VFI | progression_vfi() |
5 | vfi, eyeid |
| Schell 2014 | progression_schell2014() |
5 | td1–td54, eyeid |
| AGIS | progression_agis() |
5 | l1–l54, eyeid |
| Global Linear Regression | visualFields.glr() |
2 | global indices |
| Pointwise Linear Regression | visualFields.plr() |
2 | l1–l54 or td*/pd* |
Data is automatically sorted by date/age within each patient before progression analysis.
Function Reference
Data Utilities (PyVisualFields.utils)
| Function | Description |
|---|---|
canonicalize_vf_df(df) |
Standardize column names to canonical format |
canonicalize_vf_df(df, sort_byDateAge=True) |
Standardize and sort by date/age within patient |
compute_missing_blocks(df) |
Compute missing TD, PD, TDP, PDP blocks |
vf_blocks(df) |
Return dict of which blocks are present |
missing_blocks(df) |
Return list of missing block names |
investigate_vf_df(df) |
Return full summary dict of available data |
print_vf_summary(df) |
Print human-readable data summary |
Glaucoma Classifiers (from PyVisualFields import PyGlaucoMetrics)
| Function | Description |
|---|---|
Fn_HAP2(df) |
HAP2 Part 1: GL/Non-GL with reason |
Fn_HAP2_part2(df) |
HAP2 Part 2: Early/Moderate/Severe severity |
Fn_UKGTS(df) |
UKGTS criterion: GL/Non-GL with reason |
Fn_LoGTS(df) |
LoGTS criterion: GL/Non-GL with reason |
Fn_Foster(df) |
Foster criterion: GL/Non-GL with reason (needs GHT) |
Fn_Kangs(df) |
Kang's criterion: GL/Non-GL with reason |
Deviation Analysis (PyVisualFields.visualFields)
| Function | Description |
|---|---|
gettd(df) |
Compute total deviation |
gettdp(df) |
Compute TD probability |
getpd(df) |
Compute pattern deviation |
getpdp(df) |
Compute PD probability |
getgl(df) |
Compute global indices (MD, PSD, VFI, GH, etc.) |
getglp(df) |
Compute global index p-values |
glr(df, type, testSlope) |
Global linear regression |
plr(df, type, testSlope) |
Pointwise linear regression |
poplr(df, type, testSlope) |
PoPLR permutation regression |
Visualization
| Function | Description |
|---|---|
visualFields.vfplot(df, type='s') |
Sensitivity plot |
visualFields.vfplot_tds(df) |
TD probability plot |
visualFields.vfplot_pds(df) |
PD probability plot |
vfprogression.plotValues(arr) |
Plot sensitivity/TD/PD values |
vfprogression.plotProbabilities(arr) |
Plot TDP/PDP probability maps |
Built-in Datasets
| Function | Description |
|---|---|
visualFields.data_vfpwgRetest24d2() |
24-2 retest dataset (30 glaucoma patients) |
visualFields.data_vfctrSunyiu24d2() |
SUNY-IU 24-2 control dataset |
visualFields.data_vfpwgSunyiu24d2() |
SUNY-IU 24-2 glaucoma dataset |
vfprogression.data_vfseries() |
Longitudinal VF series |
vfprogression.data_cigts() |
CIGTS study dataset |
vfprogression.data_vfi() |
VFI dataset |
vfprogression.data_schell2014() |
Schell 2014 dataset |
Requirements
Core (all platforms):
numpy
pandas
matplotlib
scipy
PyQt5>=5.15
Pillow
seaborn
pingouin
requests
PyVisualFields
Windows only (installed automatically with [windows] extra):
pywin32
Citation
If you use PyGlaucoMetrics in your research, please cite:
-
Moradi et al. (2025) — PyGlaucoMetrics paper: Moradi, M., Hashemabad, S.K., Vu, D.M., Soneru, A.R., Fujita, A., Wang, M., Elze, T., Eslami, M. and Zebardast, N. PyGlaucoMetrics: A Stacked Weight-Based Machine Learning Approach for Glaucoma Detection Using Visual Field Data. Medicina, 61(3), 541. https://doi.org/10.3390/medicina61030541
-
Eslami et al. (2023) — PyVisualFields: Eslami, M., Kazeminasab, S., Sharma, V., Li, Y., Fazli, M., Wang, M., Zebardast, N. and Elze, T. PyVisualFields: A Python Package for Visual Field Analysis. Trans. Vis. Sci. Tech., 12(2), 6. https://doi.org/10.1167/tvst.12.2.6
-
Moradi et al. (2024) — ARVO abstract: Moradi, M. et al. PyGlaucoMetrics: An Open-Source Multi-Criteria Glaucoma Defect Evaluation. Investigative Ophthalmology & Visual Science, 65(7), OD38. https://iovs.arvojournals.org/article.aspx?articleid=2800368
Links
- PyPI: https://pypi.org/project/PyGlaucoMetrics/
- GitHub: https://github.com/Mousamoradi/PyGlaucoMetrics
- PyVisualFields: https://pypi.org/project/PyVisualFields/
License
MIT License — see LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyglaucometrics-1.0.3.tar.gz.
File metadata
- Download URL: pyglaucometrics-1.0.3.tar.gz
- Upload date:
- Size: 571.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb6f4e8a80b20aeda5153e217de4ffe6049b20018962bb55f356ebe63b39ab04
|
|
| MD5 |
c2f9a910955fb30b831ad7cf6431e9a9
|
|
| BLAKE2b-256 |
a489039dd71977154e84192fd49a4b86d5ff930cc5313e20bf92636e8bdb53d8
|
File details
Details for the file pyglaucometrics-1.0.3-py3-none-any.whl.
File metadata
- Download URL: pyglaucometrics-1.0.3-py3-none-any.whl
- Upload date:
- Size: 580.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5717af3aafe0d5f6599f78d595bf3dbf2758aa420637438aa2486f20f37e0ead
|
|
| MD5 |
8c36e94da4dc5847fafc33353d555005
|
|
| BLAKE2b-256 |
3d6f4fc36859e2ef67953f801ecf56b36ad6baf01d9a9e7f93045ec8b9755a85
|