pylocuszoom 0.2.0__tar.gz → 0.5.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 (68) hide show
  1. pylocuszoom-0.5.0/.gitattributes +3 -0
  2. pylocuszoom-0.5.0/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  3. pylocuszoom-0.5.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. pylocuszoom-0.5.0/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  5. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/.github/workflows/ci.yml +1 -1
  6. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/.gitignore +3 -0
  7. pylocuszoom-0.5.0/.pre-commit-config.yaml +7 -0
  8. pylocuszoom-0.5.0/CHANGELOG.md +126 -0
  9. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/PKG-INFO +125 -31
  10. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/README.md +121 -26
  11. pylocuszoom-0.5.0/bioconda/meta.yaml +54 -0
  12. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/docs/ARCHITECTURE.md +30 -8
  13. pylocuszoom-0.5.0/docs/USER_GUIDE.md +740 -0
  14. pylocuszoom-0.5.0/examples/eqtl_bokeh.html +61 -0
  15. pylocuszoom-0.5.0/examples/eqtl_overlay.png +0 -0
  16. pylocuszoom-0.5.0/examples/eqtl_plotly.html +3888 -0
  17. pylocuszoom-0.5.0/examples/finemapping_bokeh.html +61 -0
  18. pylocuszoom-0.5.0/examples/finemapping_plot.png +0 -0
  19. pylocuszoom-0.5.0/examples/finemapping_plotly.html +3888 -0
  20. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/examples/generate_readme_plots.py +78 -2
  21. pylocuszoom-0.5.0/examples/getting_started.ipynb +931 -0
  22. pylocuszoom-0.5.0/examples/regional_plot.png +0 -0
  23. pylocuszoom-0.5.0/examples/stacked_plot.png +0 -0
  24. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/pyproject.toml +9 -6
  25. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/__init__.py +52 -1
  26. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/backends/base.py +47 -0
  27. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/backends/bokeh_backend.py +323 -61
  28. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/backends/matplotlib_backend.py +133 -7
  29. pylocuszoom-0.5.0/src/pylocuszoom/backends/plotly_backend.py +863 -0
  30. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/colors.py +3 -1
  31. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/finemapping.py +0 -1
  32. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/gene_track.py +232 -23
  33. pylocuszoom-0.5.0/src/pylocuszoom/loaders.py +862 -0
  34. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/plotter.py +354 -245
  35. pylocuszoom-0.5.0/src/pylocuszoom/py.typed +0 -0
  36. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/recombination.py +4 -4
  37. pylocuszoom-0.5.0/src/pylocuszoom/schemas.py +395 -0
  38. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/test_finemapping.py +6 -3
  39. pylocuszoom-0.5.0/tests/test_loaders.py +466 -0
  40. pylocuszoom-0.5.0/tests/test_notebook_backends.py +798 -0
  41. pylocuszoom-0.5.0/tests/test_plotter.py +765 -0
  42. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/uv.lock +395 -8
  43. pylocuszoom-0.2.0/CHANGELOG.md +0 -59
  44. pylocuszoom-0.2.0/examples/eqtl_overlay.png +0 -0
  45. pylocuszoom-0.2.0/examples/finemapping_plot.png +0 -0
  46. pylocuszoom-0.2.0/examples/getting_started.ipynb +0 -240
  47. pylocuszoom-0.2.0/examples/regional_plot.png +0 -0
  48. pylocuszoom-0.2.0/examples/stacked_plot.png +0 -0
  49. pylocuszoom-0.2.0/src/pylocuszoom/backends/plotly_backend.py +0 -473
  50. pylocuszoom-0.2.0/tests/test_plotter.py +0 -385
  51. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/.github/workflows/publish.yml +0 -0
  52. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/CONTRIBUTING.md +0 -0
  53. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/LICENSE.md +0 -0
  54. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/logo.svg +0 -0
  55. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/backends/__init__.py +0 -0
  56. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/eqtl.py +0 -0
  57. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/labels.py +0 -0
  58. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/ld.py +0 -0
  59. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/logging.py +0 -0
  60. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/reference_data/__init__.py +0 -0
  61. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/src/pylocuszoom/utils.py +0 -0
  62. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/conftest.py +0 -0
  63. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/test_colors.py +0 -0
  64. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/test_gene_track.py +0 -0
  65. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/test_labels.py +0 -0
  66. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/test_ld.py +0 -0
  67. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/test_logging.py +0 -0
  68. {pylocuszoom-0.2.0 → pylocuszoom-0.5.0}/tests/test_recombination.py +0 -0
