gfviewer 2.0.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.
- gfviewer-2.0.0/LICENSE +21 -0
- gfviewer-2.0.0/MANIFEST.in +28 -0
- gfviewer-2.0.0/PKG-INFO +197 -0
- gfviewer-2.0.0/README.md +148 -0
- gfviewer-2.0.0/docs/BIOCONDA.md +197 -0
- gfviewer-2.0.0/docs/INSTALL.md +438 -0
- gfviewer-2.0.0/environment.yml +19 -0
- gfviewer-2.0.0/flaskapp.py +20 -0
- gfviewer-2.0.0/gfviewer/__init__.py +18 -0
- gfviewer-2.0.0/gfviewer/analytics.py +1348 -0
- gfviewer-2.0.0/gfviewer/charts.py +254 -0
- gfviewer-2.0.0/gfviewer/cli.py +284 -0
- gfviewer-2.0.0/gfviewer/errors.py +33 -0
- gfviewer-2.0.0/gfviewer/genome.py +251 -0
- gfviewer-2.0.0/gfviewer/io.py +709 -0
- gfviewer-2.0.0/gfviewer/legacy.py +459 -0
- gfviewer-2.0.0/gfviewer/palette.py +236 -0
- gfviewer-2.0.0/gfviewer/pipeline.py +115 -0
- gfviewer-2.0.0/gfviewer/render.py +709 -0
- gfviewer-2.0.0/gfviewer/style.py +210 -0
- gfviewer-2.0.0/gfviewer.egg-info/PKG-INFO +197 -0
- gfviewer-2.0.0/gfviewer.egg-info/SOURCES.txt +61 -0
- gfviewer-2.0.0/gfviewer.egg-info/dependency_links.txt +1 -0
- gfviewer-2.0.0/gfviewer.egg-info/entry_points.txt +2 -0
- gfviewer-2.0.0/gfviewer.egg-info/requires.txt +21 -0
- gfviewer-2.0.0/gfviewer.egg-info/top_level.txt +2 -0
- gfviewer-2.0.0/gfviewer.py +14 -0
- gfviewer-2.0.0/gfviewer_web/__init__.py +73 -0
- gfviewer-2.0.0/gfviewer_web/api.py +171 -0
- gfviewer-2.0.0/gfviewer_web/config.py +46 -0
- gfviewer-2.0.0/gfviewer_web/datasets.py +201 -0
- gfviewer-2.0.0/gfviewer_web/errors.py +49 -0
- gfviewer-2.0.0/gfviewer_web/jobs.py +585 -0
- gfviewer-2.0.0/gfviewer_web/routes.py +127 -0
- gfviewer-2.0.0/gfviewer_web/usage.py +181 -0
- gfviewer-2.0.0/pyproject.toml +75 -0
- gfviewer-2.0.0/requirements.txt +18 -0
- gfviewer-2.0.0/setup.cfg +4 -0
- gfviewer-2.0.0/static/images/NIH-logo.png +0 -0
- gfviewer-2.0.0/static/images/UCR_Icon_WhtBG.png +0 -0
- gfviewer-2.0.0/static/images/color_guide_sample.png +0 -0
- gfviewer-2.0.0/static/images/logo.png +0 -0
- gfviewer-2.0.0/static/js/editor.js +673 -0
- gfviewer-2.0.0/static/js/submit.js +36 -0
- gfviewer-2.0.0/static/styles.css +341 -0
- gfviewer-2.0.0/templates/about_us.html +119 -0
- gfviewer-2.0.0/templates/base.html +48 -0
- gfviewer-2.0.0/templates/error.html +15 -0
- gfviewer-2.0.0/templates/help.html +277 -0
- gfviewer-2.0.0/templates/index.html +202 -0
- gfviewer-2.0.0/templates/install.html +231 -0
- gfviewer-2.0.0/templates/result.html +243 -0
- gfviewer-2.0.0/templates/stats.html +64 -0
- gfviewer-2.0.0/tests/conftest.py +88 -0
- gfviewer-2.0.0/tests/make_fixtures.py +238 -0
- gfviewer-2.0.0/tests/test_analytics.py +311 -0
- gfviewer-2.0.0/tests/test_genome.py +80 -0
- gfviewer-2.0.0/tests/test_io.py +198 -0
- gfviewer-2.0.0/tests/test_packaging.py +68 -0
- gfviewer-2.0.0/tests/test_palette.py +82 -0
- gfviewer-2.0.0/tests/test_render_pipeline.py +241 -0
- gfviewer-2.0.0/tests/test_style_cli.py +107 -0
- gfviewer-2.0.0/tests/test_webapp.py +314 -0
gfviewer-2.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sakshar Chakravarty and Stefano Lonardi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Files to ship in the source distribution (sdist) built by `python -m build`.
|
|
2
|
+
# The wheel contents are controlled by [tool.setuptools] in pyproject.toml.
|
|
3
|
+
|
|
4
|
+
include README.md
|
|
5
|
+
include LICENSE
|
|
6
|
+
include requirements.txt
|
|
7
|
+
include environment.yml
|
|
8
|
+
include pyproject.toml
|
|
9
|
+
|
|
10
|
+
recursive-include docs *.md
|
|
11
|
+
recursive-include gfviewer *.py
|
|
12
|
+
recursive-include gfviewer_web *.py
|
|
13
|
+
|
|
14
|
+
# Web portal assets (only used when running the portal from a source checkout).
|
|
15
|
+
recursive-include templates *.html
|
|
16
|
+
recursive-include static *.css *.js *.png *.svg
|
|
17
|
+
|
|
18
|
+
# Tests and the fixture builder.
|
|
19
|
+
include flaskapp.py gfviewer.py
|
|
20
|
+
recursive-include tests *.py
|
|
21
|
+
include tests/*.csv tests/*.txt
|
|
22
|
+
|
|
23
|
+
# Never ship generated output or large bundled datasets.
|
|
24
|
+
prune static/output
|
|
25
|
+
prune static/tests
|
|
26
|
+
prune uploads
|
|
27
|
+
prune instance
|
|
28
|
+
global-exclude __pycache__ *.py[cod] .DS_Store
|
gfviewer-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: gfviewer
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Visualize and quantify the localization of multigene families across chromosomes
|
|
5
|
+
Author: Sakshar Chakravarty, Stefano Lonardi
|
|
6
|
+
Maintainer-email: Stefano Lonardi <stelo@ucr.edu>
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/sakshar/GFViewer
|
|
9
|
+
Project-URL: Repository, https://github.com/sakshar/GFViewer
|
|
10
|
+
Project-URL: Documentation, https://github.com/sakshar/GFViewer/blob/main/docs/INSTALL.md
|
|
11
|
+
Project-URL: Issues, https://github.com/sakshar/GFViewer/issues
|
|
12
|
+
Keywords: bioinformatics,genomics,multigene family,gene family,chromosome,ideogram,karyotype,visualization,comparative genomics,localization,Ripley K
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Environment :: Web Environment
|
|
16
|
+
Classifier: Framework :: Flask
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
28
|
+
Requires-Python: >=3.8
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: biopython>=1.80
|
|
32
|
+
Requires-Dist: matplotlib>=3.6
|
|
33
|
+
Requires-Dist: pandas>=1.5
|
|
34
|
+
Requires-Dist: numpy>=1.22
|
|
35
|
+
Requires-Dist: openpyxl>=3.0
|
|
36
|
+
Requires-Dist: Pillow>=9.0
|
|
37
|
+
Requires-Dist: reportlab>=3.6
|
|
38
|
+
Requires-Dist: PyPDF2>=3.0
|
|
39
|
+
Requires-Dist: PyYAML>=6.0
|
|
40
|
+
Provides-Extra: web
|
|
41
|
+
Requires-Dist: Flask>=2.2; extra == "web"
|
|
42
|
+
Requires-Dist: Werkzeug>=2.2; extra == "web"
|
|
43
|
+
Requires-Dist: gunicorn>=21.0; extra == "web"
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
46
|
+
Provides-Extra: build
|
|
47
|
+
Requires-Dist: build>=1.0; extra == "build"
|
|
48
|
+
Requires-Dist: twine>=4.0; extra == "build"
|
|
49
|
+
|
|
50
|
+
# GFViewer
|
|
51
|
+
|
|
52
|
+
Visualize the localization of **multigene families** across the chromosomes of a
|
|
53
|
+
genome, and quantify how those families are distributed.
|
|
54
|
+
|
|
55
|
+
GFViewer draws round-capped chromosome ideograms with each family in its own
|
|
56
|
+
colour (``+`` strand above the axis, ``-`` below), optionally marks centromeres,
|
|
57
|
+
and can compute localization statistics. Output is fully vector and can be saved
|
|
58
|
+
as **PDF, SVG, PNG, JPG, TIFF or EPS**.
|
|
59
|
+
|
|
60
|
+
Version 2 rewrites the rendering engine on top of matplotlib (the old
|
|
61
|
+
BioPython/`BasicChromosome` engine is kept at `gfviewer.legacy` for one
|
|
62
|
+
release), removes the 19-family ceiling, adds BED / GFF3 / GTF input, a style
|
|
63
|
+
system, an analytics module, and an interactive web portal.
|
|
64
|
+
|
|
65
|
+
## Install
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install gfviewer # the `gfviewer` command-line tool
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
From a source checkout (development, tests, or the web portal):
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
conda env create -f environment.yml # or: python -m venv .venv && source .venv/bin/activate
|
|
75
|
+
conda activate gfviewer
|
|
76
|
+
pip install -e ".[web,dev]" # editable, with Flask + pytest
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
A full pip-installation and command-line walkthrough — isolated environments,
|
|
80
|
+
every flag with worked examples, troubleshooting — is in
|
|
81
|
+
[`docs/INSTALL.md`](docs/INSTALL.md), and is mirrored on the web portal's
|
|
82
|
+
**Install** page. Build distributable artifacts with `scripts/build_wheel.sh`.
|
|
83
|
+
|
|
84
|
+
## Command line
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
gfviewer -d genes.tsv -g genome.fasta -o out/ \
|
|
88
|
+
-f pdf svg png --analytics -cen \
|
|
89
|
+
--tick-style lollipop --title "My organism"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Key options (`gfviewer --help` for the full list):
|
|
93
|
+
|
|
94
|
+
| Flag | Meaning |
|
|
95
|
+
|------|---------|
|
|
96
|
+
| `-d/--data` | one or more annotation files (`.xlsx/.csv/.tsv/.bed/.gff3/.gtf`) |
|
|
97
|
+
| `-g/--genome` | FASTA, `.fai`, `chrom.sizes`, or `chrom,length` table |
|
|
98
|
+
| `-c/--colors` | colour-map file (`family,index` / `family,#hex` / `family,r,g,b`) |
|
|
99
|
+
| `-m/--mapping` | `gene_id,gene_family` map (single BED/GFF input) |
|
|
100
|
+
| `--family-attr` | GFF3/GTF attribute that holds the family |
|
|
101
|
+
| `-f/--format` | export formats |
|
|
102
|
+
| `--collapse-rare` | fold infrequent families into "Other" above the 40-family cap |
|
|
103
|
+
| `--style` / `--save-style` | load / write a YAML/JSON style file |
|
|
104
|
+
| `--analytics` | also write per-family statistics as CSV/JSON |
|
|
105
|
+
| `--no-titles` | omit titles from the exported figure and analytics-chart images |
|
|
106
|
+
| `-cen` | draw centromeres |
|
|
107
|
+
|
|
108
|
+
### Input formats
|
|
109
|
+
|
|
110
|
+
* **Table** — columns `gene_id, gene_family, chromosome, start, end, strand`
|
|
111
|
+
(1-based, inclusive; header synonyms accepted). A `centromere` value in
|
|
112
|
+
`gene_family` (strand `0`) marks a centromere.
|
|
113
|
+
* **BED** — 0-based half-open, converted automatically. One file → column 4 is
|
|
114
|
+
the family; several files → each file's base name is the family; one file plus
|
|
115
|
+
a mapping file → family from the map.
|
|
116
|
+
* **GFF3 / GTF** — 1-based; gene-like feature types kept; family taken from
|
|
117
|
+
`--family-attr` (default search: `gene_family`, `Family`, `gene_biotype`,
|
|
118
|
+
`Name`, …).
|
|
119
|
+
|
|
120
|
+
### Analytics
|
|
121
|
+
|
|
122
|
+
`--analytics` writes `analytics_*.csv` / `.bed`, `analytics_summary.json` and
|
|
123
|
+
four figures (`analytics_genes_per_family`, `analytics_positional_profile`,
|
|
124
|
+
`analytics_ripley`, `analytics_family_proximity` — one per requested figure
|
|
125
|
+
format). It computes:
|
|
126
|
+
|
|
127
|
+
* per-family counts split into genes on chromosomes vs. unplaced/stray contigs,
|
|
128
|
+
linear density, gene length, strand fraction;
|
|
129
|
+
* permutation tests for **telomere-** and (with a centromere track)
|
|
130
|
+
**centromere-proximal** bias, plus **p-arm / q-arm** occupancy;
|
|
131
|
+
* **tandem-array** detection and a **tandem / proximal / dispersed** duplication
|
|
132
|
+
mode per family;
|
|
133
|
+
* **multi-scale clustering** — edge-corrected 1-D **Ripley's K/L** with a
|
|
134
|
+
permutation envelope (`--ripley-scales`);
|
|
135
|
+
* **chromosome-enrichment** (binomial, per family × chromosome), **strand bias**,
|
|
136
|
+
and per-chromosome **family diversity** (Shannon / evenness);
|
|
137
|
+
* a binned **positional density profile** ("metachromosome" plot);
|
|
138
|
+
* a **family × family proximity matrix** with average-linkage clustering;
|
|
139
|
+
* **multigene-family hotspots** — a Poisson window scan, merged and written as a
|
|
140
|
+
table and a **BED** file (`--hotspot-window`);
|
|
141
|
+
* optional pairwise **co-localization** (`--colocalization`).
|
|
142
|
+
|
|
143
|
+
Every per-family / per-pair / per-window test carries a Benjamini–Hochberg
|
|
144
|
+
`q_value`. See `templates/help.html` (the *Downloadable outputs* section) for the
|
|
145
|
+
column-by-column layout of each file.
|
|
146
|
+
|
|
147
|
+
## Web portal
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# development
|
|
151
|
+
python flaskapp.py # http://localhost:5001
|
|
152
|
+
|
|
153
|
+
# production
|
|
154
|
+
gunicorn -w 1 --threads 4 -b 0.0.0.0:5001 "gfviewer_web:create_app()"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Uploads are rendered on a background thread pool behind an async job API
|
|
158
|
+
(`POST /api/jobs` → `GET /api/jobs/<id>/status` → results page). The results page
|
|
159
|
+
embeds the SVG with an editor for choosing which families and chromosomes to
|
|
160
|
+
draw, recolouring, moving the legend and labels, changing fonts and mark style,
|
|
161
|
+
toggling whether titles are baked into the image files, then re-rendering and
|
|
162
|
+
exporting. Analytics figures are shown inline, and two buttons download
|
|
163
|
+
**everything as a ZIP** — either as produced, or re-rendered in every figure
|
|
164
|
+
format. `GET /api/health` is a readiness probe.
|
|
165
|
+
|
|
166
|
+
**Usage monitor.** A privacy-respecting counter (`/stats`, or JSON at
|
|
167
|
+
`/api/stats`) tracks page views, unique visitors per day (a salted daily hash —
|
|
168
|
+
no IPs, cookies or other personal data are stored), jobs submitted / completed /
|
|
169
|
+
failed, example-dataset runs and downloads, with a rolling ~120-day daily
|
|
170
|
+
series. Counters persist to `instance/usage.json`.
|
|
171
|
+
|
|
172
|
+
Configuration (environment variables): `GFVIEWER_DATA_DIR`,
|
|
173
|
+
`GFVIEWER_MAX_UPLOAD_MB` (25), `GFVIEWER_WORKERS` (2), `GFVIEWER_JOB_TTL_HOURS`
|
|
174
|
+
(24), `GFVIEWER_USAGE_FILE`, `GFVIEWER_STATS_TOKEN` (require `?token=` on
|
|
175
|
+
`/stats`), `SECRET_KEY`, `PORT`.
|
|
176
|
+
|
|
177
|
+
## Example datasets
|
|
178
|
+
|
|
179
|
+
`python tests/make_fixtures.py` builds every bundled dataset into
|
|
180
|
+
`static/tests/`: the three *Babesia* sets, the 6-family set re-expressed in
|
|
181
|
+
every input format (`formats/` — BED, per-family BED, BED + mapping, GFF3, GTF),
|
|
182
|
+
and two synthetic sets — 10 random gene families on the *Arabidopsis* (TAIR10)
|
|
183
|
+
chromosomes and 20 on *C. elegans* (WBcel235). The web home page lists them all
|
|
184
|
+
with **Run** (submits the job) and **Download** buttons, plus *Download every
|
|
185
|
+
dataset (ZIP)*.
|
|
186
|
+
|
|
187
|
+
## Tests
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
python tests/make_fixtures.py # once, to build the example datasets
|
|
191
|
+
pytest -q
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Citation
|
|
195
|
+
|
|
196
|
+
Chakravarty S. & Lonardi S. *Visualizing the localization of multigene families
|
|
197
|
+
with GFViewer.* Development supported by NIH grant 1-R01-AI169543-01.
|
gfviewer-2.0.0/README.md
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# GFViewer
|
|
2
|
+
|
|
3
|
+
Visualize the localization of **multigene families** across the chromosomes of a
|
|
4
|
+
genome, and quantify how those families are distributed.
|
|
5
|
+
|
|
6
|
+
GFViewer draws round-capped chromosome ideograms with each family in its own
|
|
7
|
+
colour (``+`` strand above the axis, ``-`` below), optionally marks centromeres,
|
|
8
|
+
and can compute localization statistics. Output is fully vector and can be saved
|
|
9
|
+
as **PDF, SVG, PNG, JPG, TIFF or EPS**.
|
|
10
|
+
|
|
11
|
+
Version 2 rewrites the rendering engine on top of matplotlib (the old
|
|
12
|
+
BioPython/`BasicChromosome` engine is kept at `gfviewer.legacy` for one
|
|
13
|
+
release), removes the 19-family ceiling, adds BED / GFF3 / GTF input, a style
|
|
14
|
+
system, an analytics module, and an interactive web portal.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install gfviewer # the `gfviewer` command-line tool
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
From a source checkout (development, tests, or the web portal):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
conda env create -f environment.yml # or: python -m venv .venv && source .venv/bin/activate
|
|
26
|
+
conda activate gfviewer
|
|
27
|
+
pip install -e ".[web,dev]" # editable, with Flask + pytest
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
A full pip-installation and command-line walkthrough — isolated environments,
|
|
31
|
+
every flag with worked examples, troubleshooting — is in
|
|
32
|
+
[`docs/INSTALL.md`](docs/INSTALL.md), and is mirrored on the web portal's
|
|
33
|
+
**Install** page. Build distributable artifacts with `scripts/build_wheel.sh`.
|
|
34
|
+
|
|
35
|
+
## Command line
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
gfviewer -d genes.tsv -g genome.fasta -o out/ \
|
|
39
|
+
-f pdf svg png --analytics -cen \
|
|
40
|
+
--tick-style lollipop --title "My organism"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Key options (`gfviewer --help` for the full list):
|
|
44
|
+
|
|
45
|
+
| Flag | Meaning |
|
|
46
|
+
|------|---------|
|
|
47
|
+
| `-d/--data` | one or more annotation files (`.xlsx/.csv/.tsv/.bed/.gff3/.gtf`) |
|
|
48
|
+
| `-g/--genome` | FASTA, `.fai`, `chrom.sizes`, or `chrom,length` table |
|
|
49
|
+
| `-c/--colors` | colour-map file (`family,index` / `family,#hex` / `family,r,g,b`) |
|
|
50
|
+
| `-m/--mapping` | `gene_id,gene_family` map (single BED/GFF input) |
|
|
51
|
+
| `--family-attr` | GFF3/GTF attribute that holds the family |
|
|
52
|
+
| `-f/--format` | export formats |
|
|
53
|
+
| `--collapse-rare` | fold infrequent families into "Other" above the 40-family cap |
|
|
54
|
+
| `--style` / `--save-style` | load / write a YAML/JSON style file |
|
|
55
|
+
| `--analytics` | also write per-family statistics as CSV/JSON |
|
|
56
|
+
| `--no-titles` | omit titles from the exported figure and analytics-chart images |
|
|
57
|
+
| `-cen` | draw centromeres |
|
|
58
|
+
|
|
59
|
+
### Input formats
|
|
60
|
+
|
|
61
|
+
* **Table** — columns `gene_id, gene_family, chromosome, start, end, strand`
|
|
62
|
+
(1-based, inclusive; header synonyms accepted). A `centromere` value in
|
|
63
|
+
`gene_family` (strand `0`) marks a centromere.
|
|
64
|
+
* **BED** — 0-based half-open, converted automatically. One file → column 4 is
|
|
65
|
+
the family; several files → each file's base name is the family; one file plus
|
|
66
|
+
a mapping file → family from the map.
|
|
67
|
+
* **GFF3 / GTF** — 1-based; gene-like feature types kept; family taken from
|
|
68
|
+
`--family-attr` (default search: `gene_family`, `Family`, `gene_biotype`,
|
|
69
|
+
`Name`, …).
|
|
70
|
+
|
|
71
|
+
### Analytics
|
|
72
|
+
|
|
73
|
+
`--analytics` writes `analytics_*.csv` / `.bed`, `analytics_summary.json` and
|
|
74
|
+
four figures (`analytics_genes_per_family`, `analytics_positional_profile`,
|
|
75
|
+
`analytics_ripley`, `analytics_family_proximity` — one per requested figure
|
|
76
|
+
format). It computes:
|
|
77
|
+
|
|
78
|
+
* per-family counts split into genes on chromosomes vs. unplaced/stray contigs,
|
|
79
|
+
linear density, gene length, strand fraction;
|
|
80
|
+
* permutation tests for **telomere-** and (with a centromere track)
|
|
81
|
+
**centromere-proximal** bias, plus **p-arm / q-arm** occupancy;
|
|
82
|
+
* **tandem-array** detection and a **tandem / proximal / dispersed** duplication
|
|
83
|
+
mode per family;
|
|
84
|
+
* **multi-scale clustering** — edge-corrected 1-D **Ripley's K/L** with a
|
|
85
|
+
permutation envelope (`--ripley-scales`);
|
|
86
|
+
* **chromosome-enrichment** (binomial, per family × chromosome), **strand bias**,
|
|
87
|
+
and per-chromosome **family diversity** (Shannon / evenness);
|
|
88
|
+
* a binned **positional density profile** ("metachromosome" plot);
|
|
89
|
+
* a **family × family proximity matrix** with average-linkage clustering;
|
|
90
|
+
* **multigene-family hotspots** — a Poisson window scan, merged and written as a
|
|
91
|
+
table and a **BED** file (`--hotspot-window`);
|
|
92
|
+
* optional pairwise **co-localization** (`--colocalization`).
|
|
93
|
+
|
|
94
|
+
Every per-family / per-pair / per-window test carries a Benjamini–Hochberg
|
|
95
|
+
`q_value`. See `templates/help.html` (the *Downloadable outputs* section) for the
|
|
96
|
+
column-by-column layout of each file.
|
|
97
|
+
|
|
98
|
+
## Web portal
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# development
|
|
102
|
+
python flaskapp.py # http://localhost:5001
|
|
103
|
+
|
|
104
|
+
# production
|
|
105
|
+
gunicorn -w 1 --threads 4 -b 0.0.0.0:5001 "gfviewer_web:create_app()"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Uploads are rendered on a background thread pool behind an async job API
|
|
109
|
+
(`POST /api/jobs` → `GET /api/jobs/<id>/status` → results page). The results page
|
|
110
|
+
embeds the SVG with an editor for choosing which families and chromosomes to
|
|
111
|
+
draw, recolouring, moving the legend and labels, changing fonts and mark style,
|
|
112
|
+
toggling whether titles are baked into the image files, then re-rendering and
|
|
113
|
+
exporting. Analytics figures are shown inline, and two buttons download
|
|
114
|
+
**everything as a ZIP** — either as produced, or re-rendered in every figure
|
|
115
|
+
format. `GET /api/health` is a readiness probe.
|
|
116
|
+
|
|
117
|
+
**Usage monitor.** A privacy-respecting counter (`/stats`, or JSON at
|
|
118
|
+
`/api/stats`) tracks page views, unique visitors per day (a salted daily hash —
|
|
119
|
+
no IPs, cookies or other personal data are stored), jobs submitted / completed /
|
|
120
|
+
failed, example-dataset runs and downloads, with a rolling ~120-day daily
|
|
121
|
+
series. Counters persist to `instance/usage.json`.
|
|
122
|
+
|
|
123
|
+
Configuration (environment variables): `GFVIEWER_DATA_DIR`,
|
|
124
|
+
`GFVIEWER_MAX_UPLOAD_MB` (25), `GFVIEWER_WORKERS` (2), `GFVIEWER_JOB_TTL_HOURS`
|
|
125
|
+
(24), `GFVIEWER_USAGE_FILE`, `GFVIEWER_STATS_TOKEN` (require `?token=` on
|
|
126
|
+
`/stats`), `SECRET_KEY`, `PORT`.
|
|
127
|
+
|
|
128
|
+
## Example datasets
|
|
129
|
+
|
|
130
|
+
`python tests/make_fixtures.py` builds every bundled dataset into
|
|
131
|
+
`static/tests/`: the three *Babesia* sets, the 6-family set re-expressed in
|
|
132
|
+
every input format (`formats/` — BED, per-family BED, BED + mapping, GFF3, GTF),
|
|
133
|
+
and two synthetic sets — 10 random gene families on the *Arabidopsis* (TAIR10)
|
|
134
|
+
chromosomes and 20 on *C. elegans* (WBcel235). The web home page lists them all
|
|
135
|
+
with **Run** (submits the job) and **Download** buttons, plus *Download every
|
|
136
|
+
dataset (ZIP)*.
|
|
137
|
+
|
|
138
|
+
## Tests
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
python tests/make_fixtures.py # once, to build the example datasets
|
|
142
|
+
pytest -q
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Citation
|
|
146
|
+
|
|
147
|
+
Chakravarty S. & Lonardi S. *Visualizing the localization of multigene families
|
|
148
|
+
with GFViewer.* Development supported by NIH grant 1-R01-AI169543-01.
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Releasing GFViewer on Bioconda
|
|
2
|
+
|
|
3
|
+
GFViewer is packaged on **Bioconda** (channel `bioconda`), recipe at
|
|
4
|
+
`bioconda/bioconda-recipes` → `recipes/gfviewer/meta.yaml`. Recipe maintainer:
|
|
5
|
+
`sakshar`. The package is `noarch: python` and ships the **CLI only**
|
|
6
|
+
(`gfviewer` command); the Flask web portal (`pip install "gfviewer[web]"`) is
|
|
7
|
+
not part of the conda package.
|
|
8
|
+
|
|
9
|
+
Install (Bioconda requires conda-forge in the channel list):
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
conda install -c conda-forge -c bioconda gfviewer
|
|
13
|
+
# or
|
|
14
|
+
mamba install -c conda-forge -c bioconda gfviewer
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## How a release reaches Bioconda
|
|
20
|
+
|
|
21
|
+
1. You push a new tag `vX.Y.Z` to `github.com/sakshar/GFViewer` and cut a GitHub
|
|
22
|
+
Release.
|
|
23
|
+
2. **BiocondaBot** notices the new tag within a few hours and opens an
|
|
24
|
+
auto-bump PR against `bioconda-recipes` titled *"Update gfviewer to X.Y.Z"*.
|
|
25
|
+
It changes only `version`, `source.url`, `source.sha256` and resets
|
|
26
|
+
`build.number` to `0`.
|
|
27
|
+
3. Bioconda CI builds the recipe on Linux / OSX / ARM. When green **and a
|
|
28
|
+
maintainer approves**, it is merged and the build bot uploads the package to
|
|
29
|
+
`anaconda.org/bioconda/gfviewer` (usually 30–60 min after merge).
|
|
30
|
+
|
|
31
|
+
The auto-bump PR does **not** update dependencies or metadata — do that in a
|
|
32
|
+
separate follow-up PR (see below) whenever `pyproject.toml` deps change.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Step 1 — Merge the auto-bump PR
|
|
37
|
+
|
|
38
|
+
On the BiocondaBot PR page (e.g. `bioconda/bioconda-recipes#68787` for 2.0.0):
|
|
39
|
+
|
|
40
|
+
1. Check that all CI checks are green (Linux Tests, OSX-64 Tests,
|
|
41
|
+
build and test (ARM), Lint).
|
|
42
|
+
2. Verify the `sha256` matches the tag tarball:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
curl -sL https://github.com/sakshar/GFViewer/archive/refs/tags/vX.Y.Z.tar.gz | shasum -a 256
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
> GitHub's auto-generated tag tarballs are **not guaranteed byte-stable**,
|
|
49
|
+
> and force-moving a tag changes the hash. If the hashes differ, comment
|
|
50
|
+
> `@BiocondaBot please update` on the PR (or fix `sha256` by hand). Long
|
|
51
|
+
> term, once GFViewer is on PyPI, switch `source.url` to the immutable PyPI
|
|
52
|
+
> sdist: `https://pypi.io/packages/source/g/gfviewer/gfviewer-{{ version }}.tar.gz`.
|
|
53
|
+
|
|
54
|
+
3. As the recipe maintainer, comment to merge:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
@BiocondaBot please merge
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Step 2 — Follow-up PR to update `meta.yaml` (deps / metadata)
|
|
63
|
+
|
|
64
|
+
Do this **after** the auto-bump PR is merged, so you branch off an up-to-date
|
|
65
|
+
`master`. `bioconda-recipes` is huge — edit the single file in the browser
|
|
66
|
+
rather than cloning.
|
|
67
|
+
|
|
68
|
+
### Web UI (recommended)
|
|
69
|
+
|
|
70
|
+
1. Open
|
|
71
|
+
`https://github.com/bioconda/bioconda-recipes/blob/master/recipes/gfviewer/meta.yaml`
|
|
72
|
+
and confirm `version:` is the new one.
|
|
73
|
+
2. Click the **pencil** ("Edit this file"). GitHub prompts to **fork the
|
|
74
|
+
repository** (one-time) — accept.
|
|
75
|
+
3. Apply your changes (see the reference `meta.yaml` below).
|
|
76
|
+
4. **Bump `build.number`** by 1 (a recipe change without a version change needs
|
|
77
|
+
a new build number; the auto-bump already set it to `0` for the version
|
|
78
|
+
change, so a same-version follow-up becomes `1`).
|
|
79
|
+
5. Commit message e.g. `gfviewer: add numpy, pillow, pyyaml to run deps (build 1)`
|
|
80
|
+
→ **"Create a new branch and start a pull request"** → branch
|
|
81
|
+
`gfviewer-deps` → **Propose changes**.
|
|
82
|
+
6. Base must be `bioconda:master`. Complete the PR template checklist
|
|
83
|
+
(one recipe changed; build number bumped).
|
|
84
|
+
7. When CI is green and approved: `@BiocondaBot please merge`.
|
|
85
|
+
|
|
86
|
+
### Local git (alternative)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Fork bioconda/bioconda-recipes on GitHub first, then:
|
|
90
|
+
git clone --depth 1 https://github.com/<your-username>/bioconda-recipes.git
|
|
91
|
+
cd bioconda-recipes
|
|
92
|
+
git remote add upstream https://github.com/bioconda/bioconda-recipes.git
|
|
93
|
+
git checkout -b gfviewer-deps
|
|
94
|
+
|
|
95
|
+
$EDITOR recipes/gfviewer/meta.yaml # apply the changes
|
|
96
|
+
|
|
97
|
+
git add recipes/gfviewer/meta.yaml
|
|
98
|
+
git commit -m "gfviewer: add numpy, pillow, pyyaml to run deps (build 1)"
|
|
99
|
+
git push -u origin gfviewer-deps
|
|
100
|
+
# open the PR: <you>:gfviewer-deps -> bioconda:master
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
No local build needed — Bioconda CI builds it. (A local `conda build` of a
|
|
104
|
+
Bioconda recipe needs `bioconda-utils` and is heavy.)
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Reference `meta.yaml` for GFViewer v2.x
|
|
109
|
+
|
|
110
|
+
Keep `requirements.run` in sync with `[project.dependencies]` in
|
|
111
|
+
`pyproject.toml`. As of v2.0.0 that is: biopython, matplotlib, pandas, numpy,
|
|
112
|
+
openpyxl, Pillow, reportlab, PyPDF2, PyYAML. On conda: `matplotlib` →
|
|
113
|
+
`matplotlib-base` (headless), `PyPDF2` → `pypdf2`, `Pillow` → `pillow`,
|
|
114
|
+
`PyYAML` → `pyyaml`.
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
package:
|
|
118
|
+
name: gfviewer
|
|
119
|
+
version: "2.0.0"
|
|
120
|
+
|
|
121
|
+
source:
|
|
122
|
+
url: https://github.com/sakshar/GFViewer/archive/refs/tags/v2.0.0.tar.gz
|
|
123
|
+
sha256: 30aec61635d669ac86f9596b254646bf1cff3544bc033fe87d0d376510e94c5f
|
|
124
|
+
|
|
125
|
+
build:
|
|
126
|
+
noarch: python
|
|
127
|
+
number: 1 # bump on any recipe change without a version change
|
|
128
|
+
script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv"
|
|
129
|
+
run_exports:
|
|
130
|
+
- {{ pin_subpackage("gfviewer", max_pin="x") }}
|
|
131
|
+
|
|
132
|
+
requirements:
|
|
133
|
+
host:
|
|
134
|
+
- python >=3.8,<3.13
|
|
135
|
+
- pip
|
|
136
|
+
- setuptools >=64
|
|
137
|
+
- wheel
|
|
138
|
+
run:
|
|
139
|
+
- python >=3.8,<3.13
|
|
140
|
+
- biopython
|
|
141
|
+
- pandas
|
|
142
|
+
- numpy # imported directly by gfviewer.analytics
|
|
143
|
+
- matplotlib-base
|
|
144
|
+
- pillow # matplotlib-base excludes it; needed for -f jpg / tiff
|
|
145
|
+
- reportlab
|
|
146
|
+
- pypdf2
|
|
147
|
+
- openpyxl
|
|
148
|
+
- pyyaml # --style / --save-style *.yaml
|
|
149
|
+
|
|
150
|
+
test:
|
|
151
|
+
imports:
|
|
152
|
+
- gfviewer # do NOT test `import gfviewer_web` (needs Flask, not a dep)
|
|
153
|
+
commands:
|
|
154
|
+
- gfviewer --help
|
|
155
|
+
- gfviewer --version
|
|
156
|
+
|
|
157
|
+
about:
|
|
158
|
+
home: https://github.com/sakshar/GFViewer
|
|
159
|
+
license: MIT
|
|
160
|
+
license_file: LICENSE
|
|
161
|
+
summary: "Visualize and quantify the localization of multigene families across chromosomes."
|
|
162
|
+
description: |
|
|
163
|
+
GFViewer draws round-capped chromosome ideograms with each gene family in
|
|
164
|
+
its own colour and computes localization statistics (sub-telomeric bias,
|
|
165
|
+
tandem arrays, 1-D Ripley's K/L, chromosome enrichment, multigene-family
|
|
166
|
+
hotspots, family-proximity clustering, ...). Reads annotation tables, BED,
|
|
167
|
+
GFF3 and GTF. Provides the `gfviewer` command-line tool.
|
|
168
|
+
dev_url: https://github.com/sakshar/GFViewer
|
|
169
|
+
|
|
170
|
+
extra:
|
|
171
|
+
recipe-maintainers:
|
|
172
|
+
- sakshar
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Checklist for the next version bump (vX.Y.Z)
|
|
178
|
+
|
|
179
|
+
- [ ] `gfviewer/__init__.py::__version__` and `pyproject.toml::version` bumped
|
|
180
|
+
together (`tests/test_packaging.py` fails if they drift).
|
|
181
|
+
- [ ] Tag `vX.Y.Z` pushed; GitHub Release published.
|
|
182
|
+
- [ ] Wait for the BiocondaBot *"Update gfviewer to X.Y.Z"* PR.
|
|
183
|
+
- [ ] Confirm `sha256` matches `curl -sL <tag tarball> | shasum -a 256`.
|
|
184
|
+
- [ ] If `pyproject.toml` deps changed, prepare the `meta.yaml` `run:` update.
|
|
185
|
+
- [ ] `@BiocondaBot please merge` once green + approved.
|
|
186
|
+
- [ ] Follow-up PR for deps/metadata if needed (`build.number` +1).
|
|
187
|
+
- [ ] After the channel updates: `conda install -c conda-forge -c bioconda gfviewer`
|
|
188
|
+
and check `gfviewer --version`.
|
|
189
|
+
|
|
190
|
+
## Useful BiocondaBot / PR commands
|
|
191
|
+
|
|
192
|
+
| Comment | Effect |
|
|
193
|
+
|---|---|
|
|
194
|
+
| `@BiocondaBot please merge` | maintainer merges a green, approved PR |
|
|
195
|
+
| `@BiocondaBot please update` | regenerate the bump PR (re-fetch source, recompute hash) |
|
|
196
|
+
| `@BiocondaBot please add label` | add the `please review & merge` label |
|
|
197
|
+
| `@bioconda-bot please fetch artifacts` | link to the built packages from CI for local testing |
|