pycmplot 0.3.1__tar.gz → 0.4.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 (52) hide show
  1. {pycmplot-0.3.1 → pycmplot-0.4.0}/PKG-INFO +62 -2
  2. {pycmplot-0.3.1 → pycmplot-0.4.0}/README.md +61 -1
  3. pycmplot-0.4.0/docs-bak/conf.py +90 -0
  4. pycmplot-0.4.0/pycmplot/__init__.py +50 -0
  5. pycmplot-0.4.0/pycmplot/__main__.py +6 -0
  6. pycmplot-0.4.0/pycmplot/_core.py +419 -0
  7. pycmplot-0.4.0/pycmplot/annotation.py +904 -0
  8. pycmplot-0.4.0/pycmplot/cache.py +832 -0
  9. pycmplot-0.4.0/pycmplot/cli.py +614 -0
  10. pycmplot-0.4.0/pycmplot/constants.py +91 -0
  11. pycmplot-0.4.0/pycmplot/io.py +1714 -0
  12. pycmplot-0.4.0/pycmplot/liftover.py +303 -0
  13. pycmplot-0.4.0/pycmplot/plotting/__init__.py +31 -0
  14. pycmplot-0.4.0/pycmplot/plotting/circular.py +832 -0
  15. pycmplot-0.4.0/pycmplot/plotting/linear.py +1728 -0
  16. pycmplot-0.4.0/pycmplot/plotting/qq.py +938 -0
  17. pycmplot-0.4.0/pycmplot/resources.py +199 -0
  18. pycmplot-0.4.0/pycmplot/stats.py +180 -0
  19. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/__init__.py +1 -1
  20. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/_core.py +30 -4
  21. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/annotation.py +298 -0
  22. pycmplot-0.4.0/pycmplot-bak/cache.py +832 -0
  23. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/cli.py +75 -1
  24. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/io.py +449 -82
  25. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/plotting/circular.py +104 -19
  26. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/plotting/linear.py +59 -7
  27. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/plotting/qq.py +248 -26
  28. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot.egg-info/PKG-INFO +62 -2
  29. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot.egg-info/SOURCES.txt +17 -0
  30. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot.egg-info/top_level.txt +2 -0
  31. {pycmplot-0.3.1 → pycmplot-0.4.0}/pyproject.toml +1 -1
  32. {pycmplot-0.3.1 → pycmplot-0.4.0}/setup.cfg +1 -1
  33. {pycmplot-0.3.1 → pycmplot-0.4.0}/LICENSE +0 -0
  34. {pycmplot-0.3.1 → pycmplot-0.4.0}/benchmark/bench_python.py +0 -0
  35. {pycmplot-0.3.1 → pycmplot-0.4.0}/benchmark/build_composite_figure.py +0 -0
  36. {pycmplot-0.3.1 → pycmplot-0.4.0}/benchmark/collect_results.py +0 -0
  37. {pycmplot-0.3.1 → pycmplot-0.4.0}/benchmark/generate_multi_sumstats.py +0 -0
  38. {pycmplot-0.3.1 → pycmplot-0.4.0}/benchmark/generate_sumstats.py +0 -0
  39. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot/data/Homo_sapiens.GRCh37.geneinfo.tsv.gz +0 -0
  40. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot/data/Homo_sapiens.GRCh38.geneinfo.tsv.gz +0 -0
  41. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot/data/hg18ToHg38.over.chain.gz +0 -0
  42. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot/data/hg19ToHg38.over.chain.gz +0 -0
  43. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/__main__.py +0 -0
  44. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/constants.py +0 -0
  45. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/liftover.py +0 -0
  46. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/plotting/__init__.py +0 -0
  47. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/resources.py +0 -0
  48. {pycmplot-0.3.1/pycmplot → pycmplot-0.4.0/pycmplot-bak}/stats.py +0 -0
  49. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot.egg-info/dependency_links.txt +0 -0
  50. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot.egg-info/entry_points.txt +0 -0
  51. {pycmplot-0.3.1 → pycmplot-0.4.0}/pycmplot.egg-info/requires.txt +0 -0
  52. {pycmplot-0.3.1 → pycmplot-0.4.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycmplot
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: Multi-track circular and linear Manhattan plot generation for GWAS summary statistics
5
5
  Author: Kevin Esoh
6
6
  Author-email: Kevin Esoh <kesohku1@jh.edu>
@@ -44,7 +44,7 @@ Dynamic: license-file
44
44
  </div>
45
45
 
46
46
  <p align="center">
47
- <img width="600" height="400" src="docs/pycmplot-logo-circular.png">
47
+ <img width="600" height="400" src="https://github.com/esohkevin/pycmplot/blob/main/docs/pycmplot-logo-circular.png">
48
48
  </p>
49
49
 
50
50
 
@@ -67,6 +67,10 @@ Dynamic: license-file
67
67
  - [Trim insignificant variants for faster plotting](#trim-insignificant-variants-for-faster-plotting)
68
68
  - [Genome build conversion (liftover)](#genome-build-conversion-liftover)
69
69
  - [Nearest-gene annotation for GWAS lead SNPs](#nearest-gene-annotation-for-gwas-lead-snps)
70
+ - [Caching & warm resume](#caching--warm-resume)
71
+ - [User-editable hits overlay](#user-editable-hits-overlay)
72
+ - [Per-locus highlight colours & custom legend](#per-locus-highlight-colours--custom-legend)
73
+ - [Multi-panel canvas](#multi-panel-canvas)
70
74
  3. [Application](#application)
71
75
  4. [Tip](#tip)
72
76
  5. [Installation](#installation)
@@ -179,6 +183,46 @@ for gene annotation. Also included are UCSC chain files for coordinate conversio
179
183
  ``Homo_sapiens.GRCh37.geneinfo.tsv.gz``.
180
184
 
181
185
 
186
+ ### Caching & warm resume
187
+ Loading is the expensive step (I/O + trim + liftover + lead extraction), so
188
+ pycmplot ships a per-track cache keyed on `SHA-256(raw_file_sha256 + version + Stage-1 params)`.
189
+ Warm re-runs of the same `(files, parameters)` combination complete in
190
+ milliseconds; changing any parameter transparently invalidates only the
191
+ affected tracks and regenerates them. Enable with `--cache` (CLI) or
192
+ `cache=True` (Python API); use `--clear_cache` to wipe the tree.
193
+
194
+ ```bash
195
+ pycmplot --sum_stats hb.tsv,mcv.tsv --labels Hb,MCV \
196
+ --logp --highlight --cache --cache_dir ./.pycmplot
197
+ ```
198
+
199
+ ### User-editable hits overlay
200
+ When caching is on, the auto-generated hits table is written to a
201
+ group-scoped TSV at `<cache_dir>/annotations/hits.<group_key>.tsv`
202
+ that you're *expected to hand-edit*. Rows added or changed there feed
203
+ straight back into the next plot — no re-plumbing required. Each row
204
+ carries `source` (`auto` vs `user`), `highlight_color`, and `category`
205
+ columns; user edits are inherited across cache regenerations by
206
+ `(CHR, POS)` lookup, so re-running with a new parameter never loses
207
+ your annotations.
208
+
209
+ ### Per-locus highlight colours & custom legend
210
+ Set the `highlight_color` column on any row of the hits overlay to a
211
+ matplotlib-parseable colour (name, `#rrggbb`, or an RGB tuple) to give
212
+ that locus its own highlight colour; leave `auto` to fall back to the
213
+ plot-wide `--highlight_color`. Set the `category` column
214
+ (e.g. `novel`, `replicated`, `MHC`) to group loci in a
215
+ **"Highlighted Categories"** legend that both the linear and circular
216
+ plotters render automatically. If nothing is edited, no legend is
217
+ added — the pre-feature layout is preserved.
218
+
219
+ ### Multi-panel canvas
220
+ Place multiple *groups* of sumstats on the same figure by passing an
221
+ explicit matplotlib `Axes` or `SubFigure` via `ax=` to the plotter.
222
+ Cache files and hits overlays are group-scoped, so two panels with
223
+ different sumstats never clobber each other's artefacts.
224
+
225
+
182
226
  ## Application
183
227
  A potential useful application is **comparative visualization** of results from multiple imputation panels,
184
228
  multiple populations, or multiple traits to observe shared genetic architecture.
@@ -305,6 +349,16 @@ pycmplot \
305
349
  | `-st, --sort_track` | Sort tracks by `label` or `chrom_len` | input order |
306
350
  | `-od, --output_dir` | Output directory | `.` |
307
351
  | `-of, --output_format` | Output format (`png`, `pdf`, `svg`, `jpg`) | `png` |
352
+ | `--cache` | Enable per-track cache + user-editable hits overlay | off |
353
+ | `--cache_dir` | Where to store cache artefacts | `./.pycmplot` |
354
+ | `--no_resume` | Regenerate but still write fresh cache entries | resume on |
355
+ | `--clear_cache` | Delete the cache tree and exit | off |
356
+ | `-V, --version` | Print version and exit | — |
357
+
358
+ > **QQ note (0.4.0+):** the loader no longer materialises the full sorted
359
+ > p-value array by default. `-qq/--qq_plot` sets `compute_pvals=True`
360
+ > automatically on the CLI; Python-API callers must pass it explicitly
361
+ > to feed `bundle['pvals']` into a QQ plotter.
308
362
 
309
363
  Run `pycmplot -h` for the full option list.
310
364
 
@@ -314,6 +368,12 @@ Run `pycmplot -h` for the full option list.
314
368
 
315
369
  A demonstration of how to use the python API is provided in this notebook: https://github.com/esohkevin/pycmplot/blob/main/pycmplot_python_api.ipynb
316
370
 
371
+ For an end-to-end walkthrough of every feature (caching, hits overlay,
372
+ per-locus colours & categories, multi-panel canvas, mixed-build
373
+ liftover, QQ opt-in), see the
374
+ [Tutorial](https://pycmplot.readthedocs.io/en/latest/tutorial.html)
375
+ page in the docs.
376
+
317
377
 
318
378
  ---
319
379
 
@@ -5,7 +5,7 @@
5
5
  </div>
6
6
 
7
7
  <p align="center">
8
- <img width="600" height="400" src="docs/pycmplot-logo-circular.png">
8
+ <img width="600" height="400" src="https://github.com/esohkevin/pycmplot/blob/main/docs/pycmplot-logo-circular.png">
9
9
  </p>
10
10
 
11
11
 
@@ -28,6 +28,10 @@
28
28
  - [Trim insignificant variants for faster plotting](#trim-insignificant-variants-for-faster-plotting)
29
29
  - [Genome build conversion (liftover)](#genome-build-conversion-liftover)
30
30
  - [Nearest-gene annotation for GWAS lead SNPs](#nearest-gene-annotation-for-gwas-lead-snps)
31
+ - [Caching & warm resume](#caching--warm-resume)
32
+ - [User-editable hits overlay](#user-editable-hits-overlay)
33
+ - [Per-locus highlight colours & custom legend](#per-locus-highlight-colours--custom-legend)
34
+ - [Multi-panel canvas](#multi-panel-canvas)
31
35
  3. [Application](#application)
32
36
  4. [Tip](#tip)
33
37
  5. [Installation](#installation)
@@ -140,6 +144,46 @@ for gene annotation. Also included are UCSC chain files for coordinate conversio
140
144
  ``Homo_sapiens.GRCh37.geneinfo.tsv.gz``.
141
145
 
142
146
 
147
+ ### Caching & warm resume
148
+ Loading is the expensive step (I/O + trim + liftover + lead extraction), so
149
+ pycmplot ships a per-track cache keyed on `SHA-256(raw_file_sha256 + version + Stage-1 params)`.
150
+ Warm re-runs of the same `(files, parameters)` combination complete in
151
+ milliseconds; changing any parameter transparently invalidates only the
152
+ affected tracks and regenerates them. Enable with `--cache` (CLI) or
153
+ `cache=True` (Python API); use `--clear_cache` to wipe the tree.
154
+
155
+ ```bash
156
+ pycmplot --sum_stats hb.tsv,mcv.tsv --labels Hb,MCV \
157
+ --logp --highlight --cache --cache_dir ./.pycmplot
158
+ ```
159
+
160
+ ### User-editable hits overlay
161
+ When caching is on, the auto-generated hits table is written to a
162
+ group-scoped TSV at `<cache_dir>/annotations/hits.<group_key>.tsv`
163
+ that you're *expected to hand-edit*. Rows added or changed there feed
164
+ straight back into the next plot — no re-plumbing required. Each row
165
+ carries `source` (`auto` vs `user`), `highlight_color`, and `category`
166
+ columns; user edits are inherited across cache regenerations by
167
+ `(CHR, POS)` lookup, so re-running with a new parameter never loses
168
+ your annotations.
169
+
170
+ ### Per-locus highlight colours & custom legend
171
+ Set the `highlight_color` column on any row of the hits overlay to a
172
+ matplotlib-parseable colour (name, `#rrggbb`, or an RGB tuple) to give
173
+ that locus its own highlight colour; leave `auto` to fall back to the
174
+ plot-wide `--highlight_color`. Set the `category` column
175
+ (e.g. `novel`, `replicated`, `MHC`) to group loci in a
176
+ **"Highlighted Categories"** legend that both the linear and circular
177
+ plotters render automatically. If nothing is edited, no legend is
178
+ added — the pre-feature layout is preserved.
179
+
180
+ ### Multi-panel canvas
181
+ Place multiple *groups* of sumstats on the same figure by passing an
182
+ explicit matplotlib `Axes` or `SubFigure` via `ax=` to the plotter.
183
+ Cache files and hits overlays are group-scoped, so two panels with
184
+ different sumstats never clobber each other's artefacts.
185
+
186
+
143
187
  ## Application
144
188
  A potential useful application is **comparative visualization** of results from multiple imputation panels,
145
189
  multiple populations, or multiple traits to observe shared genetic architecture.
@@ -266,6 +310,16 @@ pycmplot \
266
310
  | `-st, --sort_track` | Sort tracks by `label` or `chrom_len` | input order |
267
311
  | `-od, --output_dir` | Output directory | `.` |
268
312
  | `-of, --output_format` | Output format (`png`, `pdf`, `svg`, `jpg`) | `png` |
313
+ | `--cache` | Enable per-track cache + user-editable hits overlay | off |
314
+ | `--cache_dir` | Where to store cache artefacts | `./.pycmplot` |
315
+ | `--no_resume` | Regenerate but still write fresh cache entries | resume on |
316
+ | `--clear_cache` | Delete the cache tree and exit | off |
317
+ | `-V, --version` | Print version and exit | — |
318
+
319
+ > **QQ note (0.4.0+):** the loader no longer materialises the full sorted
320
+ > p-value array by default. `-qq/--qq_plot` sets `compute_pvals=True`
321
+ > automatically on the CLI; Python-API callers must pass it explicitly
322
+ > to feed `bundle['pvals']` into a QQ plotter.
269
323
 
270
324
  Run `pycmplot -h` for the full option list.
271
325
 
@@ -275,6 +329,12 @@ Run `pycmplot -h` for the full option list.
275
329
 
276
330
  A demonstration of how to use the python API is provided in this notebook: https://github.com/esohkevin/pycmplot/blob/main/pycmplot_python_api.ipynb
277
331
 
332
+ For an end-to-end walkthrough of every feature (caching, hits overlay,
333
+ per-locus colours & categories, multi-panel canvas, mixed-build
334
+ liftover, QQ opt-in), see the
335
+ [Tutorial](https://pycmplot.readthedocs.io/en/latest/tutorial.html)
336
+ page in the docs.
337
+
278
338
 
279
339
  ---
280
340
 
@@ -0,0 +1,90 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
3
+
4
+ import os
5
+ import sys
6
+
7
+ # -- Path setup ---------------------------------------------------------------
8
+ # Allow Sphinx to find the pycmplot package (needed for autodoc)
9
+ sys.path.insert(0, os.path.abspath(".."))
10
+
11
+ # -- Project information -------------------------------------------------------
12
+ project = "pycmplot"
13
+ copyright = "2026, Kevin Esoh"
14
+ author = "Kevin Esoh"
15
+ release = "0.3.1" # update to match PyPI version
16
+
17
+ # -- General configuration -----------------------------------------------------
18
+ extensions = [
19
+ "sphinx.ext.autodoc", # auto-generate docs from docstrings
20
+ "sphinx.ext.autosummary", # summary tables for modules/classes
21
+ "sphinx.ext.napoleon", # NumPy / Google docstring styles
22
+ "sphinx.ext.viewcode", # [source] links in API docs
23
+ "sphinx.ext.intersphinx", # cross-links to numpy, pandas, matplotlib docs
24
+ "numpydoc", # richer NumPy-style rendering
25
+ "nbsphinx", # embed Jupyter notebooks
26
+ "sphinx_copybutton", # copy-button on code blocks
27
+ "myst_parser", # allow Markdown (.md) pages alongside .rst
28
+ ]
29
+
30
+ # Napoleon settings (NumPy docstring style)
31
+ napoleon_google_docstring = False
32
+ napoleon_numpy_docstring = True
33
+ napoleon_include_init_with_doc = True
34
+ napoleon_include_private_with_doc = False
35
+ napoleon_use_param = True
36
+ napoleon_use_rtype = True
37
+
38
+ # numpydoc settings
39
+ numpydoc_show_class_members = False
40
+
41
+ # Autosummary: auto-generate stub files
42
+ autosummary_generate = True
43
+ autodoc_default_options = {
44
+ "members": True,
45
+ "undoc-members": False,
46
+ "show-inheritance": True,
47
+ }
48
+
49
+ # Intersphinx: link to external package docs
50
+ intersphinx_mapping = {
51
+ "python": ("https://docs.python.org/3", None),
52
+ "numpy": ("https://numpy.org/doc/stable", None),
53
+ "pandas": ("https://pandas.pydata.org/docs", None),
54
+ "matplotlib": ("https://matplotlib.org/stable", None),
55
+ }
56
+
57
+ # nbsphinx: do not re-execute notebooks during docs build
58
+ nbsphinx_execute = "never"
59
+
60
+ # Source file suffixes
61
+ source_suffix = {
62
+ ".rst": "restructuredtext",
63
+ ".md": "markdown",
64
+ }
65
+
66
+ templates_path = ["_templates"]
67
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "**.ipynb_checkpoints"]
68
+
69
+ # -- Options for HTML output ---------------------------------------------------
70
+ html_theme = "sphinx_rtd_theme"
71
+ html_theme_options = {
72
+ "logo_only": False,
73
+ "prev_next_buttons_location": "bottom",
74
+ "style_nav_header_background": "#2980B9",
75
+ "collapse_navigation": False,
76
+ "sticky_navigation": True,
77
+ "navigation_depth": 4,
78
+ "includehidden": True,
79
+ "titles_only": False,
80
+ }
81
+
82
+ html_static_path = ["_static"]
83
+ html_css_files = ["custom.css"]
84
+
85
+ # Optional: path to logo image (add docs/_static/logo.png if you have one)
86
+ # html_logo = "_static/logo.png"
87
+
88
+ html_show_sourcelink = True
89
+ html_show_sphinx = True
90
+ html_show_copyright = True
@@ -0,0 +1,50 @@
1
+ """
2
+ pycmplot
3
+ ========
4
+ Multi-track circular and linear Manhattan plot generation for GWAS summary statistics.
5
+
6
+ Quickstart
7
+ ----------
8
+ Command-line::
9
+
10
+ pycmplot -s file1.gz,file2.gz -l HbF,MCV --logp --mode lm
11
+
12
+ Python API::
13
+
14
+ from pycmplot.io import prep_pycmplot_input_info, get_sumstats_and_merged_sector_list
15
+ from pycmplot.plotting import plot_linear, plot_circular, plot_qq_single, plot_qq_separate, plot_qq_overlay, plot_qq_combined
16
+ from pycmplot.stats import get_lead_snps
17
+ from pycmplot.annotation import get_hits_summary_table
18
+
19
+ Public surface
20
+ --------------
21
+ """
22
+
23
+ from pycmplot.plotting.linear import plot_linear
24
+ from pycmplot.plotting.circular import plot_circular, compute_track_radii_dict
25
+ from pycmplot.plotting.qq import plot_qq_single, plot_qq_separate, plot_qq_overlay, plot_qq_combined
26
+ from pycmplot.stats import get_lead_snps, get_highlight_snps
27
+ from pycmplot.io import prep_pycmplot_input_info, get_sumstats_and_merged_sector_list
28
+ from pycmplot.annotation import get_hits_summary_table
29
+ from pycmplot.constants import hg38_chr_lengths, BIOTYPE_WEIGHTS
30
+ from pycmplot.resources import ResourceConfig
31
+
32
+ __all__ = [
33
+ "plot_linear",
34
+ "plot_circular",
35
+ "plot_qq_single",
36
+ "plot_qq_separate",
37
+ "plot_qq_overlay",
38
+ "plot_qq_combined",
39
+ "compute_track_radii_dict",
40
+ "get_lead_snps",
41
+ "get_highlight_snps",
42
+ "prep_pycmplot_input_info",
43
+ "get_sumstats_and_merged_sector_list",
44
+ "get_hits_summary_table",
45
+ "hg38_chr_lengths",
46
+ "BIOTYPE_WEIGHTS",
47
+ "ResourceConfig",
48
+ ]
49
+
50
+ __version__ = "0.4.0"
@@ -0,0 +1,6 @@
1
+ """Entry point for ``python -m pycmplot`` invocation."""
2
+
3
+ from pycmplot._core import main
4
+
5
+ if __name__ == "__main__":
6
+ main()