@@ -0,0 +1,3 @@
1
+
2
+ # Use bd merge for beads JSONL files
3
+ .beads/issues.jsonl merge=beads
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: Bug Report
3
+ about: Report a bug or unexpected behavior
4
+ title: ''
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Description
10
+
11
+ A clear description of the bug.
12
+
13
+ ## Minimal Reproducible Example
14
+
15
+ ```python
16
+ from pylocuszoom import LocusZoomPlotter
17
+ import pandas as pd
18
+
19
+ # Minimal code to reproduce the issue
20
+ ```
21
+
22
+ ## Expected Behavior
23
+
24
+ What you expected to happen.
25
+
26
+ ## Actual Behavior
27
+
28
+ What actually happened. Include error messages if applicable.
29
+
30
+ ## Environment
31
+
32
+ - pylocuszoom version:
33
+ - Python version:
34
+ - OS:
35
+ - Installation method: pip / conda / uv
36
+
37
+ ## Additional Context
38
+
39
+ Any other relevant information (screenshots, data samples, etc.)
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Documentation
4
+ url: https://github.com/michael-denyer/pyLocusZoom/blob/main/docs/USER_GUIDE.md
5
+ about: Check the user guide before opening an issue
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: Feature Request
3
+ about: Suggest a new feature or enhancement
4
+ title: ''
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Problem
10
+
11
+ What problem does this feature solve?
12
+
13
+ ## Proposed Solution
14
+
15
+ Describe the feature you'd like.
16
+
17
+ ## Alternatives Considered
18
+
19
+ Any alternative solutions or workarounds you've tried.
20
+
21
+ ## Additional Context
22
+
23
+ Any other relevant information (mockups, examples from other tools, etc.)
@@ -29,7 +29,7 @@ jobs:
29
29
  strategy:
30
30
  fail-fast: false
31
31
  matrix:
32
- python-version: ["3.9", "3.10", "3.11", "3.12"]
32
+ python-version: ["3.10", "3.11", "3.12"]
33
33
 
34
34
  steps:
35
35
  - uses: actions/checkout@v4
@@ -21,5 +21,8 @@ htmlcov/
21
21
  *.swp
22
22
  .claude/
23
23
 
24
+ # Issue tracking (local)
25
+ .beads/
26
+
24
27
  # Project instructions (private)
25
28
  CLAUDE.md
