Skip to content
Draft

Paper #244

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
fa61064
Merge branch 'release' of github.com:biomarkersParkinson/paradigma
Erikpostt Aug 20, 2025
b9d137e
Add markdown, bibliography and pdf to repo
Erikpostt Aug 20, 2025
e546953
Add workflow for automatic .pdf creation
Erikpostt Aug 20, 2025
c3852e2
Remove .pdf to let workflow automatically generate new one
Erikpostt Aug 20, 2025
335eb2a
Fix author typo in bibliography
Erikpostt Aug 20, 2025
9251e5b
Add acknowledgements section
Erikpostt Aug 20, 2025
bcfaa8e
Add doi for GGIR, remove abstracts from bib
Erikpostt Sep 4, 2025
daa1be3
Remove doi prefix
Erikpostt Sep 4, 2025
8ddd659
Merge branch 'main' of github.com:biomarkersParkinson/paradigma into …
Erikpostt Dec 5, 2025
01a601b
Solve feedback #238
Erikpostt Dec 5, 2025
8360403
Add example data and plotting notebook
Erikpostt Dec 5, 2025
b234eb3
add sample data, update figure resolution
Erikpostt Dec 11, 2025
8427940
Rephrase to Parkinson's after internal consultation
Erikpostt Dec 11, 2025
ed01fff
Add cross-OS testing, split by test/quality
Erikpostt Dec 23, 2025
ae30f22
Update dependencies
Erikpostt Dec 23, 2025
1d150ad
Ensure consistency in docstrings
Erikpostt Dec 23, 2025
ec88a83
Modify ruff for linting
Erikpostt Dec 23, 2025
5ba9f99
Clarify testing Python vs
Erikpostt Dec 23, 2025
eedecda
Apply pre-commit hooks
Erikpostt Dec 23, 2025
2a05275
Update np.trapz to np.trapezoid for numpy v2.X
Erikpostt Dec 23, 2025
dfbabca
Remove inaccurate claims
Erikpostt Jan 9, 2026
7a0a83f
fix: Final black formatting
Erikpostt Jan 11, 2026
3e3c75f
Fix syntax errors and code formatting in pipeline implementation
Erikpostt Jan 12, 2026
af972dc
Fix code formatting
Erikpostt Jan 12, 2026
9acff40
Merge branch 'main' of github.com:biomarkersParkinson/paradigma into …
Erikpostt Jan 14, 2026
355aa92
Update tutorials, shorten readme, add guides, expand orchestrator
Erikpostt Jan 14, 2026
1f9c17a
Update dependencies, add physilog test data
Erikpostt Jan 15, 2026
900d348
Bump
Erikpostt Jan 15, 2026
2a02a72
Bump
Erikpostt Jan 15, 2026
2ce56a0
Resolve raised issues by copilot in PR
Erikpostt Jan 15, 2026
87f352e
Re-build docs with verbose added
Erikpostt Jan 15, 2026
eef4bc3
Modify codebase to reviewer suggestions
Erikpostt Jan 23, 2026
f1a49f7
fix: Track test_file.parquet with Git LFS
Erikpostt Jan 26, 2026
5e4083d
Update readme and docs based on internal feedback
Erikpostt Jan 26, 2026
b43f53b
Update documentation slightly
Erikpostt Jan 27, 2026
98c3fce
Always create output dir for logging
Erikpostt Jan 28, 2026
d58f3a1
Ensure single file to preserve memory efficiency
Erikpostt Jan 28, 2026
71d70ed
Move to single-file handling
Erikpostt Jan 28, 2026
f994df4
Ensure single file to preserve memory efficiency
Erikpostt Jan 28, 2026
8309450
Resolve merge conflicts
Erikpostt Jan 28, 2026
39f4b54
Update paper.md (#275)
Kevin-Mattheus-Moerman Mar 25, 2026
41c7fb7
Fix title formatting in paper.md (block scalar to resolve conflict wi…
Erikpostt Mar 25, 2026
390958f
Remove corrupted test data files before merging main
Erikpostt Mar 25, 2026
87c3189
Merge main: accept main version of code, docs, and data files
Erikpostt Mar 25, 2026
35270a3
Restore paper submission materials to paper branch
Erikpostt Mar 25, 2026
fda4558
Update ORCIDs, add two references of preprints
Erikpostt Mar 25, 2026
0b925f5
Merge branch 'paper' of github.com:biomarkersParkinson/paradigma into…
Erikpostt Mar 25, 2026
63a761d
Resolve merge conflicts: remove corrupted test data directories
Erikpostt Mar 25, 2026
4befeca
Update ORCIDs, add two references of preprints
Erikpostt Mar 25, 2026
107986f
Merge main into paper
Erikpostt Mar 25, 2026
04d4d65
Update reference mijnsbergen
Erikpostt Mar 25, 2026
3b6879f
Align paper with archive
Erikpostt Mar 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 16 additions & 23 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
name: Build and test

on:
push:
branches: [ main ]
branches: [ main, paper ]
pull_request:
branches: [ '**' ]
workflow_call:
outputs:
version:
description: "The version retrieved from the pyproject.toml file."
value: ${{ jobs.build-and-test.outputs.version }}
value: ${{ jobs.quality.outputs.version }}

jobs:
build-and-test:
quality:
name: Quality checks (lint, build, docs)
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.12']
defaults:
run:
shell: bash
outputs:
version: ${{ steps.get_version.outputs.version }}

Expand All @@ -25,43 +24,37 @@ jobs:
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
python-version: '3.12'

# Get the version from pyproject.toml
# This will be used to tag the release in the publishing workflow
- name: Install toml package
- name: Install toml
run: pip install toml

- name: Get version from pyproject.toml
id: get_version
run: |
VERSION=$(python -c "import toml; print(toml.load('pyproject.toml')['tool']['poetry']['version'])")
echo Version: $VERSION
echo "version=$VERSION" >> $GITHUB_OUTPUT

# Install project dependencies
- name: Install dependencies
run: |
python -m pip install poetry
poetry install

# Run pre-commit hooks (formatting, linting, YAML checks, etc.)
- name: Run pre-commit hooks
run: poetry run pre-commit run --all-files --show-diff-on-failure

# Run tests
- name: Run pytest
run: poetry run pytest --maxfail=1 --disable-warnings -q

# Build the package
- name: Build package
run: poetry build

- name: Build documentation
run: poetry run make html --directory docs

- name: Archive build artifacts
uses: actions/upload-artifact@v4
if: github.ref == 'refs/heads/release'
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: dist/
Expand All @@ -71,8 +64,8 @@ jobs:
run: poetry run build-docs --dev

- name: Archive documentation
uses: actions/upload-artifact@v4
if: github.ref == 'refs/heads/release'
uses: actions/upload-artifact@v4
with:
name: docs-html
path: docs/_build/html/
24 changes: 24 additions & 0 deletions .github/workflows/draft-pdf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Draft PDF
on: [push]

jobs:
paper:
runs-on: ubuntu-latest
name: Paper Draft
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build draft PDF
uses: openjournals/openjournals-draft-action@master
with:
journal: joss
# This should be the path to the paper within your repo.
paper-path: paper/paper.md
- name: Upload
uses: actions/upload-artifact@v4
with:
name: paper
# This is the output path where Pandoc will write the compiled
# PDF. Note, this should be the same directory as the input
# paper.md
path: paper/paper.pdf
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ site/
# =========================
# Project-specific / temporary
# =========================
paper/
tests/data/tmp

# =========================
Expand Down
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ repos:
hooks:
- id: ruff
args: ["--fix"]
typs: [python]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
Expand Down
6 changes: 5 additions & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cff-version: 1.3.1
title: >-
ParaDigMa: A toolbox for deriving Parkinson's disease Digital Markers from real-life wrist sensor data
ParaDigMa: a Python toolbox for extracting Parkinson's disease digital biomarkers
from daily life wrist sensor data
message: >-
If you use this software, please cite it using the
metadata from this file.
Expand Down Expand Up @@ -39,6 +40,7 @@ authors:
Center for Engineering, Modeling and Applied Social
Sciences (CECS), Federal University of ABC (UFABC),
Brazil
orcid: 'https://orcid.org/0000-0002-9804-7477'

- given-names: Vedran
family-names: Kasalica
Expand All @@ -64,11 +66,13 @@ authors:
affiliation: >-
Radboud University Medical Center, Nijmegen,
Netherlands
orcid: 'https://orcid.org/0000-0002-6371-3337'

- given-names: Max A.
family-names: Little
email: max.a.little@gmail.com
affiliation: University of Birmingham
orcid: 'https://orcid.org/0000-0002-1507-3822'

- given-names: Jordan P.
family-names: Raykov
Expand Down
33 changes: 25 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,33 @@ For other issues, check our [issue tracker](https://github.com/biomarkersParkins

The following publications contain details and validation of the pipelines:

**Arm swing during gait**
* [Post, E. et al. (2025) - Quantifying arm swing in Parkinson's disease: a method account for arm activities during free-living gait](https://doi.org/10.1186/s12984-025-01578-z)
* [Post, E. et al. (2026) - (Pre-print) Longitudinal progression of digital arm swing measures during free-living gait in early Parkinson's disease](https://doi.org/10.64898/2026.01.06.26343500)
All pipelines require data from a wrist-worn sensor with:

**Tremor**
* [Timmermans, N.A. et al. (2025) - A generalizable and open-source algorithm for real-life monitoring of tremor in Parkinson's disease](https://doi.org/10.1038/s41531-025-01056-2)
* [Timmermans, N.A. et al. (2025) - (Pre-print) Progression of daily-life tremor measures in early Parkinson disease: a longitudinal continuous monitoring study](https://www.medrxiv.org/content/10.64898/2025.12.23.25342892v1)
- **Sensor Position**: Either wrist (left or right)
- **Population**: Persons with Parkinson's disease
- **Data Quality**: Strictly increasing timestamps
- **Orientation**: Standardized coordinate system (see [Coordinate System Guide](coordinate_system.md))

**Pulse rate**
* [Veldkamp, K.I. et al. (2025) - Heart rate monitoring using wrist photoplethysmography in Parkinson disease: feasibility and relation with autonomic dysfunction](https://doi.org/10.1101/2025.08.15.25333751)
ParaDigMa is designed to work on prepared sensor data of any device, but it has been emperically validated on:

- **Verily Study Watch** (gait, tremor, pulse rate)
- **Axivity AX6** (gait, tremor)
- **Gait-up Physilog 4** (gait, tremor)
- **Empatica EmbracePlus** (data loading)

See [sensor requirements guide](https://biomarkersparkinson.github.io/paradigma/guides/sensor_requirements.html) for more details on requirements; see [supported devices guide](https://biomarkersparkinson.github.io/paradigma/guides/supported_devices.html) for details on device-specific usage.

## Scientific Validation

ParaDigMa pipelines are validated in peer-reviewed publications:

| Pipeline | Publication |
|----------|-------------|
| **Arm swing during gait** | Post et al. (2025, 2026) |
| **Tremor** | Timmermans et al. (2025a, 2025b) |
| **Pulse rate** | Veldkamp et al. (2025) |

See the [validation guide](https://biomarkersparkinson.github.io/paradigma/guides/validation.html) for full publication details.


## Contributing
Expand Down
56 changes: 56 additions & 0 deletions docs/guides/validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Scientific Validation

ParaDigMa pipelines have been scientifically validated through rigorous testing on real-world datasets in published peer-reviewed studies. This document provides an overview of the validation evidence.

## Validation Overview

ParaDigMa offers three validated processing pipelines for extracting digital biomarkers from wrist sensor data in Parkinson's disease. Details on publications are shown below.

### Arm Swing during Gait

**Post, E. et al. (2025)**
- **Title**: Quantifying arm swing in Parkinson's disease: a method account for arm activities during free-living gait
- **Journal**: Journal of NeuroEngineering and Rehabilitation
- **DOI**: https://doi.org/10.1186/s12984-025-01578-z

**Post, E. et al. (2026)**
- **Title**: Longitudinal progression of digital arm swing measures during free-living gait in early Parkinson's disease
- **Status**: Pre-print
- **DOI**: https://doi.org/10.64898/2026.01.06.26343500

### Tremor

**Timmermans, N.A. et al. (2025)**
- **Title**: A generalizable and open-source algorithm for real-life monitoring of tremor in Parkinson's disease
- **Journal**: npj Parkinson's Disease
- **DOI**: https://doi.org/10.1038/s41531-025-01056-2

**Timmermans, N.A. et al. (2025)**
- **Title**: Progression of daily-life tremor measures in early Parkinson disease: a longitudinal continuous monitoring study
- **Status**: Pre-print
- **DOI**: https://www.medrxiv.org/content/10.64898/2025.12.23.25342892v1

### Pulse Rate

**Veldkamp, K.I. et al. (2025)**
- **Title**: Heart rate monitoring using wrist photoplethysmography in Parkinson disease: feasibility and relation with autonomic dysfunction
- **Status**: Pre-print
- **DOI**: https://doi.org/10.1101/2025.08.15.25333751

## Important Caveats

> [!WARNING]
> While ParaDigMa has been validated in published research, the following limitations should be considered:
>
> 1. **Device-Specific Validation**: Formal validation is limited to Gait-up Physilog 4 and Verily Study Watch
> 2. **Population**: Validation primarily in persons with early-to-moderate PD; extrapolation to advanced stages requires caution
> 3. **Wrist Placement**: Some measures show different sensitivity depending on whether the sensor is on the most or least affected side
> 4. **Data Quality**: All validation studies assume high-quality sensor data with sufficient compliance; poor data quality may affect results
> 5. **Generalization**: While algorithms are designed to be generalizable, use on new devices should be validated by the user

## Best Practices

1. **Data Quality**: Ensure sensor compliance (minimum wearing time, data continuity)
2. **Validation**: For new devices or populations, conduct local validation studies
3. **Documentation**: Record device model, firmware, wearing location, and collection protocol
4. **Reproducibility**: Share data and analysis code to enable reproducibility and validation
53 changes: 53 additions & 0 deletions paper/code_and_data/example_arm_swing_tremor.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
week,median_rom,95p_rom,Tremor time,Modal tremor power,90th percentile of tremor power
2,14.063698465497058,25.11725739294099,31.509316258953632,0.5157667756167951,0.5894862807236706
4,9.623803132342964,23.42999621990865,8.934828259402014,0.006964342050393868,1.341321100836319
6,11.609110476111322,24.265030707173814,37.786937441114645,0.20594503502792336,1.110153685178083
8,17.412487770268687,27.02688546085788,18.48695848565883,0.8046583599469156,0.9791448712486097
10,17.42401117908109,28.330703583987354,16.919580498235547,-0.5148744255253643,0.4434269665709303
12,15.659213623854829,31.004316688880632,31.28970845677863,0.36185044546168055,0.3987016161669699
14,15.871866094465345,32.29630779397007,25.48872635185473,0.37378322122190166,1.4565799981567833
16,18.03149829506909,27.774675288051334,32.78086070766597,0.09371462061329168,1.5804914375051582
18,17.57183071528083,27.188837544177932,19.515380889449343,0.03897713403426349,1.8226711861732126
20,13.261960252850825,22.791502087793887,62.618871205940536,0.07385130606636338,1.571817085660392
22,16.641493819332652,24.859415290544504,24.908293109839736,0.4481452522510748,0.7716155921786618
24,15.209776696928596,22.04664459311973,28.8005165649379,-0.517022861863033,1.3950010320698207
26,14.626900064010451,26.734138625051834,29.30629619515508,0.09793934910193358,1.126718209577575
28,10.742208943348697,17.544749923983478,23.843882801728043,0.05608916313450325,1.6866383761152877
30,13.02956313080337,21.98003631478054,35.26158156511925,-0.03404702123100922,1.1729201271438394
32,14.730336455085522,26.833691566723697,34.686305018872886,0.20504761839995156,1.0641757446224969
34,12.312871471709778,20.93541272083357,46.57616507485811,-0.22455502977141717,1.4704037260394824
36,14.21061182034899,15.906160011971949,41.458517291521744,0.49565927701899704,1.614406750196181
38,13.654241782385478,22.160648379140202,36.18158532556405,0.540071332890852,1.0457374796347172
40,14.766984562559061,32.16573786319236,30.799579795617085,-0.012055033812627236,1.828748860702618
42,11.505856164320868,22.327037097218295,28.850543766542167,-0.386757450974094,1.8473586688252195
44,13.510632055006194,17.83689503557449,36.750373720877036,0.1331555360071351,0.9051149693780386
46,10.742695643051844,19.177171944058454,39.09177452136794,0.5036035641328648,1.5330122519909757
48,7.7836787806312255,20.298901764773397,53.87593378311031,0.7013590184881651,1.4066420893087486
50,10.320307683149089,25.239306025871148,21.359521413009077,0.35157204388304675,2.4081434194826032
52,14.03089387461516,20.590233711647496,51.991514378738806,-0.011816978912036813,0.9424396589066156
54,13.028258846351754,22.38724023232427,43.58256529613727,0.3917317579836822,1.5901196856680255
56,10.074367314263258,18.664652798858015,42.19656994737066,0.43612075796864647,2.333459176770986
58,8.903233558686917,19.647734165971368,44.233716197222265,1.0368780152275117,1.7663988441160163
60,8.665484753063163,15.610171380988664,65.92162142053776,0.7161473608868426,2.3666616694981166
62,12.31442031167999,17.91298921912596,47.16006162829853,0.2629391945611494,2.4122449221108506
64,8.633120895528245,19.285220526222712,70.41881308356614,0.8106804987085826,1.8749706897171314
66,5.646255456615746,18.21946385170942,56.410711311150244,0.9552471118231376,2.714541622642977
68,7.545543664289485,24.686979086434633,67.40712220150017,0.7326670885465636,2.570683238010141
70,12.21502917552369,19.98292336368996,69.72631326333398,1.095728570131417,2.6978007529590284
72,14.175138935207885,19.004278711515166,62.48534394602318,1.3610651789988317,1.8364881415050274
74,9.82524813040465,18.12311605153331,39.6762646050514,0.5126612737271343,3.1597027676622895
76,9.642081116521647,18.151780583521884,54.96217796344953,1.5018991836072353,2.136018901698529
78,12.297342934063602,22.941312220404328,81.27252816832566,1.2974040656815764,2.960189780449548
80,12.303773412706478,19.274078117883697,68.87953817395777,1.5129762876844348,3.213958686028462
82,11.987456455315213,19.024718813796866,70.45404363251903,1.4841685324675558,2.642355870891909
84,14.533387837651759,18.41849642401664,92.12967973122079,1.3776804104271743,3.197943787769014
86,11.704185663972712,21.03358964109759,90.94134414228839,1.6618585070250576,3.5023211655279947
88,12.790452497802274,14.94846887109603,71.86835835937846,1.6912334262629483,2.829085411661269
90,13.542397501815492,17.4588990705185,72.15746100117788,1.5232119455879163,3.482474962461197
92,15.321618943693903,17.01173674375007,89.54205128133046,1.2602202614545808,3.223936291132102
94,7.59596896296431,17.695274519553127,76.60714946041783,2.515846861790992,3.6194619433543784
96,14.369463974969863,21.790655213711833,82.70508629215512,1.931961279168552,3.7180544789965286
98,,,69.3194872661142,1.4020076687727485,3.7774517065251865
100,,,,,
102,,,,,
104,,,,,
62 changes: 62 additions & 0 deletions paper/code_and_data/plot_longitiudinal_example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {},
"source": [
"# Plot longitudinal example\n",
"This notebook plots biweekly digital measures of tremor and arm swing of an individual\n",
"participant of the Personalized Parkinson Project. Note that we've added random normal \n",
"noise based on the standard deviation to optimize anonymization."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import pandas as pd\n",
"import seaborn as sns\n",
"\n",
"df_subject = pd.read_csv(\"example_arm_swing_tremor.csv\")\n",
"\n",
"# set Seaborn theme for aesthetics\n",
"sns.set_theme(style='whitegrid', context='talk')\n",
"\n",
"# select measures to plot\n",
"arm_swing_measure = '95p_rom'\n",
"tremor_measure = 'Tremor time'\n",
"\n",
"# fetch data to plot\n",
"weeks = df_subject['week'].values\n",
"arm_swing_values = df_subject[arm_swing_measure].values\n",
"tremor_values = df_subject[tremor_measure].values\n",
"\n",
"# plotting\n",
"fig, ax = plt.subplots(figsize=(14, 6))\n",
"\n",
"sns.lineplot(x=weeks, y=tremor_values, label='Tremor time [% of inactive time]',\n",
" marker='o', color='crimson', linewidth=2.5)\n",
"sns.lineplot(x=weeks, y=arm_swing_values,\n",
" label='95th percentile arm swing range of motion [degrees]', marker='o',\n",
" color='steelblue', linewidth=2.5)\n",
"\n",
"ax.set_xlabel('Time [weeks]', fontsize=18)\n",
"ax.set_ylabel('Measurement value', fontsize=18)\n",
"ax.legend(loc='upper left', fontsize=16, frameon=True, framealpha=0.9)\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"fig.savefig('../imgs/example-digital-biomarkers.png', dpi=300)"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 5
}
Binary file added paper/imgs/example-digital-biomarkers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added paper/imgs/pipeline-architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading