afquery 0.2.0__tar.gz → 0.2.2__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.
Files changed (130) hide show
  1. afquery-0.2.2/Dockerfile +16 -0
  2. {afquery-0.2.0 → afquery-0.2.2}/PKG-INFO +4 -1
  3. {afquery-0.2.0 → afquery-0.2.2}/docs/advanced/benchmarking.md +8 -0
  4. {afquery-0.2.0 → afquery-0.2.2}/docs/advanced/debugging-results.md +4 -1
  5. {afquery-0.2.0 → afquery-0.2.2}/docs/advanced/filter-pass-tracking.md +19 -11
  6. {afquery-0.2.0 → afquery-0.2.2}/docs/advanced/multi-cohort-strategies.md +1 -1
  7. {afquery-0.2.0 → afquery-0.2.2}/docs/advanced/performance.md +11 -2
  8. {afquery-0.2.0 → afquery-0.2.2}/docs/advanced/pipeline-integration.md +1 -1
  9. {afquery-0.2.0 → afquery-0.2.2}/docs/advanced/ploidy-and-sex-chroms.md +14 -0
  10. afquery-0.2.2/docs/assets/img/gap2_mixed_technologies.png +0 -0
  11. {afquery-0.2.0 → afquery-0.2.2}/docs/faq.md +8 -6
  12. {afquery-0.2.0 → afquery-0.2.2}/docs/getting-started/concepts.md +10 -0
  13. {afquery-0.2.0 → afquery-0.2.2}/docs/getting-started/installation.md +8 -0
  14. afquery-0.2.2/docs/getting-started/motivation.md +108 -0
  15. {afquery-0.2.0 → afquery-0.2.2}/docs/getting-started/preprocessing.md +8 -0
  16. {afquery-0.2.0 → afquery-0.2.2}/docs/getting-started/quickstart.md +29 -3
  17. afquery-0.2.2/docs/getting-started/tutorial.md +403 -0
  18. {afquery-0.2.0 → afquery-0.2.2}/docs/getting-started/understanding-output.md +2 -2
  19. {afquery-0.2.0 → afquery-0.2.2}/docs/guides/annotate-vcf.md +9 -1
  20. {afquery-0.2.0 → afquery-0.2.2}/docs/guides/create-database.md +8 -0
  21. {afquery-0.2.0 → afquery-0.2.2}/docs/guides/dump-export.md +8 -0
  22. {afquery-0.2.0 → afquery-0.2.2}/docs/guides/manifest-format.md +13 -0
  23. {afquery-0.2.0 → afquery-0.2.2}/docs/guides/query.md +12 -1
  24. {afquery-0.2.0 → afquery-0.2.2}/docs/guides/sample-filtering.md +13 -0
  25. {afquery-0.2.0 → afquery-0.2.2}/docs/guides/update-database.md +8 -0
  26. afquery-0.2.2/docs/guides/variant-info.md +163 -0
  27. {afquery-0.2.0 → afquery-0.2.2}/docs/index.md +44 -1
  28. {afquery-0.2.0 → afquery-0.2.2}/docs/reference/cli.md +24 -0
  29. {afquery-0.2.0 → afquery-0.2.2}/docs/reference/glossary.md +4 -0
  30. {afquery-0.2.0 → afquery-0.2.2}/docs/reference/python-api.md +87 -0
  31. afquery-0.2.2/docs/scripts/gen_gap2_figure.py +157 -0
  32. afquery-0.2.2/docs/stylesheets/extra.css +8 -0
  33. {afquery-0.2.0 → afquery-0.2.2}/docs/troubleshooting.md +13 -16
  34. {afquery-0.2.0 → afquery-0.2.2}/docs/use-cases/acmg-use-cases.md +10 -3
  35. {afquery-0.2.0 → afquery-0.2.2}/docs/use-cases/clinical-prioritization.md +14 -1
  36. {afquery-0.2.0 → afquery-0.2.2}/docs/use-cases/cohort-stratification.md +4 -1
  37. {afquery-0.2.0 → afquery-0.2.2}/docs/use-cases/population-specific-af.md +2 -1
  38. {afquery-0.2.0 → afquery-0.2.2}/docs/use-cases/pseudo-controls.md +1 -1
  39. {afquery-0.2.0 → afquery-0.2.2}/docs/use-cases/sex-specific-af.md +4 -2
  40. {afquery-0.2.0 → afquery-0.2.2}/docs/use-cases/technology-integration.md +1 -1
  41. afquery-0.2.2/examples/demo/README.md +27 -0
  42. afquery-0.2.2/examples/demo/create_demo_data.py +324 -0
  43. {afquery-0.2.0 → afquery-0.2.2}/mkdocs.yml +14 -1
  44. {afquery-0.2.0 → afquery-0.2.2}/pyproject.toml +3 -0
  45. afquery-0.2.2/src/afquery/__init__.py +6 -0
  46. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/_version.py +2 -2
  47. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/cli.py +94 -2
  48. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/database.py +35 -1
  49. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/models.py +12 -0
  50. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/query.py +115 -1
  51. afquery-0.2.2/src/afquery/variant_info.py +49 -0
  52. {afquery-0.2.0 → afquery-0.2.2}/tests/test_dump.py +2 -2
  53. {afquery-0.2.0 → afquery-0.2.2}/tests/test_pass_filter.py +9 -9
  54. afquery-0.2.2/tests/test_variant_info.py +358 -0
  55. afquery-0.2.0/Dockerfile +0 -6
  56. afquery-0.2.0/docs/getting-started/motivation.md +0 -140
  57. afquery-0.2.0/plans/issue-01-remove-publication-section.md +0 -27
  58. afquery-0.2.0/plans/issue-02-drop-schema-v1.md +0 -52
  59. afquery-0.2.0/plans/issue-03-query-syntax-chrom-pos.md +0 -83
  60. afquery-0.2.0/plans/issue-04-wes-bed-validation.md +0 -62
  61. afquery-0.2.0/plans/issue-05-update-sample-metadata.md +0 -79
  62. afquery-0.2.0/plans/issue-06-multi-chromosome-query.md +0 -55
  63. afquery-0.2.0/plans/issue-07-doc-formatting-fixes.md +0 -71
  64. afquery-0.2.0/plans/issue-08-index-feature-list.md +0 -49
  65. afquery-0.2.0/plans/issue-09-doc-content-improvements.md +0 -97
  66. afquery-0.2.0/src/afquery/__init__.py +0 -5
  67. {afquery-0.2.0 → afquery-0.2.2}/.dockerignore +0 -0
  68. {afquery-0.2.0 → afquery-0.2.2}/.github/workflows/ci.yml +0 -0
  69. {afquery-0.2.0 → afquery-0.2.2}/.github/workflows/docs.yml +0 -0
  70. {afquery-0.2.0 → afquery-0.2.2}/.github/workflows/release.yml +0 -0
  71. {afquery-0.2.0 → afquery-0.2.2}/.gitignore +0 -0
  72. {afquery-0.2.0 → afquery-0.2.2}/LICENSE +0 -0
  73. {afquery-0.2.0 → afquery-0.2.2}/README.md +0 -0
  74. {afquery-0.2.0 → afquery-0.2.2}/docs/reference/data-model.md +0 -0
  75. {afquery-0.2.0 → afquery-0.2.2}/recipes/afquery/meta.yaml +0 -0
  76. {afquery-0.2.0 → afquery-0.2.2}/resources/normalize_vcf.sh +0 -0
  77. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/annotate.py +0 -0
  78. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/benchmark.py +0 -0
  79. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/bitmaps.py +0 -0
  80. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/capture.py +0 -0
  81. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/cli.pyr +0 -0
  82. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/constants.py +0 -0
  83. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/dump.py +0 -0
  84. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/ploidy.py +0 -0
  85. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/__init__.py +0 -0
  86. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/build.py +0 -0
  87. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/compact.py +0 -0
  88. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/ingest.py +0 -0
  89. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/manifest.py +0 -0
  90. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/regions.py +0 -0
  91. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/synth.py +0 -0
  92. {afquery-0.2.0 → afquery-0.2.2}/src/afquery/preprocess/update.py +0 -0
  93. {afquery-0.2.0 → afquery-0.2.2}/tests/conftest.py +0 -0
  94. {afquery-0.2.0 → afquery-0.2.2}/tests/data/annotate_input.vcf +0 -0
  95. {afquery-0.2.0 → afquery-0.2.2}/tests/data/annotate_multi_bucket.vcf +0 -0
  96. {afquery-0.2.0 → afquery-0.2.2}/tests/data/annotate_multi_chrom.vcf +0 -0
  97. {afquery-0.2.0 → afquery-0.2.2}/tests/data/beds/wes_kit_a.bed +0 -0
  98. {afquery-0.2.0 → afquery-0.2.2}/tests/data/beds/wes_kit_b.bed +0 -0
  99. {afquery-0.2.0 → afquery-0.2.2}/tests/data/expected_results.json +0 -0
  100. {afquery-0.2.0 → afquery-0.2.2}/tests/data/manifest.tsv +0 -0
  101. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S00.vcf +0 -0
  102. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S01.vcf +0 -0
  103. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S02.vcf +0 -0
  104. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S03.vcf +0 -0
  105. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S04.vcf +0 -0
  106. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S05.vcf +0 -0
  107. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S06.vcf +0 -0
  108. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S07.vcf +0 -0
  109. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S08.vcf +0 -0
  110. {afquery-0.2.0 → afquery-0.2.2}/tests/data/vcfs/S09.vcf +0 -0
  111. {afquery-0.2.0 → afquery-0.2.2}/tests/test_annotate.py +0 -0
  112. {afquery-0.2.0 → afquery-0.2.2}/tests/test_batch.py +0 -0
  113. {afquery-0.2.0 → afquery-0.2.2}/tests/test_benchmark.py +0 -0
  114. {afquery-0.2.0 → afquery-0.2.2}/tests/test_bitmaps.py +0 -0
  115. {afquery-0.2.0 → afquery-0.2.2}/tests/test_capture.py +0 -0
  116. {afquery-0.2.0 → afquery-0.2.2}/tests/test_cli.py +0 -0
  117. {afquery-0.2.0 → afquery-0.2.2}/tests/test_cli_docs_consistency.py +0 -0
  118. {afquery-0.2.0 → afquery-0.2.2}/tests/test_compact.py +0 -0
  119. {afquery-0.2.0 → afquery-0.2.2}/tests/test_constants.py +0 -0
  120. {afquery-0.2.0 → afquery-0.2.2}/tests/test_haploid_stats.py +0 -0
  121. {afquery-0.2.0 → afquery-0.2.2}/tests/test_info.py +0 -0
  122. {afquery-0.2.0 → afquery-0.2.2}/tests/test_ploidy.py +0 -0
  123. {afquery-0.2.0 → afquery-0.2.2}/tests/test_preprocess.py +0 -0
  124. {afquery-0.2.0 → afquery-0.2.2}/tests/test_query.py +0 -0
  125. {afquery-0.2.0 → afquery-0.2.2}/tests/test_sample_filter.py +0 -0
  126. {afquery-0.2.0 → afquery-0.2.2}/tests/test_synth.py +0 -0
  127. {afquery-0.2.0 → afquery-0.2.2}/tests/test_synthetic_stats.py +0 -0
  128. {afquery-0.2.0 → afquery-0.2.2}/tests/test_update.py +0 -0
  129. {afquery-0.2.0 → afquery-0.2.2}/tests/test_update_metadata.py +0 -0
  130. {afquery-0.2.0 → afquery-0.2.2}/tests/test_warnings.py +0 -0