@@ -0,0 +1,7 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.9.1
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
@@ -0,0 +1,126 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.5.0] - 2026-01-27
11
+
12
+ ### Added
13
+ - Hover tooltips for fine-mapping scatter plots (Plotly/Bokeh backends)
14
+ - Hover tooltips for eQTL scatter plots (Plotly/Bokeh backends)
15
+ - Interactive HTML example plots for eQTL and fine-mapping (Plotly/Bokeh)
16
+ - Comprehensive marker and hover data tests for interactive backends
17
+
18
+ ### Changed
19
+ - Plotly/Bokeh backends now hide grid lines for cleaner LocusZoom appearance
20
+ - Plotly/Bokeh backends now show black axis lines (matching matplotlib style)
21
+ - Plotly/Bokeh gene track panels now hide y-axis (ticks, labels, line, grid)
22
+ - Plotly/Bokeh backends now hide minor ticks and zero lines
23
+
24
+ ## [0.4.0] - 2026-01-26
25
+
26
+ ### Added
27
+ - **File format loaders** for common GWAS, eQTL, and fine-mapping formats:
28
+ - GWAS: `load_gwas`, `load_plink_assoc`, `load_regenie`, `load_bolt_lmm`, `load_gemma`, `load_saige`, `load_gwas_catalog`
29
+ - eQTL: `load_gtex_eqtl`, `load_eqtl_catalogue`, `load_matrixeqtl`
30
+ - Fine-mapping: `load_susie`, `load_finemap`, `load_caviar`, `load_polyfun`
31
+ - Gene annotations: `load_gtf`, `load_bed`, `load_ensembl_genes`
32
+ - Pydantic validation for file loaders with detailed error messages
33
+ - `py.typed` marker for PEP 561 type checking support
34
+ - Pre-commit configuration for automated linting
35
+ - GitHub issue templates for bug reports and feature requests
36
+ - Codecov badge in README
37
+
38
+ ### Changed
39
+ - eQTL and fine-mapping legends now route through backend protocol (works with all backends)
40
+ - Simplified backend code with reduced duplication
41
+ - Backend protocol class diagram added to ARCHITECTURE.md
42
+
43
+ ### Fixed
44
+ - Additional robustness improvements for edge cases
45
+
46
+ ## [0.3.0] - 2026-01-26
47
+
48
+ ### Added
49
+ - Bioconda recipe for conda installation
50
+ - `adjustText` moved to default dependencies (was optional)
51
+ - **Interactive plotly backend** - use `backend="plotly"` for hover tooltips and pan/zoom
52
+ - **Interactive bokeh backend** - use `backend="bokeh"` for dashboard-ready plots
53
+
54
+ ### Changed
55
+ - `plot()` and `plot_stacked()` now use backend protocol for all rendering (scatter, line, axes, layout)
56
+ - **Gene track now works with all backends** (plotly, bokeh, matplotlib)
57
+ - **Recombination overlay now works with all backends** - secondary y-axis with rate line and fill
58
+ - **LD legend now works with all backends** - r² color scale (lead SNP highlighted in plot, not legend)
59
+ - SNP labels remain matplotlib-only (interactive backends use hover tooltips instead)
60
+ - Default `genomewide_threshold` changed from 5e-7 to 5e-8 (standard GWAS significance)
61
+ - Gene track strand colors: forward strand now goldenrod (#DAA520), reverse strand light blue (#6BB3FF)
62
+ - Gene track directional arrows: black for forward, dark grey for reverse
63
+ - Added panel spacing (hspace=0.1) between stacked/fine-mapping panels for visual separation
64
+ - Tightened gene track internal spacing for more compact layout
65
+
66
+ ### Fixed
67
+ - Bokeh backend `x_range=None` error when creating figures with shared x-axis
68
+ - Bokeh backend `legend_label=None` error in scatter plots
69
+ - Bokeh backend LD legend not rendering (empty scatter plots don't create legend glyphs)
70
+ - Bokeh backend deprecated `FuncTickFormatter` replaced with `CustomJSTickFormatter`
71
+ - Bokeh backend deprecated `circle()` method replaced with `scatter(marker=...)`
72
+ - Bokeh backend `FIXED_SIZING_MODE` validation warning in column layouts
73
+
74
+ ## [0.2.0] - 2026-01-26
75
+
76
+ ### Added
77
+ - Fine-mapping/SuSiE visualization with credible set coloring
78
+ - Example plots in `examples/` directory
79
+ - Plot generation script for documentation
80
+
81
+ ### Fixed
82
+ - Ruff linting and formatting errors
83
+ - Bokeh security vulnerability (bumped to >= 3.8.2)
84
+ - `plot()` KeyError when `rs_col` column missing with `ld_reference_file` provided
85
+ - `plot_stacked()` now validates eQTL DataFrame columns before use
86
+ - `plot_stacked()` now validates list lengths for `lead_positions`, `panel_labels`, and `ld_reference_files`
87
+ - `calculate_ld()` docstring now documents `ValidationError` for missing PLINK files
88
+
89
+ ### Changed
90
+ - Minimum Python version bumped to 3.10 (required by bokeh 3.8.2)
91
+ - Renamed species terminology: "dog" → "canine", "cat" → "feline"
92
+ - Clarified interactive backend status in README (coming soon)
93
+
94
+ ## [0.1.0] - 2026-01-26
95
+
96
+ ### Added
97
+ - Initial release of pyLocusZoom
98
+ - Regional association plots with LD coloring
99
+ - Gene and exon track visualization
100
+ - Recombination rate overlay (canine only)
101
+ - Automatic SNP labeling with adjustText
102
+ - Species support: Canine (CanFam3.1/CanFam4), Feline (FelCat9), custom
103
+ - CanFam4 coordinate liftover via pyliftover
104
+ - Stacked plots for multi-GWAS comparison
105
+ - eQTL overlay panel support
106
+ - PySpark DataFrame support
107
+ - Backend infrastructure for matplotlib, plotly, bokeh (matplotlib only active)
108
+ - Logging via loguru
109
+ - Comprehensive test suite
110
+
111
+ ### Dependencies
112
+ - matplotlib >= 3.5.0
113
+ - pandas >= 1.4.0
114
+ - numpy >= 1.21.0
115
+ - loguru >= 0.7.0
116
+ - pyliftover >= 0.4
117
+ - plotly >= 5.0.0
118
+ - bokeh >= 3.8.2
119
+ - kaleido >= 0.2.0
120
+
121
+ [Unreleased]: https://github.com/michael-denyer/pyLocusZoom/compare/v0.5.0...HEAD
122
+ [0.5.0]: https://github.com/michael-denyer/pyLocusZoom/compare/v0.4.0...v0.5.0
123
+ [0.4.0]: https://github.com/michael-denyer/pyLocusZoom/compare/v0.3.0...v0.4.0
124
+ [0.3.0]: https://github.com/michael-denyer/pyLocusZoom/compare/v0.2.0...v0.3.0
125
+ [0.2.0]: https://github.com/michael-denyer/pyLocusZoom/compare/v0.1.0...v0.2.0
126
+ [0.1.0]: https://github.com/michael-denyer/pyLocusZoom/releases/tag/v0.1.0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pylocuszoom
3
- Version: 0.2.0
4
- Summary: Regional association plots for GWAS results with LD coloring, gene tracks, and recombination rate overlays
3
+ Version: 0.5.0
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
7
7
  Project-URL: Repository, https://github.com/michael-denyer/pylocuszoom
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
20
20
  Classifier: Topic :: Scientific/Engineering :: Visualization
21
21
  Requires-Python: >=3.10
22
+ Requires-Dist: adjusttext>=0.8
22
23
  Requires-Dist: bokeh>=3.8.2
23
24
  Requires-Dist: kaleido>=0.2.0
24
25
  Requires-Dist: loguru>=0.7.0
@@ -26,63 +27,72 @@ Requires-Dist: matplotlib>=3.5.0
26
27
  Requires-Dist: numpy>=1.21.0
27
28
  Requires-Dist: pandas>=1.4.0
28
29
  Requires-Dist: plotly>=5.0.0
30
+ Requires-Dist: pydantic>=2.0.0
29
31
  Requires-Dist: pyliftover>=0.4
30
32
  Provides-Extra: all
31
- Requires-Dist: adjusttext>=0.8; extra == 'all'
32
33
  Requires-Dist: pyspark>=3.0.0; extra == 'all'
33
34
  Provides-Extra: dev
34
35
  Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
35
36
  Requires-Dist: pytest>=7.0.0; extra == 'dev'
36
37
  Requires-Dist: ruff>=0.1.0; extra == 'dev'
37
- Provides-Extra: labels
38
- Requires-Dist: adjusttext>=0.8; extra == 'labels'
39
38
  Provides-Extra: spark
40
39
  Requires-Dist: pyspark>=3.0.0; extra == 'spark'
41
40
  Description-Content-Type: text/markdown
42
41
 
43
- # pyLocusZoom
44
-
45
42
  [![CI](https://github.com/michael-denyer/pyLocusZoom/actions/workflows/ci.yml/badge.svg)](https://github.com/michael-denyer/pyLocusZoom/actions/workflows/ci.yml)
46
- [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
43
+ [![codecov](https://codecov.io/gh/michael-denyer/pyLocusZoom/graph/badge.svg)](https://codecov.io/gh/michael-denyer/pyLocusZoom)
44
+ [![PyPI](https://img.shields.io/pypi/v/pylocuszoom)](https://pypi.org/project/pylocuszoom/)
45
+ [![Bioconda](https://img.shields.io/conda/vn/bioconda/pylocuszoom)](https://anaconda.org/bioconda/pylocuszoom)
46
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-red.svg)](https://www.gnu.org/licenses/gpl-3.0)
47
47
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
48
48
  [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
49
-
50
49
  [![Matplotlib](https://img.shields.io/badge/Matplotlib-3.5+-11557c.svg)](https://matplotlib.org/)
51
50
  [![Plotly](https://img.shields.io/badge/Plotly-5.0+-3F4F75.svg)](https://plotly.com/python/)
52
51
  [![Bokeh](https://img.shields.io/badge/Bokeh-3.8+-E6526F.svg)](https://bokeh.org/)
53
52
  [![Pandas](https://img.shields.io/badge/Pandas-1.4+-150458.svg)](https://pandas.pydata.org/)
54
-
55
53
  <img src="logo.svg" alt="pyLocusZoom logo" width="120" align="right">
54
+ # pyLocusZoom
56
55
 
57
- Regional association plots for GWAS results with LD coloring, gene tracks, and recombination rate overlays.
56
+ Publication-ready regional association plots with LD coloring, gene tracks, and recombination overlays.
58
57
 
59
58
  Inspired by [LocusZoom](http://locuszoom.org/) and [locuszoomr](https://github.com/myles-lewis/locuszoomr).
60
59
 
61
60
  ## Features
62
61
 
63
- - **LD coloring**: SNPs colored by linkage disequilibrium (R²) with lead variant
64
- - **Gene track**: Annotated gene/exon positions below the association plot
65
- - **Recombination rate**: Overlay showing recombination rate across region (*Canis lupus familiaris* only)
66
- - **SNP labels**: Automatic labeling of top SNPs with RS ID or nearest gene
67
- - **Species support**: Built-in *Canis lupus familiaris* (CanFam3.1/CanFam4), *Felis catus* (FelCat9), or custom species
68
- - **CanFam4 support**: Automatic coordinate liftover for recombination maps
69
- - **Multiple backends**: matplotlib (static), plotly (interactive), bokeh (dashboards)
70
- - **Stacked plots**: Compare multiple GWAS/phenotypes vertically
71
- - **eQTL overlay**: Expression QTL data as separate panel
72
- - **PySpark support**: Handles large-scale genomics DataFrames
62
+ 1. **Regional association plot**:
63
+
64
+ - **Multi-species support**: Built-in reference data for *Canis lupus familiaris* (CanFam3.1/CanFam4) and *Felis catus* (FelCat9), or optionally provide your own for any species
65
+ - **LD coloring**: SNPs colored by linkage disequilibrium (R²) with lead variant
66
+ - **Gene tracks**: Annotated gene/exon positions below the association plot
67
+ - **Recombination rate**: Overlay showing recombination rate across region (*Canis lupus familiaris* only)
68
+ - **SNP labels (matplotlib)**: Automatic labeling of lead SNPs with RS ID
69
+ - **Tooltips (Bokeh and Plotly)**: Mouseover for detailed SNP data
73
70
 
74
71
  ![Example regional association plot](examples/regional_plot.png)
75
72
 
73
+ 2. **Stacked plots**: Compare multiple GWAS/phenotypes vertically
74
+ 3. **eQTL plot**: Expression QTL data aligned with association plots and gene tracks
75
+ 4. **Fine-mapping plots**: Visualize SuSiE credible sets with posterior inclusion probabilities
76
+ 5. **Multiple charting libraries**: matplotlib (static), plotly (interactive), bokeh (dashboards)
77
+ 6. **Pandas and PySpark support**: Works with both Pandas and PySpark DataFrames for large-scale genomics data
78
+ 7. **Convenience data file loaders**: Load and validate common GWAS, eQTL and fine-mapping file formats
79
+
76
80
  ## Installation
77
81
 
82
+ ```bash
83
+ pip install pylocuszoom
84
+ ```
85
+
86
+ Or with uv:
87
+
78
88
  ```bash
79
89
  uv add pylocuszoom
80
90
  ```
81
91
 
82
- Or with pip:
92
+ Or with conda (Bioconda):
83
93
 
84
94
  ```bash
85
- pip install pylocuszoom
95
+ conda install -c bioconda pylocuszoom
86
96
  ```
87
97
 
88
98
  ## Quick Start
@@ -165,20 +175,30 @@ fig = plotter.plot(
165
175
  )
166
176
  ```
167
177
 
168
- ## Interactive Backends (Coming Soon)
178
+ ## Backends
169
179
 
170
- > **Note:** Interactive backends (plotly, bokeh) are planned but not yet fully integrated. Currently all plots use matplotlib.
180
+ pyLocusZoom supports multiple rendering backends:
171
181
 
172
182
  ```python
173
- # Static publication-quality plot (default, currently only supported backend)
174
- plotter = LocusZoomPlotter(species="canine", backend="matplotlib")
175
- fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000)
183
+ # Static publication-quality plot (default)
184
+ fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000, backend="matplotlib")
176
185
  fig.savefig("plot.png", dpi=150)
186
+
187
+ # Interactive Plotly (hover tooltips, pan/zoom)
188
+ fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000, backend="plotly")
189
+ fig.write_html("plot.html")
190
+
191
+ # Interactive Bokeh (dashboard-ready)
192
+ fig = plotter.plot(gwas_df, chrom=1, start=1000000, end=2000000, backend="bokeh")
177
193
  ```
178
194
 
179
- Future releases will support:
180
- - **Plotly**: Interactive plots with hover tooltips, zoom/pan
181
- - **Bokeh**: Dashboard-friendly interactive plots
195
+ | Backend | Output | Best For | Features |
196
+ |---------|--------|----------|----------|
197
+ | `matplotlib` | Static PNG/PDF/SVG | Publications, presentations | Full feature set with SNP labels |
198
+ | `plotly` | Interactive HTML | Web reports, data exploration | Hover tooltips, pan/zoom |
199
+ | `bokeh` | Interactive HTML | Dashboards, web apps | Hover tooltips, pan/zoom |
200
+
201
+ > **Note:** All backends support scatter plots, gene tracks, recombination overlay, and LD legend. SNP labels (auto-positioned with adjustText) are matplotlib-only; interactive backends use hover tooltips instead.
182
202
 
183
203
  ## Stacked Plots
184
204
 
@@ -195,6 +215,8 @@ fig = plotter.plot_stacked(
195
215
  )
196
216
  ```
197
217
 
218
+ ![Example stacked plot](examples/stacked_plot.png)
219
+
198
220
  ## eQTL Overlay
199
221
 
200
222
  Add expression QTL data as a separate panel:
@@ -215,6 +237,30 @@ fig = plotter.plot_stacked(
215
237
  )
216
238
  ```
217
239
 
240
+ ![Example eQTL overlay plot](examples/eqtl_overlay.png)
241
+
242
+ ## Fine-mapping Visualization
243
+
244
+ Visualize SuSiE or other fine-mapping results with credible set coloring:
245
+
246
+ ```python
247
+ finemapping_df = pd.DataFrame({
248
+ "pos": [1000500, 1001200, 1002000, 1003500],
249
+ "pip": [0.85, 0.12, 0.02, 0.45], # Posterior inclusion probability
250
+ "cs": [1, 1, 0, 2], # Credible set assignment (0 = not in CS)
251
+ })
252
+
253
+ fig = plotter.plot_stacked(
254
+ [gwas_df],
255
+ chrom=1, start=1000000, end=2000000,
256
+ finemapping_df=finemapping_df,
257
+ finemapping_cs_col="cs",
258
+ genes_df=genes_df,
259
+ )
260
+ ```
261
+
262
+ ![Example fine-mapping plot](examples/finemapping_plot.png)
263
+
218
264
  ## PySpark Support
219
265
 
220
266
  For large-scale genomics data, pass PySpark DataFrames directly:
@@ -231,6 +277,47 @@ pandas_df = to_pandas(spark_gwas_df, sample_size=100000)
231
277
 
232
278
  Install PySpark support: `uv add pylocuszoom[spark]`
233
279
 
280
+ ## Loading Data from Files
281
+
282
+ pyLocusZoom includes loaders for common GWAS, eQTL, and fine-mapping file formats:
283
+
284
+ ```python
285
+ from pylocuszoom import (
286
+ # GWAS loaders
287
+ load_gwas, # Auto-detect format
288
+ load_plink_assoc, # PLINK .assoc, .assoc.linear, .qassoc
289
+ load_regenie, # REGENIE .regenie
290
+ load_bolt_lmm, # BOLT-LMM .stats
291
+ load_gemma, # GEMMA .assoc.txt
292
+ load_saige, # SAIGE output
293
+ # eQTL loaders
294
+ load_gtex_eqtl, # GTEx significant pairs
295
+ load_eqtl_catalogue, # eQTL Catalogue format
296
+ # Fine-mapping loaders
297
+ load_susie, # SuSiE output
298
+ load_finemap, # FINEMAP .snp output
299
+ # Gene annotations
300
+ load_gtf, # GTF/GFF3 files
301
+ load_bed, # BED files
302
+ )
303
+
304
+ # Auto-detect GWAS format from filename
305
+ gwas_df = load_gwas("results.assoc.linear")
306
+
307
+ # Or use specific loader
308
+ gwas_df = load_regenie("ukb_results.regenie")
309
+
310
+ # Load gene annotations
311
+ genes_df = load_gtf("genes.gtf", feature_type="gene")
312
+ exons_df = load_gtf("genes.gtf", feature_type="exon")
313
+
314
+ # Load eQTL data
315
+ eqtl_df = load_gtex_eqtl("GTEx.signif_pairs.txt.gz", gene="BRCA1")
316
+
317
+ # Load fine-mapping results
318
+ fm_df = load_susie("susie_output.tsv")
319
+ ```
320
+
234
321
  ## Data Formats
235
322
 
236
323
  ### GWAS Results DataFrame
@@ -357,6 +444,13 @@ plotter = LocusZoomPlotter(log_level="DEBUG")
357
444
  Optional:
358
445
  - pyspark >= 3.0.0 (for PySpark DataFrame support) - `uv add pylocuszoom[spark]`
359
446
 
447
+ ## Documentation
448
+
449
+ - [User Guide](docs/USER_GUIDE.md) - Comprehensive documentation with API reference
450
+ - [Architecture](docs/ARCHITECTURE.md) - Design decisions and component overview
451
+ - [Example Notebook](examples/getting_started.ipynb) - Interactive tutorial
452
+ - [CHANGELOG](CHANGELOG.md) - Version history
453
+
360
454
  ## License
361
455
 
362
456
  GPL-3.0-or-later