manifold-genetics 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- manifold_genetics-0.2.0/.flake8 +3 -0
- manifold_genetics-0.2.0/.gitignore +196 -0
- manifold_genetics-0.2.0/CHANGELOG.md +164 -0
- manifold_genetics-0.2.0/LICENSE +28 -0
- manifold_genetics-0.2.0/PKG-INFO +607 -0
- manifold_genetics-0.2.0/README.md +551 -0
- manifold_genetics-0.2.0/pyproject.toml +141 -0
- manifold_genetics-0.2.0/scripts/__init__.py +0 -0
- manifold_genetics-0.2.0/scripts/check_sensitive_files.py +281 -0
- manifold_genetics-0.2.0/src/manifold_genetics/__init__.py +31 -0
- manifold_genetics-0.2.0/src/manifold_genetics/admixture/__init__.py +17 -0
- manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/__init__.py +13 -0
- manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/base.py +86 -0
- manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/fake.py +167 -0
- manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/neural.py +419 -0
- manifold_genetics-0.2.0/src/manifold_genetics/admixture/backends/precomputed.py +196 -0
- manifold_genetics-0.2.0/src/manifold_genetics/admixture/neural.py +150 -0
- manifold_genetics-0.2.0/src/manifold_genetics/cli.py +1533 -0
- manifold_genetics-0.2.0/src/manifold_genetics/embeddings/__init__.py +9 -0
- manifold_genetics-0.2.0/src/manifold_genetics/embeddings/base.py +154 -0
- manifold_genetics-0.2.0/src/manifold_genetics/embeddings/diffusion_map.py +225 -0
- manifold_genetics-0.2.0/src/manifold_genetics/embeddings/phate.py +191 -0
- manifold_genetics-0.2.0/src/manifold_genetics/embeddings/tsne.py +139 -0
- manifold_genetics-0.2.0/src/manifold_genetics/embeddings/umap.py +143 -0
- manifold_genetics-0.2.0/src/manifold_genetics/metrics/__init__.py +9 -0
- manifold_genetics-0.2.0/src/manifold_genetics/metrics/admixture.py +190 -0
- manifold_genetics-0.2.0/src/manifold_genetics/metrics/geographic.py +157 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/__init__.py +5 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/backends/__init__.py +6 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/backends/base.py +79 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/backends/sklearn_backend.py +262 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/flashpca.py +498 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/flashpca_format.py +150 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/plink.py +157 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pca/standardize.py +78 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/__init__.py +7 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/config.py +226 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/configfile.py +268 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/orchestrator.py +424 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/result.py +70 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/runner.py +206 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/__init__.py +64 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/admixture.py +133 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/embedding.py +183 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/metrics.py +122 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/paths.py +59 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/pca.py +131 -0
- manifold_genetics-0.2.0/src/manifold_genetics/pipeline/steps/viz.py +262 -0
- manifold_genetics-0.2.0/src/manifold_genetics/py.typed +0 -0
- manifold_genetics-0.2.0/src/manifold_genetics/utils/__init__.py +0 -0
- manifold_genetics-0.2.0/src/manifold_genetics/utils/filter_duplicates.py +202 -0
- manifold_genetics-0.2.0/src/manifold_genetics/utils/io.py +408 -0
- manifold_genetics-0.2.0/src/manifold_genetics/utils/tools.py +579 -0
- manifold_genetics-0.2.0/src/manifold_genetics/utils/validation.py +509 -0
- manifold_genetics-0.2.0/src/manifold_genetics/visualization/__init__.py +21 -0
- manifold_genetics-0.2.0/src/manifold_genetics/visualization/plotting.py +1392 -0
- manifold_genetics-0.2.0/tests/__init__.py +6 -0
- manifold_genetics-0.2.0/tests/conftest.py +270 -0
- manifold_genetics-0.2.0/tests/fixtures/admixture/README.md +58 -0
- manifold_genetics-0.2.0/tests/fixtures/admixture/fit.2.csv +51 -0
- manifold_genetics-0.2.0/tests/fixtures/admixture/fit.3.csv +51 -0
- manifold_genetics-0.2.0/tests/fixtures/admixture/project.2.csv +51 -0
- manifold_genetics-0.2.0/tests/fixtures/admixture/project.3.csv +51 -0
- manifold_genetics-0.2.0/tests/fixtures/cross_cohort/README.md +12 -0
- manifold_genetics-0.2.0/tests/fixtures/cross_cohort/fit_colormap.json +9 -0
- manifold_genetics-0.2.0/tests/fixtures/cross_cohort/fit_labels.csv +51 -0
- manifold_genetics-0.2.0/tests/fixtures/cross_cohort/generate.py +65 -0
- manifold_genetics-0.2.0/tests/fixtures/cross_cohort/geographic.csv +51 -0
- manifold_genetics-0.2.0/tests/fixtures/cross_cohort/project_colormap.json +9 -0
- manifold_genetics-0.2.0/tests/fixtures/cross_cohort/project_labels.csv +51 -0
- manifold_genetics-0.2.0/tests/integration/__init__.py +0 -0
- manifold_genetics-0.2.0/tests/integration/cohorts.py +152 -0
- manifold_genetics-0.2.0/tests/integration/submit_cohort_tests.sh +112 -0
- manifold_genetics-0.2.0/tests/integration/test_cohort_pipeline_real.py +279 -0
- manifold_genetics-0.2.0/tests/integration/test_cohort_preflight.py +217 -0
- manifold_genetics-0.2.0/tests/integration/test_cohort_registry.py +161 -0
- manifold_genetics-0.2.0/tests/integration/test_filter_duplicates_real_data.py +209 -0
- manifold_genetics-0.2.0/tests/integration/test_generic_pipeline.py +311 -0
- manifold_genetics-0.2.0/tests/integration/test_hgdp_pipeline_real.py +172 -0
- manifold_genetics-0.2.0/tests/integration/test_hgdp_reproducibility.py +106 -0
- manifold_genetics-0.2.0/tests/integration/test_integration.py +107 -0
- manifold_genetics-0.2.0/tests/integration/test_pca_flashpca_parity.py +341 -0
- manifold_genetics-0.2.0/tests/integration/test_pipeline_contract.py +230 -0
- manifold_genetics-0.2.0/tests/integration/test_sdist_contents.py +132 -0
- manifold_genetics-0.2.0/tests/science.py +101 -0
- manifold_genetics-0.2.0/tests/slow/__init__.py +0 -0
- manifold_genetics-0.2.0/tests/test_api.py +150 -0
- manifold_genetics-0.2.0/tests/test_cli.py +177 -0
- manifold_genetics-0.2.0/tests/test_metrics.py +346 -0
- manifold_genetics-0.2.0/tests/unit/__init__.py +0 -0
- manifold_genetics-0.2.0/tests/unit/test_admixture_backends.py +261 -0
- manifold_genetics-0.2.0/tests/unit/test_admixture_backends_coverage.py +174 -0
- manifold_genetics-0.2.0/tests/unit/test_admixture_batch_size_default.py +76 -0
- manifold_genetics-0.2.0/tests/unit/test_cli_main.py +830 -0
- manifold_genetics-0.2.0/tests/unit/test_cli_run_command.py +149 -0
- manifold_genetics-0.2.0/tests/unit/test_config_file.py +249 -0
- manifold_genetics-0.2.0/tests/unit/test_embeddings.py +119 -0
- manifold_genetics-0.2.0/tests/unit/test_embeddings_wrapper.py +225 -0
- manifold_genetics-0.2.0/tests/unit/test_filter_duplicates.py +462 -0
- manifold_genetics-0.2.0/tests/unit/test_filter_duplicates_main.py +97 -0
- manifold_genetics-0.2.0/tests/unit/test_flashpca_format.py +147 -0
- manifold_genetics-0.2.0/tests/unit/test_io.py +241 -0
- manifold_genetics-0.2.0/tests/unit/test_io_helpers.py +195 -0
- manifold_genetics-0.2.0/tests/unit/test_metrics_edgecases.py +125 -0
- manifold_genetics-0.2.0/tests/unit/test_orchestrator.py +986 -0
- manifold_genetics-0.2.0/tests/unit/test_package_metadata.py +148 -0
- manifold_genetics-0.2.0/tests/unit/test_pca_backend_plumbing.py +59 -0
- manifold_genetics-0.2.0/tests/unit/test_pca_backend_selection.py +123 -0
- manifold_genetics-0.2.0/tests/unit/test_pca_backend_sklearn.py +186 -0
- manifold_genetics-0.2.0/tests/unit/test_pca_fit_memory_budget.py +85 -0
- manifold_genetics-0.2.0/tests/unit/test_pca_python_checkpoint.py +132 -0
- manifold_genetics-0.2.0/tests/unit/test_pca_standardize.py +111 -0
- manifold_genetics-0.2.0/tests/unit/test_pca_streaming_fit.py +100 -0
- manifold_genetics-0.2.0/tests/unit/test_pipeline_config.py +228 -0
- manifold_genetics-0.2.0/tests/unit/test_pipeline_result.py +230 -0
- manifold_genetics-0.2.0/tests/unit/test_plink_reader.py +96 -0
- manifold_genetics-0.2.0/tests/unit/test_plotting_coverage.py +299 -0
- manifold_genetics-0.2.0/tests/unit/test_plotting_projection.py +309 -0
- manifold_genetics-0.2.0/tests/unit/test_preset_naming.py +94 -0
- manifold_genetics-0.2.0/tests/unit/test_runner.py +136 -0
- manifold_genetics-0.2.0/tests/unit/test_science_assertions.py +131 -0
- manifold_genetics-0.2.0/tests/unit/test_sensitive_file_check.py +244 -0
- manifold_genetics-0.2.0/tests/unit/test_setup_logging.py +88 -0
- manifold_genetics-0.2.0/tests/unit/test_shipped_configs.py +101 -0
- manifold_genetics-0.2.0/tests/unit/test_step_admixture.py +286 -0
- manifold_genetics-0.2.0/tests/unit/test_step_embedding.py +372 -0
- manifold_genetics-0.2.0/tests/unit/test_step_metrics.py +193 -0
- manifold_genetics-0.2.0/tests/unit/test_step_paths.py +141 -0
- manifold_genetics-0.2.0/tests/unit/test_step_pca.py +236 -0
- manifold_genetics-0.2.0/tests/unit/test_step_viz.py +384 -0
- manifold_genetics-0.2.0/tests/unit/test_subprocess_wrappers.py +284 -0
- manifold_genetics-0.2.0/tests/unit/test_tool_download_urls.py +139 -0
- manifold_genetics-0.2.0/tests/unit/test_tools.py +301 -0
- manifold_genetics-0.2.0/tests/unit/test_tools_download.py +246 -0
- manifold_genetics-0.2.0/tests/unit/test_validation.py +389 -0
- manifold_genetics-0.2.0/tests/unit/test_validation_overlap_threshold.py +76 -0
- manifold_genetics-0.2.0/tests/unit/test_visualization.py +356 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
develop-eggs/
|
|
14
|
+
dist/
|
|
15
|
+
downloads/
|
|
16
|
+
eggs/
|
|
17
|
+
.eggs/
|
|
18
|
+
lib/
|
|
19
|
+
lib64/
|
|
20
|
+
parts/
|
|
21
|
+
sdist/
|
|
22
|
+
var/
|
|
23
|
+
wheels/
|
|
24
|
+
pip-wheel-metadata/
|
|
25
|
+
share/python-wheels/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
.installed.cfg
|
|
28
|
+
*.egg
|
|
29
|
+
MANIFEST
|
|
30
|
+
|
|
31
|
+
# PyInstaller
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
coverage.lcov
|
|
49
|
+
*.cover
|
|
50
|
+
*.py,cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
target/
|
|
76
|
+
|
|
77
|
+
# Jupyter Notebook
|
|
78
|
+
.ipynb_checkpoints
|
|
79
|
+
|
|
80
|
+
# IPython
|
|
81
|
+
profile_default/
|
|
82
|
+
ipython_config.py
|
|
83
|
+
|
|
84
|
+
# pyenv
|
|
85
|
+
.python-version
|
|
86
|
+
|
|
87
|
+
# pipenv
|
|
88
|
+
Pipfile.lock
|
|
89
|
+
|
|
90
|
+
# PEP 582
|
|
91
|
+
__pypackages__/
|
|
92
|
+
|
|
93
|
+
# Celery stuff
|
|
94
|
+
celerybeat-schedule
|
|
95
|
+
celerybeat.pid
|
|
96
|
+
|
|
97
|
+
# SageMath parsed files
|
|
98
|
+
*.sage.py
|
|
99
|
+
|
|
100
|
+
# Environments
|
|
101
|
+
.env
|
|
102
|
+
.venv
|
|
103
|
+
env/
|
|
104
|
+
venv/
|
|
105
|
+
ENV/
|
|
106
|
+
env.bak/
|
|
107
|
+
venv.bak/
|
|
108
|
+
|
|
109
|
+
# Spyder project settings
|
|
110
|
+
.spyderproject
|
|
111
|
+
.spyproject
|
|
112
|
+
|
|
113
|
+
# Rope project settings
|
|
114
|
+
.ropeproject
|
|
115
|
+
|
|
116
|
+
# mkdocs documentation
|
|
117
|
+
/site
|
|
118
|
+
|
|
119
|
+
# mypy
|
|
120
|
+
.mypy_cache/
|
|
121
|
+
.dmypy.json
|
|
122
|
+
dmypy.json
|
|
123
|
+
|
|
124
|
+
# Pyre type checker
|
|
125
|
+
.pyre/
|
|
126
|
+
|
|
127
|
+
# IDE
|
|
128
|
+
.vscode/
|
|
129
|
+
.idea/
|
|
130
|
+
*.swp
|
|
131
|
+
*.swo
|
|
132
|
+
*~
|
|
133
|
+
|
|
134
|
+
# OS
|
|
135
|
+
.DS_Store
|
|
136
|
+
Thumbs.db
|
|
137
|
+
|
|
138
|
+
# Project-specific (keep local only)
|
|
139
|
+
CLAUDE.md
|
|
140
|
+
|
|
141
|
+
# docs/ used to be ignored wholesale, which made every design doc and plan in the
|
|
142
|
+
# repo invisible to collaborators and made a docs site unbuildable. Only build
|
|
143
|
+
# artefacts are ignored now.
|
|
144
|
+
docs/_build/
|
|
145
|
+
docs/site/
|
|
146
|
+
|
|
147
|
+
# Scripts that ship with the examples are tracked; only the Dropbox packaging
|
|
148
|
+
# helper stays local (it encodes personal paths).
|
|
149
|
+
examples/hgdp_1kgp/package_data_for_dropbox.sh
|
|
150
|
+
|
|
151
|
+
# Binary tools and data
|
|
152
|
+
bin/
|
|
153
|
+
data/
|
|
154
|
+
logs/
|
|
155
|
+
examples/_shared/tools/
|
|
156
|
+
|
|
157
|
+
# Example outputs
|
|
158
|
+
examples/hgdp_1kgp/outputs/
|
|
159
|
+
examples/ukbb/*/outputs/
|
|
160
|
+
examples/aou/*/outputs/
|
|
161
|
+
|
|
162
|
+
# Controlled-access genetic data must never be committed.
|
|
163
|
+
# Binary genotype/dosage formats (PLINK, BGEN) - never belong in git
|
|
164
|
+
*.bed
|
|
165
|
+
*.bim
|
|
166
|
+
*.fam
|
|
167
|
+
*.bgen
|
|
168
|
+
*.pgen
|
|
169
|
+
*.psam
|
|
170
|
+
*.sample
|
|
171
|
+
*.bcf
|
|
172
|
+
*.vcf
|
|
173
|
+
*.vcf.gz
|
|
174
|
+
|
|
175
|
+
# Local-only data/output staging dirs (e.g. data_old/, outputs_old/, figures/)
|
|
176
|
+
**/data_old/
|
|
177
|
+
**/outputs_old/
|
|
178
|
+
**/data/
|
|
179
|
+
**/figures/
|
|
180
|
+
|
|
181
|
+
# Files holding real sample IDs / private path mappings
|
|
182
|
+
*_private*
|
|
183
|
+
*mappings_private*
|
|
184
|
+
*_labels.csv
|
|
185
|
+
*_samples.txt
|
|
186
|
+
# Synthetic test fixtures (SAMPLE_### IDs, no private data) must stay tracked
|
|
187
|
+
!tests/fixtures/cross_cohort/fit_labels.csv
|
|
188
|
+
!tests/fixtures/cross_cohort/project_labels.csv
|
|
189
|
+
examples/CaG/
|
|
190
|
+
examples/ukbb/60k_random/data/
|
|
191
|
+
examples/ukbb/60k_random/outputs/
|
|
192
|
+
|
|
193
|
+
# Local-only working dirs: superseded code kept for reference, and stray run
|
|
194
|
+
# output. Neither is part of the package; kept out of git rather than deleted.
|
|
195
|
+
deprecated/
|
|
196
|
+
admixture_outputs/
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
6
|
+
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.2.0] - 2026-09-12
|
|
11
|
+
|
|
12
|
+
First public release.
|
|
13
|
+
|
|
14
|
+
The headline is that `pip install manifold-genetics` gives you a working
|
|
15
|
+
pipeline. Until this release it did not: PCA required the `flashpca` binary,
|
|
16
|
+
which ships only as a Linux x86-64 executable and had to be fetched and placed
|
|
17
|
+
by hand.
|
|
18
|
+
|
|
19
|
+
The version number is deliberately low. The API is not frozen, the
|
|
20
|
+
`transform` -> `whole_cohort` rename landed days before this, and All of Us has
|
|
21
|
+
not yet been verified end to end -- so expect further breaking changes before
|
|
22
|
+
1.0.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **Guardrails against committing controlled-access data**
|
|
27
|
+
([docs/working-with-agents.md](docs/working-with-agents.md)). A pre-commit hook and
|
|
28
|
+
a CI job run `scripts/check_sensitive_files.py`, written against this
|
|
29
|
+
repository's own two incidents rather than as a generic secret scanner: it
|
|
30
|
+
flags files whose header declares them private, genotype containers, long
|
|
31
|
+
columns of biobank identifiers, local agent and editor state, and absolute
|
|
32
|
+
cluster paths. Public cohort identifiers (`HG00096`) deliberately do not
|
|
33
|
+
trigger it. Exemptions live in `.sensitive-allow`, scoped to a single rule, so
|
|
34
|
+
that overriding the check leaves a reviewable trace.
|
|
35
|
+
- **A pure-Python PCA backend**, selected by default. Reads PLINK 1 `.bed`
|
|
36
|
+
directly (about forty lines of numpy, no new dependency) and computes a
|
|
37
|
+
randomized SVD. It reproduces `flashpca`'s conventions rather than inventing
|
|
38
|
+
its own — dosage as the count of A1, `binom2` standardisation, eigenvalues as
|
|
39
|
+
`S²/n_variants`, projection through the reference cohort's statistics — to
|
|
40
|
+
agreement of 5e-7 or better against checked-in reference outputs. The
|
|
41
|
+
standardisation was determined empirically from real `.meansd` files, not from
|
|
42
|
+
documentation.
|
|
43
|
+
- **`flashpca` remains available** as an opt-in accelerator via
|
|
44
|
+
`--pca-backend flashpca`, and writes the same artefacts as the Python backend,
|
|
45
|
+
so downstream code cannot tell which produced a result.
|
|
46
|
+
- **Streaming fit** for cohorts too large to hold densely. Selected
|
|
47
|
+
automatically from `max_fit_memory_gb`: a 60,000-sample cohort needs 82 GB
|
|
48
|
+
dense and about 110 MB streamed.
|
|
49
|
+
- **`manifold-genetics run config.yaml`** — runs a whole pipeline from a config
|
|
50
|
+
file, with `--dry-run` to print the resolved settings first. Unknown keys are
|
|
51
|
+
rejected with a suggestion rather than ignored.
|
|
52
|
+
- **A config file for every shipped example**, replacing 1,382 lines of shell.
|
|
53
|
+
- **`py.typed`**, so the annotations in this package are visible to type
|
|
54
|
+
checkers in projects that depend on it.
|
|
55
|
+
- **A real-cohort test suite** (`docs/testing-real-cohorts.md`): fast preflight
|
|
56
|
+
checks that a cohort's data agrees with the config describing it, and an
|
|
57
|
+
end-to-end suite with chance-corrected assertions about the science. Includes
|
|
58
|
+
a SLURM entry point.
|
|
59
|
+
- **A documentation site** built with MkDocs Material and published to GitHub
|
|
60
|
+
Pages, including a tutorial notebook that runs the whole pipeline on a cohort
|
|
61
|
+
it simulates as it goes. The notebook is *executed* during the build and the
|
|
62
|
+
build runs in strict mode, so a tutorial that stopped working or a broken
|
|
63
|
+
internal link fails CI rather than shipping.
|
|
64
|
+
- **A tag-triggered release workflow** (`docs/releasing.md`) using trusted
|
|
65
|
+
publishing, so there is no API token in the repository and no way to publish
|
|
66
|
+
from a laptop. It builds from a fresh checkout, verifies the package metadata
|
|
67
|
+
and the distribution contents, and installs the wheel into a clean
|
|
68
|
+
virtualenv on Linux and macOS before anything is uploaded.
|
|
69
|
+
|
|
70
|
+
### Changed
|
|
71
|
+
|
|
72
|
+
- **External tools are cached per user and fetched on first use.** They were
|
|
73
|
+
downloaded to a directory computed from `__file__`, which in a git checkout is
|
|
74
|
+
the repository's `bin/` and in a `pip install` is a directory *beside*
|
|
75
|
+
site-packages: the wrong place, frequently not writable, and discarded on
|
|
76
|
+
upgrade. Worse, the constructor created it eagerly, so merely building a
|
|
77
|
+
`ToolResolver` — which `PCA(backend="flashpca")` does — left a stray directory
|
|
78
|
+
behind.
|
|
79
|
+
|
|
80
|
+
Now: `$MANIFOLD_GENETICS_TOOL_DIR` if set, else the checkout's `bin/` when
|
|
81
|
+
running from one, else a per-user cache (`~/.cache/manifold-genetics/bin`).
|
|
82
|
+
Nothing is created until something is actually downloaded.
|
|
83
|
+
`manifold-genetics setup` stays, as the pre-fetch you want before submitting a
|
|
84
|
+
job to a compute node with no internet.
|
|
85
|
+
- **The right binary is downloaded for the platform.** Every URL was
|
|
86
|
+
`linux_x86_64`, so on macOS the resolver fetched a Linux binary and then
|
|
87
|
+
failed to execute it — which reads as a corrupt download rather than as "there
|
|
88
|
+
is no build for you". plink2 and plink now resolve per platform (Linux x86-64,
|
|
89
|
+
macOS arm64 and Intel, Windows x64), and `flashpca`, which upstream publishes
|
|
90
|
+
only for Linux x86-64, says exactly that and points at the in-process PCA
|
|
91
|
+
backend that needs no binary.
|
|
92
|
+
|
|
93
|
+
- **The `transform` preset is now `whole_cohort`.** This project used
|
|
94
|
+
`transform` for two things — the second cohort's dataset role and the
|
|
95
|
+
sklearn-style method verb. The role was renamed to `project` earlier; this
|
|
96
|
+
preset was the last holdout, naming a *mode* while every other use of the word
|
|
97
|
+
names an *operation*. The rule is now: `fit` estimates, `transform` applies,
|
|
98
|
+
`project` is the second cohort and its outputs, and a preset is named for the
|
|
99
|
+
shape of the run.
|
|
100
|
+
|
|
101
|
+
`transform` still works as a deprecated alias and warns, naming its
|
|
102
|
+
replacement. It is deliberately not listed among the valid choices in the
|
|
103
|
+
error message, because an advertised alias is a name people keep choosing.
|
|
104
|
+
- **PCA's default backend is now `python`.** `flashpca` produced the reference
|
|
105
|
+
outputs and still reproduces them bit-for-bit; the change is about being
|
|
106
|
+
installable, not about accuracy.
|
|
107
|
+
- **Landmarking defaults are consistent across large cohorts**: 10,000 random
|
|
108
|
+
landmarks and `t=50` for every cohort above ~50,000 samples, whether the fit
|
|
109
|
+
subset was chosen by majority-capping or by geometric sketching. How a subset
|
|
110
|
+
was selected should not change how it is embedded. A matched comparison found
|
|
111
|
+
the two give the same branch topology.
|
|
112
|
+
- **`--verbose` no longer sets the root logger.** It previously enabled DEBUG
|
|
113
|
+
for every library in the process, which produced 665 KB of numba SSA dumps in
|
|
114
|
+
two minutes of one run.
|
|
115
|
+
- **`manifold-genetics run --dry-run` now prints the whole effective call**,
|
|
116
|
+
marking `(default)` on anything the package supplied rather than the config
|
|
117
|
+
file. The admixture batch size is why: it is a workaround for an upstream bug,
|
|
118
|
+
so it appears in no config and was previously invisible in the one place built
|
|
119
|
+
for checking settings before a long run.
|
|
120
|
+
|
|
121
|
+
### Fixed
|
|
122
|
+
|
|
123
|
+
- **`manifold-genetics --version` disagreed with the package.** The number was
|
|
124
|
+
typed into the argparse argument as a third copy and drifted a minor version
|
|
125
|
+
behind `manifold_genetics.__version__`. It now reads the package. Caught by a
|
|
126
|
+
TestPyPI rehearsal, which is what a rehearsal is for.
|
|
127
|
+
|
|
128
|
+
A test pinned the stale literal, so it passed while the command was wrong; it
|
|
129
|
+
now compares against the package. Two further tests assert that the CLI
|
|
130
|
+
reports the declared version and that the version appears in exactly one
|
|
131
|
+
source file.
|
|
132
|
+
- The wheel is now checked to contain no untracked module. It picks files by the
|
|
133
|
+
same "everything not gitignored" rule that put untracked working files in a
|
|
134
|
+
pre-release sdist; there are stale `.ipynb_checkpoints` copies of two real
|
|
135
|
+
backends under `src/` today, kept out only by a `.gitignore` entry.
|
|
136
|
+
- **The declared license was MIT; the LICENSE file is BSD 3-Clause.** The
|
|
137
|
+
LICENSE file is authoritative and the metadata now matches it. A release
|
|
138
|
+
cannot be re-uploaded under the same version, so this would have been
|
|
139
|
+
permanent.
|
|
140
|
+
- **Every `project.urls` entry pointed at `manifold-genetics` with a hyphen**,
|
|
141
|
+
which is not the repository name — four 404s on the PyPI sidebar.
|
|
142
|
+
- **Neural admixture is always given a batch size** (400). Left unset it batches
|
|
143
|
+
the entire dataset at once; that is a bug in the tool, and the workaround was
|
|
144
|
+
previously applied only in `subsample` mode, leaving the All of Us projection
|
|
145
|
+
example — the one running on the largest cohort — without it.
|
|
146
|
+
- **`validate_sample_id_overlap` now enforces a minimum overlap** (50% by
|
|
147
|
+
default) instead of raising only at zero. Near-total mismatch between a label
|
|
148
|
+
file and a genotype set previously passed silently, which is how one example's
|
|
149
|
+
figures came to colour 40% of their points from a superseded sample selection.
|
|
150
|
+
- Example label files are regenerated when they no longer match their `.fam`,
|
|
151
|
+
rather than being kept because they exist.
|
|
152
|
+
- **The source distribution contained untracked working files.** hatchling's
|
|
153
|
+
default is to include everything not gitignored, which is not the same as
|
|
154
|
+
everything tracked; a pre-release sdist carried local tool state and an
|
|
155
|
+
example script whose header says "NOT for external users". Its contents are now
|
|
156
|
+
declared explicitly and checked by a test.
|
|
157
|
+
|
|
158
|
+
### Removed
|
|
159
|
+
|
|
160
|
+
- `examples/_shared/run_pipeline.sh`, `examples/_shared/detect_cluster.sh` and
|
|
161
|
+
the nine per-example `run_pipeline.sh` wrappers, superseded by config files.
|
|
162
|
+
|
|
163
|
+
[Unreleased]: https://github.com/MattScicluna/manifold_genetics/compare/v0.2.0...HEAD
|
|
164
|
+
[0.2.0]: https://github.com/MattScicluna/manifold_genetics/releases/tag/v0.2.0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Matthew Scicluna
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|