pylocuszoom 1.1.2__tar.gz → 1.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.
Files changed (115) hide show
  1. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.gitignore +4 -0
  2. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/CHANGELOG.md +25 -0
  3. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/PKG-INFO +18 -11
  4. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/README.md +16 -10
  5. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/docs/USER_GUIDE.md +44 -211
  6. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/generate_example_plots.py +10 -13
  7. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/pyproject.toml +2 -1
  8. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/__init__.py +4 -0
  9. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/finemapping.py +111 -3
  10. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/plotter.py +11 -336
  11. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/recombination.py +39 -0
  12. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/conftest.py +19 -3
  13. pylocuszoom-1.2.0/tests/strategies.py +312 -0
  14. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_backend_bugs.py +6 -5
  15. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_colors.py +71 -0
  16. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_edge_cases.py +10 -7
  17. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_finemapping.py +96 -0
  18. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_gene_track.py +70 -0
  19. pylocuszoom-1.2.0/tests/test_init.py +15 -0
  20. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_manhattan.py +39 -0
  21. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_phewas.py +2 -2
  22. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_plotter.py +174 -182
  23. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_plotter_manhattan_qq.py +19 -19
  24. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_qq.py +44 -0
  25. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_recombination.py +77 -0
  26. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_validation.py +66 -0
  27. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/uv.lock +25 -1
  28. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.gitattributes +0 -0
  29. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  30. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  31. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  32. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.github/workflows/ci.yml +0 -0
  33. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.github/workflows/publish.yml +0 -0
  34. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/.pre-commit-config.yaml +0 -0
  35. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/CONTRIBUTING.md +0 -0
  36. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/LICENSE.md +0 -0
  37. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/bioconda/meta.yaml +0 -0
  38. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/docs/ARCHITECTURE.md +0 -0
  39. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/docs/CODEMAP.md +0 -0
  40. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/eqtl_bokeh.html +0 -0
  41. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/eqtl_overlay.png +0 -0
  42. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/eqtl_plotly.html +0 -0
  43. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/finemapping_bokeh.html +0 -0
  44. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/finemapping_plot.png +0 -0
  45. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/finemapping_plotly.html +0 -0
  46. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/forest_plot.png +0 -0
  47. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/getting_started.ipynb +0 -0
  48. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_bokeh.html +0 -0
  49. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_plot.png +0 -0
  50. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_plotly.html +0 -0
  51. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_qq_bokeh.html +0 -0
  52. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_qq_canine.png +0 -0
  53. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_qq_plotly.html +0 -0
  54. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_qq_sidebyside.png +0 -0
  55. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_qq_stacked.png +0 -0
  56. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_qq_stacked_bokeh.html +0 -0
  57. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_qq_stacked_plotly.html +0 -0
  58. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_stacked.png +0 -0
  59. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_stacked_bokeh.html +0 -0
  60. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/manhattan_stacked_plotly.html +0 -0
  61. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/phewas_plot.png +0 -0
  62. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/qq_bokeh.html +0 -0
  63. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/qq_plot.png +0 -0
  64. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/qq_plotly.html +0 -0
  65. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/regional_plot.png +0 -0
  66. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/regional_plot_with_recomb.png +0 -0
  67. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/regional_recomb_bokeh.html +0 -0
  68. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/regional_recomb_plotly.html +0 -0
  69. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/examples/stacked_plot.png +0 -0
  70. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/logo.svg +0 -0
  71. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/_plotter_utils.py +0 -0
  72. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/backends/__init__.py +0 -0
  73. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/backends/base.py +0 -0
  74. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/backends/bokeh_backend.py +0 -0
  75. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/backends/hover.py +0 -0
  76. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/backends/matplotlib_backend.py +0 -0
  77. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/backends/plotly_backend.py +0 -0
  78. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/colors.py +0 -0
  79. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/config.py +0 -0
  80. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/ensembl.py +0 -0
  81. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/eqtl.py +0 -0
  82. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/exceptions.py +0 -0
  83. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/forest.py +0 -0
  84. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/gene_track.py +0 -0
  85. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/labels.py +0 -0
  86. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/ld.py +0 -0
  87. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/loaders.py +0 -0
  88. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/logging.py +0 -0
  89. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/manhattan.py +0 -0
  90. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/manhattan_plotter.py +0 -0
  91. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/phewas.py +0 -0
  92. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/py.typed +0 -0
  93. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/qq.py +0 -0
  94. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/reference_data/__init__.py +0 -0
  95. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/schemas.py +0 -0
  96. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/stats_plotter.py +0 -0
  97. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/utils.py +0 -0
  98. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/src/pylocuszoom/validation.py +0 -0
  99. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_backends.py +0 -0
  100. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_config.py +0 -0
  101. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_ensembl.py +0 -0
  102. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_ensembl_integration.py +0 -0
  103. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_eqtl.py +0 -0
  104. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_exceptions.py +0 -0
  105. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_forest.py +0 -0
  106. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_hover.py +0 -0
  107. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_labels.py +0 -0
  108. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_ld.py +0 -0
  109. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_loaders.py +0 -0
  110. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_logging.py +0 -0
  111. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_manhattan_plotter.py +0 -0
  112. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_notebook_backends.py +0 -0
  113. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_plotter_utils.py +0 -0
  114. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_stats_plotter.py +0 -0
  115. {pylocuszoom-1.1.2 → pylocuszoom-1.2.0}/tests/test_utils.py +0 -0