@@ -0,0 +1,16 @@
1
+ FROM python:3.11-slim AS builder
2
+
3
+ RUN apt-get update && \
4
+ apt-get install -y --no-install-recommends build-essential && \
5
+ rm -rf /var/lib/apt/lists/*
6
+
7
+ ARG VERSION
8
+ RUN pip install --no-cache-dir afquery==${VERSION}
9
+
10
+
11
+ FROM python:3.11-slim
12
+
13
+ COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
14
+ COPY --from=builder /usr/local/bin/afquery /usr/local/bin/afquery
15
+
16
+ ENTRYPOINT ["afquery"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: afquery
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Genomic allele frequency query engine with bitmap-encoded genotypes
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -20,7 +20,10 @@ Provides-Extra: dev
20
20
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
21
21
  Requires-Dist: pytest>=8.0; extra == 'dev'
22
22
  Provides-Extra: docs
23
+ Requires-Dist: matplotlib>=3.8; extra == 'docs'
24
+ Requires-Dist: mike>=2.0; extra == 'docs'
23
25
  Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
26
+ Requires-Dist: mkdocs-print-site-plugin>=2.6.1; extra == 'docs'
24
27
  Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
25
28
  Requires-Dist: pymdown-extensions>=10.7; extra == 'docs'
26
29
  Description-Content-Type: text/markdown
@@ -76,6 +76,7 @@ If `point_query_cold_ms` exceeds 500 ms, check disk I/O performance. If `point_q
76
76
  ## Synthetic Data Generation
77
77
 
78
78
  The benchmark generates:
79
+
79
80
  - `N` samples with random sex (50/50) and random technology assignment
80
81
  - `M` variants per chromosome with uniformly random positions
81
82
  - Random genotypes with configurable carrier rates
@@ -168,3 +169,10 @@ EOF
168
169
  ```
169
170
 
170
171
  A regression of >20% on `point_query_cold_ms` warrants investigation.
172
+
173
+ ---
174
+
175
+ ## Next Steps
176
+
177
+ - [Performance Tuning](performance.md) — tune threads and memory to improve build and query speed
178
+ - [Debugging Results](debugging-results.md) — diagnose unexpected AN=0 or surprising AF values
@@ -54,6 +54,9 @@ To inspect a site with high N_FAIL, query with `--format json` to see all fields
54
54
  afquery query --db ./db/ --locus chr1:12345678 --format json
55
55
  ```
56
56
 
57
+ !!! tip "Identify failing samples"
58
+ Use `afquery variant-info --db ./db/ --locus chr1:12345678` to see exactly which samples have FAIL status and their metadata (technology, phenotype codes). This helps determine if failures cluster in a specific technology or sample subset. See [Variant Info](../guides/variant-info.md).
59
+
57
60
  If N_FAIL is consistently high across many sites, check the variant calling pipeline and FILTER field settings in your VCFs.
58
61
 
59
62
  ---
@@ -130,7 +133,7 @@ conn.close()
130
133
 
131
134
  ---
132
135
 
133
- ## Related Pages
136
+ ## Next Steps
134
137
 
135
138
  - [Understanding Output](../getting-started/understanding-output.md) — what each field means
136
139
  - [FAQ](../faq.md) — common questions and answers
@@ -7,10 +7,12 @@ AFQuery tracks variants that are called but fail quality filters (`FILTER≠PASS
7
7
  ## Background: VCF FILTER Field
8
8
 
9
9
  In VCF format, the FILTER column indicates whether a variant call passed quality filters:
10
+
10
11
  - `PASS` or `.` (missing) — the variant passed all filters
11
12
  - Any other value (e.g., `LowQual`, `VQSRTrancheSNP99.90to100.00`) — the variant failed one or more filters
12
13
 
13
14
  AFQuery default behavior:
15
+
14
16
  - **PASS-only**: only `FILTER=PASS` variants are counted in AC/AN. This is always enforced.
15
17
 
16
18
  ---
@@ -22,6 +24,7 @@ AFQuery stores a third bitmap per variant alongside `het_bitmap` and `hom_bitmap
22
24
  - **`fail_bitmap`** — bit set for each sample that has a non-ref genotype (AC>0) AND `FILTER≠PASS`
23
25
 
24
26
  This means:
27
+
25
28
  - A sample in `fail_bitmap` was genotyped with the alt allele but the call failed QC
26
29
  - Such samples are **not** counted in AC/AN (they don't affect AF)
27
30
  - Their count is exposed as `N_FAIL`
@@ -66,6 +69,16 @@ for r in results:
66
69
 
67
70
  `N_FAIL` is always an `int` (default `0`).
68
71
 
72
+ ### Identifying specific FAIL samples
73
+
74
+ To see which individual samples have FAIL status at a position, use `variant-info`:
75
+
76
+ ```bash
77
+ afquery variant-info --db ./db/ --locus chr1:925952
78
+ ```
79
+
80
+ Each carrier row shows its `filter` column as `PASS` or `FAIL`, along with sample metadata (technology, phenotype codes). This helps pinpoint whether failures cluster in a specific technology or sample group. See [Variant Info](../guides/variant-info.md) for full options.
81
+
69
82
  ---
70
83
 
71
84
  ## VCF Annotation
@@ -82,19 +95,14 @@ afquery annotate --db ./db/ --input variants.vcf --output annotated.vcf
82
95
 
83
96
  ---
84
97
 
85
- ## Schema Version Compatibility
86
-
87
- The `fail_bitmap` and `N_FAIL` tracking requires schema version 2.0 or later. Databases created with older versions of AFQuery do not contain `fail_bitmap` data.
88
-
89
- | Database schema | N_FAIL behavior |
90
- |----------------|-----------------|
91
- | ≥ 2.0 | `N_FAIL` is always an integer (0 or more) |
92
- | < 2.0 (legacy) | `N_FAIL` is `None` in Python API results |
98
+ ## PASS-Only Enforcement
93
99
 
94
- To upgrade a legacy database, rebuild it with `afquery create-db`. There is no in-place migration.
100
+ AF reflects the quality-filtered allele frequency the frequency of the alt allele among high-quality calls. This is appropriate for most clinical and research use cases. PASS-only ingestion is always enforced.
95
101
 
96
102
  ---
97
103
 
98
- ## PASS-Only Enforcement
104
+ ## Next Steps
99
105
 
100
- AF reflects the quality-filtered allele frequency — the frequency of the alt allele among high-quality calls. This is appropriate for most clinical and research use cases. PASS-only ingestion is always enforced.
106
+ - [Understanding Output](../getting-started/understanding-output.md) interpreting N_FAIL in query and annotate results
107
+ - [ACMG Criteria](../use-cases/acmg-use-cases.md) — using N_FAIL to assess site quality before applying BA1/PM2
108
+ - [Debugging Results](debugging-results.md) — diagnosing unexpectedly high N_FAIL values
@@ -152,7 +152,7 @@ afquery annotate --db /databases/institutional/cardiology/ \
152
152
 
153
153
  ---
154
154
 
155
- ## Related Pages
155
+ ## Next Steps
156
156
 
157
157
  - [Create a Database](../guides/create-database.md) — database creation options
158
158
  - [Update a Database](../guides/update-database.md) — adding samples to an existing database
@@ -107,7 +107,7 @@ graph TD
107
107
 
108
108
  ### Sub-100 ms Point Queries
109
109
 
110
- Query performance for a typical 50K-sample cohort:
110
+ Query performance for a typical 50K-sample cohort (see [Benchmarking](benchmarking.md) to measure these on your own database):
111
111
 
112
112
  | Query type | Cold (first call) | Warm (cached) |
113
113
  |------------|-------------------|---------------|
@@ -168,6 +168,7 @@ Actual disk usage depends on variant density and carrier rates. Rare variants (l
168
168
  ## Memory at Query Time
169
169
 
170
170
  Query memory is very low:
171
+
171
172
  - **Bitmap operations**: only the relevant bitmaps are loaded from Parquet (~64 KB per variant at 50K samples)
172
173
  - **No full chromosome load**: DuckDB reads only the specific rows matching the query position
173
174
  - **Capture index**: one small interval tree per WES technology loaded at `Database.__init__`
@@ -182,4 +183,12 @@ Enable verbose output to see per-step timings (available on `annotate`, `dump`,
182
183
 
183
184
  ```bash
184
185
  afquery annotate --db ./db/ --input variants.vcf --output annotated.vcf --verbose
185
- ```
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Next Steps
191
+
192
+ - [Benchmarking](benchmarking.md) — measure and track query performance on your database
193
+ - [Create a Database](../guides/create-database.md) — build options including `--build-threads` and `--build-memory`
194
+ - [Pipeline Integration](pipeline-integration.md) — thread configuration in Nextflow and Snakemake workflows
@@ -177,7 +177,7 @@ afquery_db: /shared/databases/afquery/cohort_v2
177
177
 
178
178
  ---
179
179
 
180
- ## Related Pages
180
+ ## Next Steps
181
181
 
182
182
  - [Annotate a VCF](../guides/annotate-vcf.md) — full annotation CLI reference
183
183
  - [Performance Tuning](performance.md) — thread and memory optimization
@@ -107,6 +107,9 @@ For every query result, the following identity holds:
107
107
 
108
108
  This can be used to validate results. N_HOM_REF is the number of eligible samples that are homozygous reference (i.e., do not carry the alt allele and passed quality filters).
109
109
 
110
+ !!! note "Mutual exclusivity"
111
+ N_HET, N_HOM_ALT, N_HOM_REF, and N_FAIL are mutually exclusive. A sample with a non-ref allele but FILTER≠PASS is counted in N_FAIL only — it does not appear in N_HET or N_HOM_ALT. Likewise, N_HOM_REF counts only PASS-filtered samples.
112
+
110
113
  ### chrX non-PAR
111
114
 
112
115
  - A male with GT=`1` contributes AC=1, AN=1
@@ -114,6 +117,7 @@ This can be used to validate results. N_HOM_REF is the number of eligible sample
114
117
  - A female with GT=`1/1` contributes AC=2, AN=2
115
118
 
116
119
  N_HET and N_HOM_ALT are counted per sample (not per allele):
120
+
117
121
  - Males at chrX non-PAR (haploid positions) are counted in **N_HOM_ALT** when GT=1, because all alleles at that position are alternate. N_HET is reserved for diploid positions where both reference and alternate alleles are present.
118
122
  - Females at chrX with GT=`0/1` are counted in N_HET; with GT=`1/1` in N_HOM_ALT.
119
123
 
@@ -139,11 +143,21 @@ chrM is haploid for all samples (both sexes contribute AN=1):
139
143
  ## Sex Filter Interaction
140
144
 
141
145
  When `--sex female` is used on chrX (non-PAR), AN is purely diploid:
146
+
142
147
  - Each eligible female contributes AN=2
143
148
  - AF is computed over a fully diploid denominator
144
149
 
145
150
  When `--sex male` is used on chrX (non-PAR), AN is purely haploid:
151
+
146
152
  - Each eligible male contributes AN=1
147
153
  - AF reflects the observed allele frequency in haploid male calls
148
154
 
149
155
  This makes it straightforward to compare X-linked variant frequencies between sexes without manual ploidy adjustment.
156
+
157
+ ---
158
+
159
+ ## Next Steps
160
+
161
+ - [Sex-Specific AF](../use-cases/sex-specific-af.md) — X-linked variant analysis using sex-stratified queries
162
+ - [Key Concepts](../getting-started/concepts.md) — AC/AN/AF overview and the ploidy table
163
+ - [Sample Filtering](../guides/sample-filtering.md) — `--sex` filter syntax
@@ -88,7 +88,7 @@ See [Updating sample metadata](guides/update-database.md#update-sample-metadata)
88
88
 
89
89
  AFQuery has been tested with up to 50,000 samples. Bitmap operations remain fast at this scale because Roaring Bitmaps are highly compressed for sparse data. At 50K samples, a typical variant bitmap is ~64 KB.
90
90
 
91
- For cohorts larger than 50K, performance should remain sub-second for point queries, but build-phase memory requirements scale with cohort size. See [Performance Tuning](advanced/performance.md).
91
+ For cohorts larger than 50K, performance should remain sub-second for point queries, but build-phase memory requirements scale with cohort size. See [Performance Tuning](advanced/performance.md) and [Benchmarking](advanced/benchmarking.md) to measure latency on your own database.
92
92
 
93
93
  ---
94
94
 
@@ -135,6 +135,7 @@ print(db.get_all_phenotypes())
135
135
  ## Does filtering by technology affect WGS samples?
136
136
 
137
137
  WGS samples are always covered at every position (no BED file). Technology filters work by sample membership, not coverage:
138
+
138
139
  - `--tech wgs` restricts to samples with `tech=wgs` in the manifest
139
140
  - WES samples at positions outside their capture BED are excluded by coverage, not by the tech filter
140
141
 
@@ -177,16 +178,15 @@ Use `afquery info --db ./db/` to list all registered codes before running querie
177
178
 
178
179
  ### What if AN is very low?
179
180
 
180
- Low AN means the allele frequency estimate is unreliable. For example: AC=1, AN=4, AF=0.25 — this is not a robust 25% frequency estimate.
181
+ Low AN means the allele frequency estimate is unreliable.
181
182
 
182
183
  **Rules of thumb:**
184
+
183
185
  - **AN ≥ 100**: bare minimum for any interpretation
184
186
  - **AN ≥ 500**: necessary for rare variant filtering
185
187
  - **AN ≥ 1000**: required for clinical variant interpretation
186
188
 
187
- For detailed per-criterion AN thresholds, see [ACMG Criteria — AN Threshold Guidance](use-cases/acmg-use-cases.md#an-threshold-guidance).
188
-
189
- Always check `AFQUERY_AN` alongside `AFQUERY_AF` in downstream analyses. A variant with high AF but very low AN should be treated with skepticism.
189
+ For per-criterion thresholds see [ACMG Criteria — AN Threshold Guidance](use-cases/acmg-use-cases.md#an-threshold-guidance). If AN=0 unexpectedly, see [Debugging Results](advanced/debugging-results.md#1-unexpected-an0) for a step-by-step diagnostic checklist.
190
190
 
191
191
  ---
192
192
 
@@ -195,6 +195,7 @@ Always check `AFQUERY_AN` alongside `AFQUERY_AF` in downstream analyses. A varia
195
195
  If your cohort is a mix of ancestries, the AF reflects a weighted average across all ancestries. A variant at AF=0.001 globally may be at AF=0.01 in a subpopulation.
196
196
 
197
197
  **Mitigation:**
198
+
198
199
  - Tag samples by ancestry or population in `phenotype_codes`
199
200
  - Use stratified queries: `afquery query --phenotype AFR` for African samples, `--phenotype EUR` for European samples, etc.
200
201
  - Compare AF across subgroups to detect ancestry-specific signals
@@ -208,7 +209,7 @@ Without stratification, rare variant interpretation in mixed cohorts can be misl
208
209
  AFQuery is purpose-built for fast subcohort AF computation and is not a general-purpose genomic database:
209
210
 
210
211
  - **Not a joint genotyper**: AFQuery does not perform joint genotyping. Input VCFs should be individually called before ingestion.
211
- - **Not a variant database**: AFQuery stores only genotype-level summaries (bitmaps). Individual sample genotypes cannot be retrieved from the database.
212
+ - **Not a genotype store**: AFQuery stores genotype summaries as bitmaps, not raw FORMAT fields. Use `variant-info` to list carriers and their genotype class (het/hom) at a specific position; for full per-sample VCF fields (GQ, DP, AD, etc.), consult the source VCFs.
212
213
  - **No statistical genetics**: AFQuery does not compute Hardy-Weinberg equilibrium, population stratification, or other statistical genetics metrics.
213
214
  - **Batch queries**: The `--from-file` batch mode supports variants across multiple chromosomes in a single call. Point queries (`--locus`) and region queries (`--region`) target a single position or range; for multi-position multi-chromosome lookups, use `--from-file`.
214
215
  - **Cohort size limit**: Performance at >100K samples has not been validated. Memory requirements for the build phase scale with cohort size.
@@ -231,3 +232,4 @@ ManifestError: BED file not found for technology '<tech>': '<path>'
231
232
  passed to `--bed-dir`.
232
233
  - If the samples are genuinely whole-genome (no capture), change `tech_name` to `WGS`
233
234
  in the manifest (no BED file required for WGS).
235
+
@@ -167,6 +167,7 @@ WGS samples are always eligible (no BED file needed).
167
167
  ## The Manifest
168
168
 
169
169
  The manifest is a TSV file that drives database creation. It maps each sample to its:
170
+
170
171
  - VCF file path
171
172
  - Sex (`male` / `female`)
172
173
  - Sequencing technology
@@ -206,6 +207,7 @@ AN is computed only over eligible samples, so AF naturally reflects the chosen s
206
207
  Multiple labels per sample are supported. There is no validation or controlled vocabulary — you define the ontology for your cohort.
207
208
 
208
209
  When planning phenotype codes, consider:
210
+
209
211
  - Codes can be updated after ingestion using `afquery update-db --update-sample` (see [Updating sample metadata](../guides/update-database.md#update-sample-metadata))
210
212
  - Codes are case-sensitive: `E11.9` ≠ `e11.9`
211
213
  - Trailing or leading spaces cause silent mismatch (always use `E11.9,I10`, never `E11.9, I10`)
@@ -213,3 +215,11 @@ When planning phenotype codes, consider:
213
215
  ---
214
216
 
215
217
  PASS-only ingestion is always enforced. See [FILTER=PASS Tracking](../advanced/filter-pass-tracking.md) for details.
218
+
219
+ ---
220
+
221
+ ## Next Steps
222
+
223
+ - [5-Min Quickstart](quickstart.md) — build your first database and run queries
224
+ - [Sample Filtering](../guides/sample-filtering.md) — phenotype, sex, and technology filter syntax
225
+ - [Ploidy & Special Chromosomes](../advanced/ploidy-and-sex-chroms.md) — PAR regions and ploidy rules in detail
@@ -82,3 +82,11 @@ If you want to build or serve the documentation locally:
82
82
  pip install -e ".[docs]"
83
83
  mkdocs serve
84
84
  ```
85
+
86
+ ---
87
+
88
+ ## Next Steps
89
+
90
+ - [VCF Preprocessing](preprocessing.md) — normalize and prepare VCFs before ingestion
91
+ - [5-Min Quickstart](quickstart.md) — build your first database and run queries
92
+ - [Key Concepts](concepts.md) — understand the bitmap index, manifest, and metadata model
@@ -0,0 +1,108 @@
1
+ # Why Local Allele Frequencies Matter
2
+
3
+ ## Clinical Decisions Depend on Accurate AF
4
+
5
+ Allele frequency (AF) is one of the strongest lines of evidence in clinical variant classification. Under the [ACMG/AMP framework](../use-cases/acmg-use-cases.md), AF thresholds directly determine whether a variant is classified as benign (BA1: AF > 5%), supporting-pathogenic (PM2: absent or extremely rare), or strongly pathogenic through case enrichment (PS4). A misestimated AF can flip a classification — and with it, a clinical decision.
6
+
7
+ Yet AF is not an intrinsic property of a variant — it depends on the population in which it is measured. The same variant can be common in one cohort and absent in another. When the reference population does not match the patient's background, variant classification becomes unreliable.
8
+
9
+ This page describes four methodological gaps in current allele frequency workflows that AFQuery was designed to address.
10
+
11
+ ---
12
+
13
+ ## Gap 1 — Global Databases Miss Population-Specific Signals
14
+
15
+ Population databases like gnomAD are invaluable for identifying common variants, but they aggregate data from broad, predominantly European-ancestry populations. When the patient's ancestry differs from the reference, AF estimates diverge — sometimes dramatically.
16
+
17
+ !!! warning "Real-world impact"
18
+ Turkish breast cancer variants showed up to **354-fold higher** allele frequencies in a local variome compared to gnomAD, leading to **6.7% of VUS being reclassified** to likely benign when population-matched data were used [(Agaoglu et al., 2024)](https://pubmed.ncbi.nlm.nih.gov/38308423/). In Taiwanese inherited retinal degeneration, using a local biobank as ancestry-matched controls for PS4 evidence **upgraded 2 variants from LP to P and 6 from VUS to LP** [(Huang et al., 2026)](https://pubmed.ncbi.nlm.nih.gov/41692763/).
19
+
20
+ The problem extends beyond rare ancestries. In a UK arrhythmia clinic, **32.2% of VUS were reclassified** upon re-evaluation with updated frequency data [(Young et al., 2024)](https://pubmed.ncbi.nlm.nih.gov/38218330/). Analysis of 469,803 UK Biobank exomes found that **12.4% of rare LDLR VUS met criteria for reclassification** to likely pathogenic when biobank-derived odds ratios were calibrated to ACMG PS4 strength levels [(Bhat et al., 2025)](https://pubmed.ncbi.nlm.nih.gov/40639380/).
21
+
22
+ These are not edge cases. Every cohort with a population composition that differs from gnomAD — geographically, clinically, or by ascertainment — may produce misleading AF when compared only against global references.
23
+
24
+ | Study | Population | Key Finding |
25
+ |-------|-----------|-------------|
26
+ | [Agaoglu et al. 2024](https://pubmed.ncbi.nlm.nih.gov/38308423/) | Turkish breast cancer | Up to 354× AF difference vs gnomAD; 6.7% VUS reclassified |
27
+ | [Huang et al. 2026](https://pubmed.ncbi.nlm.nih.gov/41692763/) | Taiwanese IRD | 8 variants reclassified using local biobank PS4 evidence |
28
+ | [Young et al. 2024](https://pubmed.ncbi.nlm.nih.gov/38218330/) | UK arrhythmia clinic | 32.2% of VUS reclassified on re-evaluation |
29
+ | [Bhat et al. 2025](https://pubmed.ncbi.nlm.nih.gov/40639380/) | UK Biobank (470K) | 12.4% rare LDLR VUS reclassifiable via biobank OR |
30
+ | [Kotan 2022](https://pubmed.ncbi.nlm.nih.gov/35438269/) | Turkish endocrinology | Population-matched variomes correlate best geographically |
31
+ | [Soussi 2022](https://pubmed.ncbi.nlm.nih.gov/35802772/) | Multi-ethnic (TP53) | 21 benign TP53 SNPs missed in European-biased databases |
32
+ | [Dawood et al. 2024](https://pubmed.ncbi.nlm.nih.gov/39627863/) | Multi-ethnic (MAVE) | AF evidence codes have inequitable impact on non-Europeans (p = 7.47×10⁻⁶) |
33
+
34
+ ---
35
+
36
+ ## Gap 2 — Mixed Sequencing Technologies Inflate the Denominator
37
+
38
+ Modern cohorts routinely combine samples sequenced with different technologies — WGS, multiple WES capture kits, and targeted gene panels. Even different versions of the same WES kit can differ by hundreds of base pairs at capture boundaries.
39
+
40
+ This matters because **allele number (AN) must be computed per position, not per cohort**. A sample whose capture kit does not cover the queried position has no genotype there: it contributes nothing to AN. If it is naively counted, the denominator is inflated and the resulting AF is artificially deflated.
41
+
42
+ The figure below illustrates the problem with a minimal example: two versions of the same WES capture kit (V1, n = 120 and V2, n = 80) sequencing a schematic gene with eight exons.
43
+
44
+ ![Mixed sequencing technologies: coverage at different query positions](../assets/img/gap2_mixed_technologies.png)
45
+
46
+ **Position A** (Exon 5) falls within the capture region of both kit versions. All 200 samples have a genotype at this position, so AN = 200 × 2 = **400**. Both kits contribute to the count, and the resulting AF is correct.
47
+
48
+ **Position B** (Exon 7) is covered only by WES_KIT_V2. The 120 samples sequenced with V1 have no data at this position. The correct AN is 80 × 2 = **160** — but a naïve calculation that ignores capture boundaries would use 200 × 2 = 400, **underestimating AF by more than half**. A variant with AC = 5 would appear to have AF = 1.25% (5/400) instead of the true 3.13% (5/160) — enough to cross PM2 filtering thresholds and mislead clinical interpretation.
49
+
50
+ This is not hypothetical. In the Alzheimer's Disease Sequencing Project, hidden variant-level batch effects between two exome capture kits **significantly impacted disease-associated variant identification**, with a subset of top risk variants originating exclusively from one kit [(Wickland et al., 2021)](https://pubmed.ncbi.nlm.nih.gov/33861770/). A population-based WES study found that separating samples by capture protocol yielded **40.9% more high-quality variants** than pooling them [(Carson et al., 2014)](https://pubmed.ncbi.nlm.nih.gov/24884706/).
51
+
52
+ No general-purpose VCF tool automates per-position, per-technology AN computation across dozens of BED files.
53
+
54
+ ---
55
+
56
+ ## Gap 3 — Static Tools Require Reprocessing
57
+
58
+ Standard VCF tools — bcftools, VCFtools, GATK — operate on static VCF files. Computing AF over a different sample subset requires:
59
+
60
+ 1. Selecting samples by external metadata
61
+ 2. Subsetting the VCF
62
+ 3. Running AF computation
63
+ 4. Repeating for each new subset
64
+
65
+ This is adequate for one-time analyses but prohibitive for interactive clinical variant interpretation, where a geneticist may need AF across dozens of subsets in a single session: by sex, by phenotype, by technology, by combinations thereof.
66
+
67
+ For a cohort of 10,000 samples with 5 million variants, reprocessing takes minutes per subset. At 20 subsets per clinical session, the wall time is measured in hours — turning what should be an interactive workflow into a batch job.
68
+
69
+ ---
70
+
71
+ ## Gap 4 — No Metadata-Aware Filtering
72
+
73
+ Computing AF over "female WGS samples tagged with phenotype E11.9, excluding those also tagged I42" requires orchestrating multiple tools: extract sample IDs from a metadata database, subset the VCF, compute statistics. This multi-step process is error-prone (sample ID mismatches, off-by-one in subsetting) and precludes real-time exploratory analysis.
74
+
75
+ The lack of integrated metadata filtering is particularly problematic for:
76
+
77
+ - **Pseudo-control analysis** — computing AF in all samples *except* those with a specific disease to assess case enrichment (ACMG PS4)
78
+ - **Sex-stratified AF** — essential for X-linked variant interpretation, where males and females have different ploidy
79
+ - **Technology-stratified QC** — identifying variants that appear only in one sequencing technology, suggesting artifacts rather than true variation
80
+
81
+ ---
82
+
83
+ ## How AFQuery Addresses These Gaps
84
+
85
+ AFQuery introduces a pre-indexed database architecture that separates the slow step (building the genotype index from VCFs) from the fast step (querying AF on arbitrary subgroups).
86
+
87
+ The key data structure is the [Roaring Bitmap](https://roaringbitmap.org/) — a compressed bitset that records, for each variant, which samples carry the alternate allele. At query time, computing AC/AN/AF requires only:
88
+
89
+ 1. Loading the variant's carrier bitmap from Parquet storage
90
+ 2. Intersecting with the bitmap of eligible samples (determined by sex, phenotype, and capture filters)
91
+ 3. Counting set bits (popcount)
92
+
93
+ This reduces each query to microsecond-scale bitmap operations, achieving sub-100 ms end-to-end latency including Parquet I/O — regardless of cohort size.
94
+
95
+ | Gap | Existing tools | AFQuery |
96
+ |-----|---------------|---------|
97
+ | Population-specific AF | Compare against gnomAD; build separate databases per population | Compute AF on any phenotype-defined subgroup at query time |
98
+ | Mixed technologies | Manual BED intersection or ignore the problem | Automatic per-position, per-technology AN via capture index |
99
+ | Reprocessing | Re-scan VCF per subset (minutes) | Bitmap intersection (milliseconds) |
100
+ | Metadata filtering | Multi-step: extract IDs → subset VCF → compute | Single query with `--phenotype`, `--sex`, `--tech` flags |
101
+
102
+ ---
103
+
104
+ ## Next Steps
105
+
106
+ - [Installation](installation.md) — get started
107
+ - [Key Concepts](concepts.md) — how bitmaps, Parquet, and metadata filtering work together
108
+ - [ACMG Criteria](../use-cases/acmg-use-cases.md) — applying local AF to BA1, PM2, and PS4
@@ -33,3 +33,11 @@ Male samples should have haploid genotype calls at chrX non-PAR regions (GT=`1`,
33
33
  - **Non-PASS genotypes**: Masking them as missing ensures that low-quality calls do not inflate AC. AFQuery tracks these as N_FAIL.
34
34
  - **Homozygous reference calls**: Removing ref/ref genotypes reduces file size and speeds ingestion; they contribute AC=0 and are not needed
35
35
  - **INFO fields**: Stripping INFO reduces file size and speeds ingestion. Additionally, malformed or non-standard INFO fields produced by some variant callers can break downstream parsing; stripping them pre-emptively prevents these errors.
36
+
37
+ ---
38
+
39
+ ## Next Steps
40
+
41
+ - [Manifest Format](../guides/manifest-format.md) — describe your cohort samples for ingestion
42
+ - [Create a Database](../guides/create-database.md) — build the AFQuery database from normalized VCFs
43
+ - [5-Min Quickstart](quickstart.md) — end-to-end tutorial from manifest to first query
@@ -2,6 +2,9 @@
2
2
 
3
3
  This tutorial walks through building a small AFQuery database and running your first queries. It takes about 5 minutes.
4
4
 
5
+ !!! tip "New to AFQuery?"
6
+ If you want to understand how bitmaps, Parquet storage, and metadata filtering work together before diving in, read [Key Concepts](concepts.md) first. Otherwise, follow along — you can always come back to the theory later.
7
+
5
8
  !!! tip "Normalize your VCFs first"
6
9
  AFQuery works best with normalized, left-aligned VCFs with ploidy-corrected sex chromosome calls. See [VCF Preprocessing](preprocessing.md) for a reference normalization pipeline using bcftools.
7
10
 
@@ -19,6 +22,7 @@ SAMPLE_003 /data/vcfs/sample003.vcf.gz female wes_v1 I10
19
22
  ```
20
23
 
21
24
  Fields:
25
+
22
26
  - `sample_name`: unique identifier
23
27
  - `vcf_path`: path to single-sample VCF (plain or `.gz`)
24
28
  - `sex`: `male` or `female`
@@ -79,12 +83,26 @@ afquery query \
79
83
  --phenotype E11.9
80
84
  ```
81
85
 
86
+ See [Sample Filtering](../guides/sample-filtering.md) for the full include/exclude syntax.
87
+
82
88
  !!! note "Warnings for missing data"
83
89
  If a phenotype code, technology name, or chromosome is not found in the database, afquery prints a warning to stderr and returns empty results. Use `--no-warn` to suppress these warnings.
84
90
 
85
91
  ---
86
92
 
87
- ## 5. Query a Region
93
+ ## 5. Inspect Carriers (optional)
94
+
95
+ See which samples carry the variant you just queried:
96
+
97
+ ```bash
98
+ afquery variant-info --db ./my_db/ --locus chr1:925952
99
+ ```
100
+
101
+ This lists each carrier with their sex, technology, phenotype codes, genotype (het/hom), and FILTER status. See [Variant Info](../guides/variant-info.md) for details.
102
+
103
+ ---
104
+
105
+ ## 6. Query a Region
88
106
 
89
107
  ```bash
90
108
  afquery query \
@@ -94,7 +112,7 @@ afquery query \
94
112
 
95
113
  ---
96
114
 
97
- ## 6. Annotate a VCF
115
+ ## 7. Annotate a VCF
98
116
 
99
117
  Given a VCF with variants you want to annotate:
100
118
 
@@ -106,7 +124,7 @@ afquery annotate \
106
124
  --threads 12
107
125
  ```
108
126
 
109
- The output VCF gains INFO fields:
127
+ The output VCF gains INFO fields (see [Annotate a VCF](../guides/annotate-vcf.md) for parallelism options and downstream usage):
110
128
 
111
129
  | Field | Number | Description |
112
130
  |-------|--------|-------------|
@@ -118,4 +136,12 @@ The output VCF gains INFO fields:
118
136
  | `AFQUERY_N_HOM_REF` | A (per ALT) | Homozygous ref sample count |
119
137
  | `AFQUERY_N_FAIL` | 1 (per site) | Samples with FILTER≠PASS |
120
138
 
139
+ ---
140
+
141
+ ## Next Steps
121
142
 
143
+ - [Key Concepts](concepts.md) — understand how bitmaps, Parquet, and metadata filtering work together
144
+ - [Sample Filtering](../guides/sample-filtering.md) — full syntax for phenotype, sex, and technology filters
145
+ - [Variant Info](../guides/variant-info.md) — list carriers of any variant with metadata
146
+ - [Annotate a VCF](../guides/annotate-vcf.md) — annotation options, parallelism, and downstream usage
147
+ - [ACMG Criteria](../use-cases/acmg-use-cases.md) — applying local AF to BA1, PM2, and PS4