Skip to main content

gliostitch

Reproducible cohort selection over four public glioma MRI datasets — stitched into one manifest of facts, with a study definition layered on top.

Assembling a multi-cohort GBM study means reconciling four different directory layouts, four clinical CSV conventions, three ID formats, two segmentation label schemes, and an unknown number of patients who appear in more than one dataset. Most of that work gets done once, in a notebook, and is difficult to reproduce six months later.

This project does it as a pipeline. It emits one manifest of facts about every imaging session, and a separate layer that turns those facts into a cohort according to a named, versioned study definition. The split matters: the manifest never changes when the research question does.

1661 imaging sessions  →  study definition  →  502 sessions (377 training / 125 external)
                                                with a reason attached to all 1159 exclusions

Datasets: BraTS-2020 · UCSF-PDGM · UPENN-GBM · RHUH-GBM (not redistributed — you supply the data and configure its location)


Install

pip install gliostitch              # selection + path resolution
pip install "gliostitch[pipeline]"  # + build the manifest yourself
pip install "gliostitch[load]"      # + read NIfTI volumes
pip install "gliostitch[monai]"     # + framework backends: monai / torchio / torch

The core is pandas, numpy and pydantic only. If you just want to query a manifest someone else built, you never install the pipeline.


Quickstart

Build the manifest

Point config/pipeline.yaml at your dataset roots, then:

gliostitch verify-layout   # check the directories before doing any work
gliostitch build           # → output/master_manifest.csv

Select a cohort

from gbm_os import Cohort
from gbm_os.studies import GBM_OS_STUDY

cohort = Cohort.from_manifest(
    "output/master_manifest.csv",
    data_roots={"brats2020": "/data/BraTS-2020", ...},
)

view = GBM_OS_STUDY.apply(cohort)
print(len(view))                      # 502

for spec in view:                     # SampleSpec: resolved paths + clinical metadata
    print(spec.paths["t1ce"], spec.os_days, spec.os_class)

Or express criteria directly — all optional, all composable:

view = cohort.select(
    datasets=["ucsf_pdgm", "rhuh_gbm"],
    baseline_only=True,
    require_complete=True,
    filters={"eor": "GTR", "who_grade": [4, None]},
    where=lambda r: r["age"] is not None and r["age"] >= 18,
    resolve_duplicates="drop",
)

Load it

ds = view.to_monai()          # or .to_torchio() / .to_torch()
folds = view.split(k=5, seed=42)      # stratified, patient-grouped, deterministic
train = folds.fold(0, "train")

Why it is built this way

The manifest records facts, not decisions. One row per imaging session, 31 columns, covering identity, paths, modality presence, and normalised clinical values. It does not store os_class, is_baseline or partition — those are modelling choices, derived at load time. A fact discarded at ingest is unrecoverable; a derivation recomputed on load costs milliseconds.

A study is a separate, versioned object. Eligibility criteria, survival thresholds and the held-out cohort live in gbm_os.studies, declaratively — no lambdas, so a definition can be printed, diffed and pasted into a methods section.

$ gliostitch studies gbm-os
gbm-os v2
Overall-survival classification over baseline preoperative GBM MRI, held out on UPENN-GBM.

Eligibility:
  - baseline session only (session_index == 0)
  - all four structural modalities present
  - eor == 'GTR'
  - who_grade in [4, None]
  - has_os == True

Changing the study cannot change the manifest — building under a different one produces a byte-identical CSV. That property is enforced by a test.

Every exclusion is accounted for. Selection records what each criterion removed, so a cohort table is derivable rather than asserted:

>>> print(view.provenance())
input                      1661
baseline_only              1661 →   1521  (−140)
require_complete           1521 →   1126  (−395)
filter:eor                 1126 →    526  (−600)
filter:who_grade            526 →    509  (−17)
filter:has_os               509 →    503  (−6)
resolve_duplicates          503 →    502  (−1)
selected                    502

>>> view.exclusions()      # every dropped session, tagged with its reason

len(view) + len(view.exclusions()) always equals the input.

Duplicates are annotated, never deleted. Patients appearing in more than one dataset are flagged with a group id and a confidence level. Which copy to keep is a selection policy, not a manifest edit.


Documentation

Architecture How the two packages relate and which one a change belongs in
Extending Adding a dataset, column, study, criterion or backend
Design decisions Why it is shaped this way, and what breaks if reversed
Versioning Release process, and which number to bump
Usage notebook Worked end-to-end walkthrough

Development

source activate.sh
pytest                   # 246 tests
pytest tests/manifest    # pipeline only — runs against a synthetic dataset tree,
                         # no real data needed, ~1 s

The pipeline suite builds a miniature four-dataset tree on the fly and runs the real adapters against it, so join contracts are testable without access to the MRI data. Tests that need a built manifest skip themselves with a reason.


Status

Beta. The cohort figures above are current as of the latest entry in CHANGELOG.md, which records data-affecting changes separately from code changes — a fix that moves a cohort count is breaking for anyone who published against the old one.

Citation

If you use this in published work, please cite it. GitHub's Cite this repository button reads CITATION.cff and will produce BibTeX or APA for you.

Lim, Wei Xin (Davian). gliostitch: reproducible cohort selection over public glioma MRI datasets, version 0.1.0, 2026. https://github.com/realdavian/gliostitch

ORCID: 0009-0005-2683-1528

Please also cite the source datasets — BraTS-2020, UCSF-PDGM, UPENN-GBM and RHUH-GBM each have their own citation requirements, and this project redistributes none of them.

Licence

GNU General Public License v3.0 or later.

You may use, modify and redistribute this software, including commercially. If you distribute a modified version, or software that incorporates this one, that work must also be released under the GPL. Running it to produce research results places no obligation on your results — only on distributed software.

Metadata

Release files for gliostitch 0.1.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 gliostitch 0.1.0
File Size Uploaded Provenance
gliostitch-0.1.0.tar.gz 59.1 kB With provenance Details

Built distribution (wheel)

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

Total release size: 136.5 kB

Release files / gliostitch-0.1.0.tar.gz

Download URL gliostitch-0.1.0.tar.gz
Size 59.1 kB
Tags Source
SHA-256 checksum
How to use checksums
92944156d8c526664cbfcc705df5b69df000e6794075ef0d33f402139288eb16
BLAKE2b-256 checksum
How to use checksums
0be55d01f3a641fba06da1a14f5610c08dc9fc2dcdc491dc5e2191eed94e521d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 20, 2026.

Transparency log

Release files / gliostitch-0.1.0-py3-none-any.whl

Download URL gliostitch-0.1.0-py3-none-any.whl
Size 77.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b616d50a246449e24e887f03444bacf48c6563fcde742a23ee1e6bfad46c9ed0
BLAKE2b-256 checksum
How to use checksums
cc2c2e8d7ecf30d0a10ac6254326fe0c6fdf798b827be642b6900cdba5eeb4ca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 20, 2026.

Transparency log

Security for gliostitch 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for gliostitch-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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