@@ -14,6 +14,7 @@ build/
14
14
  .benchmarks/
15
15
  .coverage
16
16
  htmlcov/
17
+ .hypothesis/
17
18
 
18
19
  # IDE
19
20
  .idea/
@@ -21,6 +22,9 @@ htmlcov/
21
22
  *.swp
22
23
  .claude/
23
24
 
25
+ # Git worktrees
26
+ .worktrees/
27
+
24
28
  # Issue tracking (local)
25
29
  .beads/
26
30
 
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [1.2.0] - 2026-02-02
11
+
12
+ ### Added
13
+
14
+ - Property-based testing with Hypothesis library for improved test coverage
15
+ - `tests/strategies.py` module with reusable GWAS data generators
16
+ - Hypothesis test profiles (ci/dev/debug) for configurable test intensity
17
+ - Property tests for validation, colors, plotter, gene track, Manhattan, and QQ modules
18
+ - `ensure_recomb_maps()` function exported from package for pre-downloading recombination data
19
+ - `plot_finemapping()` function exported from package for standalone fine-mapping plots
20
+
21
+ ### Changed
22
+
23
+ - **BREAKING**: Removed deprecated wrapper methods from `LocusZoomPlotter`
24
+ - Removed: `plot_manhattan()`, `plot_qq()`, `plot_manhattan_stacked()`, `plot_manhattan_qq()`, `plot_manhattan_qq_stacked()` — use `ManhattanPlotter` instead
25
+ - Removed: `plot_phewas()`, `plot_forest()` — use `StatsPlotter` instead
26
+
27
+ ### Internal
28
+
29
+ - Test count increased from 667 to 690 with hypothesis property tests
30
+ - Removed unused `OPTIONAL_FINEMAPPING_COLS` constant from finemapping module
31
+
8
32
  ## [1.1.2] - 2026-01-30
9
33
 
10
34
  ### Fixed
@@ -271,6 +295,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
271
295
  - bokeh >= 3.8.2
272
296
  - kaleido >= 0.2.0
273
297
 
298
+ [1.2.0]: https://github.com/michael-denyer/pyLocusZoom/compare/v1.1.2...v1.2.0
274
299
  [1.1.2]: https://github.com/michael-denyer/pyLocusZoom/compare/v1.1.1...v1.1.2
275
300
  [1.1.1]: https://github.com/michael-denyer/pyLocusZoom/compare/v1.1.0...v1.1.1
276
301
  [1.1.0]: https://github.com/michael-denyer/pyLocusZoom/compare/v1.0.2...v1.1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pylocuszoom
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: Publication-ready regional association plots with LD coloring, gene tracks, and recombination overlays
5
5
  Project-URL: Homepage, https://github.com/michael-denyer/pylocuszoom
6
6
  Project-URL: Documentation, https://github.com/michael-denyer/pylocuszoom#readme
@@ -35,6 +35,7 @@ Requires-Dist: tqdm>=4.60.0
35
35
  Provides-Extra: all
36
36
  Requires-Dist: pyspark>=3.0.0; extra == 'all'
37
37
  Provides-Extra: dev
38
+ Requires-Dist: hypothesis>=6.0.0; extra == 'dev'
38
39
  Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
39
40
  Requires-Dist: pytest-randomly>=3.0.0; extra == 'dev'
40
41
  Requires-Dist: pytest-xdist>=3.0.0; extra == 'dev'
@@ -320,13 +321,16 @@ fig = plotter.plot_stacked(
320
321
  Visualize associations of a single variant across multiple phenotypes:
321
322
 
322
323
  ```python
324
+ from pylocuszoom import StatsPlotter
325
+
323
326
  phewas_df = pd.DataFrame({
324
327
  "phenotype": ["Height", "BMI", "T2D", "CAD", "HDL"],
325
328
  "p_value": [1e-15, 0.05, 1e-8, 1e-3, 1e-10],
326
329
  "category": ["Anthropometric", "Anthropometric", "Metabolic", "Cardiovascular", "Lipids"],
327
330
  })
328
331
 
329
- fig = plotter.plot_phewas(
332
+ stats_plotter = StatsPlotter()
333
+ fig = stats_plotter.plot_phewas(
330
334
  phewas_df,
331
335
  variant_id="rs12345",
332
336
  category_col="category",
@@ -341,6 +345,8 @@ fig = plotter.plot_phewas(
341
345
  Create forest plots for meta-analysis visualization:
342
346
 
343
347
  ```python
348
+ from pylocuszoom import StatsPlotter
349
+
344
350
  forest_df = pd.DataFrame({
345
351
  "study": ["Study A", "Study B", "Study C", "Meta-analysis"],
346
352
  "effect": [0.45, 0.52, 0.38, 0.46],
@@ -349,7 +355,8 @@ forest_df = pd.DataFrame({
349
355
  "weight": [25, 35, 20, 100],
350
356
  })
351
357
 
352
- fig = plotter.plot_forest(
358
+ stats_plotter = StatsPlotter()
359
+ fig = stats_plotter.plot_forest(
353
360
  forest_df,
354
361
  variant_id="rs12345",
355
362
  weight_col="weight",
@@ -364,9 +371,9 @@ fig = plotter.plot_forest(
364
371
  Create genome-wide Manhattan plots showing associations across all chromosomes:
365
372
 
366
373
  ```python
367
- from pylocuszoom import LocusZoomPlotter
374
+ from pylocuszoom import ManhattanPlotter
368
375
 
369
- plotter = LocusZoomPlotter(species="human")
376
+ plotter = ManhattanPlotter(species="human")
370
377
 
371
378
  fig = plotter.plot_manhattan(
372
379
  gwas_df,
@@ -397,9 +404,9 @@ fig = plotter.plot_manhattan(
397
404
  Create quantile-quantile plots to assess p-value distribution:
398
405
 
399
406
  ```python
400
- from pylocuszoom import LocusZoomPlotter
407
+ from pylocuszoom import ManhattanPlotter
401
408
 
402
- plotter = LocusZoomPlotter()
409
+ plotter = ManhattanPlotter()
403
410
 
404
411
  fig = plotter.plot_qq(
405
412
  gwas_df,
@@ -419,9 +426,9 @@ fig.savefig("qq_plot.png", dpi=150)
419
426
  Compare multiple GWAS results in vertically stacked Manhattan plots:
420
427
 
421
428
  ```python
422
- from pylocuszoom import LocusZoomPlotter
429
+ from pylocuszoom import ManhattanPlotter
423
430
 
424
- plotter = LocusZoomPlotter()
431
+ plotter = ManhattanPlotter()
425
432
 
426
433
  fig = plotter.plot_manhattan_stacked(
427
434
  [gwas_study1, gwas_study2, gwas_study3],
@@ -444,9 +451,9 @@ fig.savefig("manhattan_stacked.png", dpi=150)
444
451
  Create combined Manhattan and QQ plots in a single figure:
445
452
 
446
453
  ```python
447
- from pylocuszoom import LocusZoomPlotter
454
+ from pylocuszoom import ManhattanPlotter
448
455
 
449
- plotter = LocusZoomPlotter()
456
+ plotter = ManhattanPlotter()
450
457
 
451
458
  fig = plotter.plot_manhattan_qq(
452
459
  gwas_df,
@@ -274,13 +274,16 @@ fig = plotter.plot_stacked(
274
274
  Visualize associations of a single variant across multiple phenotypes:
275
275
 
276
276
  ```python
277
+ from pylocuszoom import StatsPlotter
278
+
277
279
  phewas_df = pd.DataFrame({
278
280
  "phenotype": ["Height", "BMI", "T2D", "CAD", "HDL"],
279
281
  "p_value": [1e-15, 0.05, 1e-8, 1e-3, 1e-10],
280
282
  "category": ["Anthropometric", "Anthropometric", "Metabolic", "Cardiovascular", "Lipids"],
281
283
  })
282
284
 
283
- fig = plotter.plot_phewas(
285
+ stats_plotter = StatsPlotter()
286
+ fig = stats_plotter.plot_phewas(
284
287
  phewas_df,
285
288
  variant_id="rs12345",
286
289
  category_col="category",
@@ -295,6 +298,8 @@ fig = plotter.plot_phewas(
295
298
  Create forest plots for meta-analysis visualization:
296
299
 
297
300
  ```python
301
+ from pylocuszoom import StatsPlotter
302
+
298
303
  forest_df = pd.DataFrame({
299
304
  "study": ["Study A", "Study B", "Study C", "Meta-analysis"],
300
305
  "effect": [0.45, 0.52, 0.38, 0.46],
@@ -303,7 +308,8 @@ forest_df = pd.DataFrame({
303
308
  "weight": [25, 35, 20, 100],
304
309
  })
305
310
 
306
- fig = plotter.plot_forest(
311
+ stats_plotter = StatsPlotter()
312
+ fig = stats_plotter.plot_forest(
307
313
  forest_df,
308
314
  variant_id="rs12345",
309
315
  weight_col="weight",
@@ -318,9 +324,9 @@ fig = plotter.plot_forest(
318
324
  Create genome-wide Manhattan plots showing associations across all chromosomes:
319
325
 
320
326
  ```python
321
- from pylocuszoom import LocusZoomPlotter
327
+ from pylocuszoom import ManhattanPlotter
322
328
 
323
- plotter = LocusZoomPlotter(species="human")
329
+ plotter = ManhattanPlotter(species="human")
324
330
 
325
331
  fig = plotter.plot_manhattan(
326
332
  gwas_df,
@@ -351,9 +357,9 @@ fig = plotter.plot_manhattan(
351
357
  Create quantile-quantile plots to assess p-value distribution:
352
358
 
353
359
  ```python
354
- from pylocuszoom import LocusZoomPlotter
360
+ from pylocuszoom import ManhattanPlotter
355
361
 
356
- plotter = LocusZoomPlotter()
362
+ plotter = ManhattanPlotter()
357
363
 
358
364
  fig = plotter.plot_qq(
359
365
  gwas_df,
@@ -373,9 +379,9 @@ fig.savefig("qq_plot.png", dpi=150)
373
379
  Compare multiple GWAS results in vertically stacked Manhattan plots:
374
380
 
375
381
  ```python
376
- from pylocuszoom import LocusZoomPlotter
382
+ from pylocuszoom import ManhattanPlotter
377
383
 
378
- plotter = LocusZoomPlotter()
384
+ plotter = ManhattanPlotter()
379
385
 
380
386
  fig = plotter.plot_manhattan_stacked(
381
387
  [gwas_study1, gwas_study2, gwas_study3],
@@ -398,9 +404,9 @@ fig.savefig("manhattan_stacked.png", dpi=150)
398
404
  Create combined Manhattan and QQ plots in a single figure:
399
405
 
400
406
  ```python
401
- from pylocuszoom import LocusZoomPlotter
407
+ from pylocuszoom import ManhattanPlotter
402
408
 
403
- plotter = LocusZoomPlotter()
409
+ plotter = ManhattanPlotter()
404
410
 
405
411
  fig = plotter.plot_manhattan_qq(
406
412
  gwas_df,
@@ -27,13 +27,6 @@ Comprehensive documentation for pyLocusZoom - regional association plots for GWA
27
27
  - [LocusZoomPlotter](#locuszoomplotter)
28
28
  - [plot() Method](#plot-method)
29
29
  - [plot_stacked() Method](#plot_stacked-method)
30
- - [plot_manhattan() Method](#plot_manhattan-method)
31
- - [plot_qq() Method](#plot_qq-method)
32
- - [plot_manhattan_stacked() Method](#plot_manhattan_stacked-method)
33
- - [plot_manhattan_qq() Method](#plot_manhattan_qq-method)
34
- - [plot_manhattan_qq_stacked() Method](#plot_manhattan_qq_stacked-method)
35
- - [plot_phewas() Method](#plot_phewas-method)
36
- - [plot_forest() Method](#plot_forest-method)
37
30
  - [File Loaders](#file-loaders)
38
31
  - [GWAS Loaders](#gwas-loaders)
39
32
  - [eQTL Loaders](#eqtl-loaders)
@@ -231,12 +224,15 @@ Visualize associations of a single variant across multiple phenotypes in a pheno
231
224
  ![PheWAS plot](../examples/phewas_plot.png)
232
225
 
233
226
  ```python
227
+ from pylocuszoom import StatsPlotter
228
+
234
229
  phewas_df = pd.DataFrame({
235
230
  "phenotype": ["Height", "BMI", "T2D", "CAD", "HDL"],
236
231
  "p_value": [1e-15, 0.05, 1e-8, 1e-3, 1e-10],
237
232
  "category": ["Anthropometric", "Anthropometric", "Metabolic", "Cardiovascular", "Lipids"],
238
233
  })
239
234
 
235
+ plotter = StatsPlotter()
240
236
  fig = plotter.plot_phewas(
241
237
  phewas_df,
242
238
  variant_id="rs12345",
@@ -258,6 +254,8 @@ Create forest plots for meta-analysis visualization showing effect sizes with co
258
254
  ![Forest plot](../examples/forest_plot.png)
259
255
 
260
256
  ```python
257
+ from pylocuszoom import StatsPlotter
258
+
261
259
  forest_df = pd.DataFrame({
262
260
  "study": ["Study A", "Study B", "Study C", "Meta-analysis"],
263
261
  "effect": [0.45, 0.52, 0.38, 0.46],
@@ -266,6 +264,7 @@ forest_df = pd.DataFrame({
266
264
  "weight": [25, 35, 20, 100], # Optional: affects marker size
267
265
  })
268
266
 
267
+ plotter = StatsPlotter()
269
268
  fig = plotter.plot_forest(
270
269
  forest_df,
271
270
  variant_id="rs12345",
@@ -288,6 +287,9 @@ Genome-wide Manhattan plots showing associations across all chromosomes.
288
287
  ![Manhattan plot](../examples/manhattan_plot.png)
289
288
 
290
289
  ```python
290
+ from pylocuszoom import ManhattanPlotter
291
+
292
+ plotter = ManhattanPlotter()
291
293
  fig = plotter.plot_manhattan(
292
294
  gwas_df,
293
295
  chrom_col="chrom",
@@ -312,6 +314,9 @@ Quantile-quantile plots for assessing p-value distribution and detecting systema
312
314
  ![QQ plot](../examples/qq_plot.png)
313
315
 
314
316
  ```python
317
+ from pylocuszoom import ManhattanPlotter
318
+
319
+ plotter = ManhattanPlotter()
315
320
  fig = plotter.plot_qq(
316
321
  gwas_df,
317
322
  p_col="p",
@@ -335,6 +340,9 @@ Compare multiple GWAS studies in vertically stacked Manhattan plots with shared
335
340
  ![Stacked Manhattan plot](../examples/manhattan_stacked.png)
336
341
 
337
342
  ```python
343
+ from pylocuszoom import ManhattanPlotter
344
+
345
+ plotter = ManhattanPlotter()
338
346
  fig = plotter.plot_manhattan_stacked(
339
347
  [gwas_study1, gwas_study2, gwas_study3],
340
348
  chrom_col="chrom",
@@ -362,6 +370,9 @@ Combined Manhattan and QQ plots in a single figure for comprehensive GWAS summar
362
370
  ![Manhattan and QQ side-by-side](../examples/manhattan_qq_sidebyside.png)
363
371
 
364
372
  ```python
373
+ from pylocuszoom import ManhattanPlotter
374
+
375
+ plotter = ManhattanPlotter()
365
376
  fig = plotter.plot_manhattan_qq(
366
377
  gwas_df,
367
378
  chrom_col="chrom",
@@ -448,6 +459,32 @@ save(fig)
448
459
 
449
460
  ## API Reference
450
461
 
462
+ ### Specialized Plotter Classes
463
+
464
+ pyLocusZoom provides specialized plotter classes for different plot types:
465
+
466
+ | Class | Purpose |
467
+ |-------|---------|
468
+ | `LocusZoomPlotter` | Regional association plots with LD coloring |
469
+ | `ManhattanPlotter` | Genome-wide Manhattan and QQ plots |
470
+ | `StatsPlotter` | PheWAS and forest plots |
471
+
472
+ ```python
473
+ from pylocuszoom import LocusZoomPlotter, ManhattanPlotter, StatsPlotter
474
+
475
+ # Regional plots
476
+ regional = LocusZoomPlotter(species="canine")
477
+ fig = regional.plot(gwas_df, chrom=1, start=1e6, end=2e6)
478
+
479
+ # Manhattan/QQ plots
480
+ manhattan = ManhattanPlotter()
481
+ fig = manhattan.plot_manhattan(gwas_df)
482
+
483
+ # PheWAS/forest plots
484
+ stats = StatsPlotter()
485
+ fig = stats.plot_phewas(phewas_df, variant_id="rs12345")
486
+ ```
487
+
451
488
  ### LocusZoomPlotter
452
489
 
453
490
  The main class for creating regional association plots.
@@ -582,210 +619,6 @@ fig = plotter.plot_stacked(
582
619
  | `finemapping_cs_col` | str | `"cs"` | Column for credible set assignment. |
583
620
  | `recomb_df` | DataFrame | None | Custom recombination data. |
584
621
 
585
- ### plot_manhattan() Method
586
-
587
- Create a genome-wide Manhattan plot showing associations across all chromosomes.
588
-
589
- ```python
590
- fig = plotter.plot_manhattan(
591
- gwas_df, # Required: GWAS results
592
- chrom_col="chrom", # Chromosome column
593
- pos_col="pos", # Position column
594
- p_col="p", # P-value column
595
- custom_chrom_order=None, # Custom chromosome order
596
- significance_threshold=5e-8, # Genome-wide significance line
597
- figsize=(12, 5), # Figure dimensions
598
- )
599
- ```
600
-
601
- | Parameter | Type | Default | Description |
602
- |-----------|------|---------|-------------|
603
- | `gwas_df` | DataFrame | Required | GWAS results with chromosome, position, and p-value columns. |
604
- | `chrom_col` | str | `"chrom"` | Chromosome column name. |
605
- | `pos_col` | str | `"pos"` | Position column name. |
606
- | `p_col` | str | `"p"` | P-value column name. |
607
- | `custom_chrom_order` | list | None | Custom order for chromosomes (e.g., `["1", "2", ..., "X"]`). |
608
- | `significance_threshold` | float | `5e-8` | P-value threshold for significance line. |
609
- | `figsize` | tuple | `(12, 5)` | Figure dimensions (width, height). |
610
-
611
- ### plot_qq() Method
612
-
613
- Create a quantile-quantile (QQ) plot to assess p-value distribution.
614
-
615
- ```python
616
- fig = plotter.plot_qq(
617
- gwas_df, # Required: GWAS results
618
- p_col="p", # P-value column
619
- show_confidence_band=True, # 95% confidence band
620
- show_lambda=True, # Genomic inflation factor
621
- figsize=(6, 6), # Figure dimensions
622
- )
623
- ```
624
-
625
- | Parameter | Type | Default | Description |
626
- |-----------|------|---------|-------------|
627
- | `gwas_df` | DataFrame | Required | GWAS results with p-value column. |
628
- | `p_col` | str | `"p"` | P-value column name. |
629
- | `show_confidence_band` | bool | `True` | Whether to show 95% confidence band. |
630
- | `show_lambda` | bool | `True` | Whether to show genomic inflation factor (λ) in title. |
631
- | `figsize` | tuple | `(6, 6)` | Figure dimensions (width, height). |
632
-
633
- ### plot_manhattan_stacked() Method
634
-
635
- Create stacked Manhattan plots for comparing multiple GWAS studies.
636
-
637
- ```python
638
- fig = plotter.plot_manhattan_stacked(
639
- gwas_dfs, # Required: list of GWAS DataFrames
640
- chrom_col="chrom", # Chromosome column
641
- pos_col="pos", # Position column
642
- p_col="p", # P-value column
643
- custom_chrom_order=None, # Custom chromosome order
644
- significance_threshold=5e-8, # Genome-wide significance line
645
- panel_labels=None, # Labels for each panel
646
- figsize=(12, 8), # Figure dimensions
647
- title=None, # Overall figure title
648
- )
649
- ```
650
-
651
- | Parameter | Type | Default | Description |
652
- |-----------|------|---------|-------------|
653
- | `gwas_dfs` | list | Required | List of GWAS DataFrames. |
654
- | `chrom_col` | str | `"chrom"` | Chromosome column name. |
655
- | `pos_col` | str | `"pos"` | Position column name. |
656
- | `p_col` | str | `"p"` | P-value column name. |
657
- | `custom_chrom_order` | list | None | Custom order for chromosomes. |
658
- | `significance_threshold` | float | `5e-8` | P-value threshold for significance line. |
659
- | `panel_labels` | list | None | Labels for each panel (defaults to "Study 1", "Study 2", etc.). |
660
- | `figsize` | tuple | `(12, 8)` | Figure dimensions (width, height). |
661
- | `title` | str | None | Overall figure title (suptitle). |
662
-
663
- ### plot_manhattan_qq() Method
664
-
665
- Create a combined Manhattan and QQ plot side-by-side in a single figure.
666
-
667
- ```python
668
- fig = plotter.plot_manhattan_qq(
669
- gwas_df, # Required: GWAS results
670
- chrom_col="chrom", # Chromosome column
671
- pos_col="pos", # Position column
672
- p_col="p", # P-value column
673
- custom_chrom_order=None, # Custom chromosome order
674
- significance_threshold=5e-8, # Genome-wide significance line
675
- show_confidence_band=True, # 95% confidence band on QQ
676
- show_lambda=True, # Genomic inflation factor on QQ
677
- figsize=(14, 5), # Figure dimensions
678
- title=None, # Overall figure title
679
- )
680
- ```
681
-
682
- | Parameter | Type | Default | Description |
683
- |-----------|------|---------|-------------|
684
- | `gwas_df` | DataFrame | Required | GWAS results with chromosome, position, and p-value columns. |
685
- | `chrom_col` | str | `"chrom"` | Chromosome column name. |
686
- | `pos_col` | str | `"pos"` | Position column name. |
687
- | `p_col` | str | `"p"` | P-value column name. |
688
- | `custom_chrom_order` | list | None | Custom order for chromosomes. |
689
- | `significance_threshold` | float | `5e-8` | P-value threshold for significance line. |
690
- | `show_confidence_band` | bool | `True` | Whether to show 95% confidence band on QQ plot. |
691
- | `show_lambda` | bool | `True` | Whether to show genomic inflation factor (λ) on QQ plot. |
692
- | `figsize` | tuple | `(14, 5)` | Figure dimensions (width, height). |
693
- | `title` | str | None | Overall figure title (suptitle). |
694
-
695
- ### plot_manhattan_qq_stacked() Method
696
-
697
- Create stacked Manhattan+QQ plot pairs for comparing multiple GWAS studies.
698
-
699
- ```python
700
- fig = plotter.plot_manhattan_qq_stacked(
701
- gwas_dfs, # Required: list of GWAS DataFrames
702
- chrom_col="chrom", # Chromosome column
703
- pos_col="pos", # Position column
704
- p_col="p", # P-value column
705
- custom_chrom_order=None, # Custom chromosome order
706
- significance_threshold=5e-8, # Genome-wide significance line
707
- show_confidence_band=True, # 95% confidence band on QQ
708
- show_lambda=True, # Genomic inflation factor on QQ
709
- panel_labels=None, # Labels for each study
710
- figsize=(14, 8), # Figure dimensions
711
- title=None, # Overall figure title
712
- )
713
- ```
714
-
715
- | Parameter | Type | Default | Description |
716
- |-----------|------|---------|-------------|
717
- | `gwas_dfs` | list | Required | List of GWAS DataFrames to compare. |
718
- | `chrom_col` | str | `"chrom"` | Chromosome column name. |
719
- | `pos_col` | str | `"pos"` | Position column name. |
720
- | `p_col` | str | `"p"` | P-value column name. |
721
- | `custom_chrom_order` | list | None | Custom order for chromosomes. |
722
- | `significance_threshold` | float | `5e-8` | P-value threshold for significance line. |
723
- | `show_confidence_band` | bool | `True` | Whether to show 95% confidence band on QQ plots. |
724
- | `show_lambda` | bool | `True` | Whether to show genomic inflation factor (λ) on QQ plots. |
725
- | `panel_labels` | list | None | Labels for each panel (defaults to "Study 1", "Study 2", etc.). |
726
- | `figsize` | tuple | `(14, 8)` | Figure dimensions (width, height). |
727
- | `title` | str | None | Overall figure title (suptitle). |
728
-
729
- ### plot_phewas() Method
730
-
731
- Create a PheWAS (Phenome-Wide Association Study) plot.
732
-
733
- ```python
734
- fig = plotter.plot_phewas(
735
- phewas_df, # Required: PheWAS results
736
- variant_id="rs12345", # Required: variant ID for title
737
- phenotype_col="phenotype", # Phenotype name column
738
- p_col="p_value", # P-value column
739
- category_col="category", # Category for grouping/coloring
740
- effect_col=None, # Effect column for direction markers
741
- significance_threshold=5e-8, # Significance line threshold
742
- figsize=(10, 8), # Figure dimensions
743
- )
744
- ```
745
-
746
- | Parameter | Type | Default | Description |
747
- |-----------|------|---------|-------------|
748
- | `phewas_df` | DataFrame | Required | PheWAS results with phenotype and p-value. |
749
- | `variant_id` | str | Required | Variant ID for plot title. |
750
- | `phenotype_col` | str | `"phenotype"` | Column with phenotype names. |
751
- | `p_col` | str | `"p_value"` | Column with p-values. |
752
- | `category_col` | str | `"category"` | Column for phenotype categories. |
753
- | `effect_col` | str | None | Column with effect sizes for direction markers. |
754
- | `significance_threshold` | float | `5e-8` | P-value for significance line. |
755
- | `figsize` | tuple | `(10, 8)` | Figure dimensions (width, height). |
756
-
757
- ### plot_forest() Method
758
-
759
- Create a forest plot for meta-analysis visualization.
760
-
761
- ```python
762
- fig = plotter.plot_forest(
763
- forest_df, # Required: meta-analysis data
764
- variant_id="rs12345", # Required: variant ID for title
765
- study_col="study", # Study/phenotype name column
766
- effect_col="effect", # Effect size column
767
- ci_lower_col="ci_lower", # Lower CI column
768
- ci_upper_col="ci_upper", # Upper CI column
769
- weight_col=None, # Optional weight column for marker sizes
770
- null_value=0.0, # Null effect value (0 for beta, 1 for OR)
771
- effect_label="Effect Size", # X-axis label
772
- figsize=(8, 6), # Figure dimensions
773
- )
774
- ```
775
-
776
- | Parameter | Type | Default | Description |
777
- |-----------|------|---------|-------------|
778
- | `forest_df` | DataFrame | Required | Forest plot data with effects and CIs. |
779
- | `variant_id` | str | Required | Variant ID for plot title. |
780
- | `study_col` | str | `"study"` | Column with study/phenotype names. |
781
- | `effect_col` | str | `"effect"` | Column with effect sizes. |
782
- | `ci_lower_col` | str | `"ci_lower"` | Column with lower confidence interval. |
783
- | `ci_upper_col` | str | `"ci_upper"` | Column with upper confidence interval. |
784
- | `weight_col` | str | None | Column with study weights (affects marker size). |
785
- | `null_value` | float | `0.0` | Reference value for null effect line. |
786
- | `effect_label` | str | `"Effect Size"` | X-axis label. |
787
- | `figsize` | tuple | `(8, 6)` | Figure dimensions (width, height). |
788
-
789
622
  ### Parameter Naming Conventions
790
623
 
791
624
  Note the difference in parameter naming between single-region and multi-region methods:
@@ -13,7 +13,7 @@ matplotlib.use("Agg") # Non-interactive backend
13
13
  import numpy as np
14
14
  import pandas as pd
15
15
 
16
- from pylocuszoom import LocusZoomPlotter
16
+ from pylocuszoom import LocusZoomPlotter, ManhattanPlotter, StatsPlotter
17
17
 
18
18
 
19
19
  def generate_p_values(
@@ -814,7 +814,8 @@ phewas_df = pd.DataFrame(
814
814
  ],
815
815
  }
816
816
  )
817
- fig = plotter.plot_phewas(phewas_df, variant_id="rs7903146")
817
+ stats_plotter = StatsPlotter()
818
+ fig = stats_plotter.plot_phewas(phewas_df, variant_id="rs7903146")
818
819
  fig.savefig("examples/phewas_plot.png", dpi=150, bbox_inches="tight")
819
820
  print(" Saved: examples/phewas_plot.png")
820
821
 
@@ -838,7 +839,7 @@ forest_df = pd.DataFrame(
838
839
  "weight": [22, 18, 8, 28, 12, 12, 100],
839
840
  }
840
841
  )
841
- fig = plotter.plot_forest(
842
+ fig = stats_plotter.plot_forest(
842
843
  forest_df,
843
844
  variant_id="rs7903146 (TCF7L2)",
844
845
  weight_col="weight",
@@ -868,7 +869,7 @@ for chrom in range(1, 23):
868
869
 
869
870
  manhattan_df = pd.DataFrame(manhattan_data)
870
871
 
871
- manhattan_plotter = LocusZoomPlotter(species="human", log_level=None)
872
+ manhattan_plotter = ManhattanPlotter(species="human")
872
873
  fig = manhattan_plotter.plot_manhattan(
873
874
  manhattan_df,
874
875
  significance_threshold=5e-8,
@@ -890,7 +891,7 @@ qq_pvalues[:n_true] = 10 ** np.random.uniform(-10, -5, n_true)
890
891
 
891
892
  qq_df = pd.DataFrame({"p": qq_pvalues})
892
893
 
893
- qq_plotter = LocusZoomPlotter(log_level=None)
894
+ qq_plotter = ManhattanPlotter()
894
895
  fig = qq_plotter.plot_qq(
895
896
  qq_df,
896
897
  show_confidence_band=True,
@@ -902,9 +903,7 @@ print(" Saved: examples/qq_plot.png")
902
903
 
903
904
  # Interactive Plotly Manhattan plot
904
905
  print("20. Interactive Plotly Manhattan plot...")
905
- manhattan_plotter_plotly = LocusZoomPlotter(
906
- species="human", backend="plotly", log_level=None
907
- )
906
+ manhattan_plotter_plotly = ManhattanPlotter(species="human", backend="plotly")
908
907
  fig = manhattan_plotter_plotly.plot_manhattan(
909
908
  manhattan_df,
910
909
  significance_threshold=5e-8,
@@ -919,9 +918,7 @@ print("21. Interactive Bokeh Manhattan plot...")
919
918
  from bokeh.io import save
920
919
  from bokeh.resources import CDN
921
920
 
922
- manhattan_plotter_bokeh = LocusZoomPlotter(
923
- species="human", backend="bokeh", log_level=None
924
- )
921
+ manhattan_plotter_bokeh = ManhattanPlotter(species="human", backend="bokeh")
925
922
  fig = manhattan_plotter_bokeh.plot_manhattan(
926
923
  manhattan_df,
927
924
  significance_threshold=5e-8,
@@ -935,7 +932,7 @@ print(" Saved: examples/manhattan_bokeh.html")
935
932
 
936
933
  # Interactive Plotly QQ plot
937
934
  print("22. Interactive Plotly QQ plot...")
938
- qq_plotter_plotly = LocusZoomPlotter(backend="plotly", log_level=None)
935
+ qq_plotter_plotly = ManhattanPlotter(backend="plotly")
939
936
  fig = qq_plotter_plotly.plot_qq(
940
937
  qq_df,
941
938
  show_confidence_band=True,
@@ -947,7 +944,7 @@ print(" Saved: examples/qq_plotly.html")
947
944
 
948
945
  # Interactive Bokeh QQ plot
949
946
  print("23. Interactive Bokeh QQ plot...")
950
- qq_plotter_bokeh = LocusZoomPlotter(backend="bokeh", log_level=None)
947
+ qq_plotter_bokeh = ManhattanPlotter(backend="bokeh")
951
948
  fig = qq_plotter_bokeh.plot_qq(
952
949
  qq_df,
953
950
  show_confidence_band=True,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pylocuszoom"
7
- version = "1.1.2"
7
+ version = "1.2.0"
8
8
  description = "Publication-ready regional association plots with LD coloring, gene tracks, and recombination overlays"
9
9
  readme = "README.md"
10
10
  license = "GPL-3.0-or-later"
@@ -46,6 +46,7 @@ dev = [
46
46
  "pytest-cov>=4.0.0",
47
47
  "pytest-randomly>=3.0.0",
48
48
  "pytest-xdist>=3.0.0",
49
+ "hypothesis>=6.0.0",
49
50
  "ruff>=0.1.0",
50
51
  ]
51
52
  spark = [