figwig 0.1.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.
- figwig-0.1.0/.gitignore +35 -0
- figwig-0.1.0/LICENSE +21 -0
- figwig-0.1.0/PKG-INFO +361 -0
- figwig-0.1.0/README.md +307 -0
- figwig-0.1.0/figwig/__init__.py +11 -0
- figwig-0.1.0/figwig/__main__.py +61 -0
- figwig-0.1.0/figwig/_kernels.py +765 -0
- figwig-0.1.0/figwig/bam2bw.py +2635 -0
- figwig-0.1.0/figwig/bigwig.py +802 -0
- figwig-0.1.0/figwig/install_skill.py +61 -0
- figwig-0.1.0/figwig/py.typed +0 -0
- figwig-0.1.0/figwig/skills/figwig/SKILL.md +84 -0
- figwig-0.1.0/figwig/skills/figwig/references/bam2bw.md +89 -0
- figwig-0.1.0/figwig/skills/figwig/references/errors.md +51 -0
- figwig-0.1.0/figwig/skills/figwig/references/reading.md +174 -0
- figwig-0.1.0/figwig/skills/figwig/references/threads-and-memory.md +122 -0
- figwig-0.1.0/figwig/skills/figwig/references/writing.md +135 -0
- figwig-0.1.0/figwig/writer.py +1565 -0
- figwig-0.1.0/pyproject.toml +106 -0
- figwig-0.1.0/tests/__init__.py +0 -0
- figwig-0.1.0/tests/conftest.py +90 -0
- figwig-0.1.0/tests/reads.py +280 -0
- figwig-0.1.0/tests/test_bam2bw.py +2352 -0
- figwig-0.1.0/tests/test_bigwig.py +1129 -0
- figwig-0.1.0/tests/test_install_skill.py +169 -0
- figwig-0.1.0/tests/test_writer.py +1438 -0
- figwig-0.1.0/tests/writers.py +123 -0
figwig-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Never distributed -- personal agent instructions and working notes
|
|
2
|
+
CLAUDE.md
|
|
3
|
+
claude_comments/
|
|
4
|
+
|
|
5
|
+
*.swp
|
|
6
|
+
*.swo
|
|
7
|
+
*~
|
|
8
|
+
|
|
9
|
+
*.py[cod]
|
|
10
|
+
__pycache__/
|
|
11
|
+
.cache
|
|
12
|
+
.pytest_cache
|
|
13
|
+
.ruff_cache
|
|
14
|
+
.coverage
|
|
15
|
+
.ipynb_checkpoints/
|
|
16
|
+
.venv/
|
|
17
|
+
|
|
18
|
+
# Setup and build
|
|
19
|
+
docs/_build/
|
|
20
|
+
docs/_*
|
|
21
|
+
*.egg-info/
|
|
22
|
+
dist/
|
|
23
|
+
build/
|
|
24
|
+
MANIFEST
|
|
25
|
+
|
|
26
|
+
# OS-generated files
|
|
27
|
+
.DS_Store
|
|
28
|
+
.Spotlight-V100
|
|
29
|
+
.Trashes
|
|
30
|
+
ehthumbs.db
|
|
31
|
+
Thumbs.db
|
|
32
|
+
|
|
33
|
+
# Model checkpoints and large artifacts
|
|
34
|
+
*.torch
|
|
35
|
+
*.log
|
figwig-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jacob Schreiber
|
|
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.
|
figwig-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: figwig
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A fast, multithreaded reader and writer of bigWig files, into and out of numpy.
|
|
5
|
+
Project-URL: Homepage, https://github.com/jmschrei/figwig
|
|
6
|
+
Project-URL: Repository, https://github.com/jmschrei/figwig
|
|
7
|
+
Project-URL: Issues, https://github.com/jmschrei/figwig/issues
|
|
8
|
+
Project-URL: Documentation, https://figwig.readthedocs.io
|
|
9
|
+
Author-email: Jacob Schreiber <jmschreiber91@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: bigwig,bioinformatics,genomics,machine-learning
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Requires-Dist: numba>=0.58
|
|
27
|
+
Requires-Dist: numpy>=1.23
|
|
28
|
+
Provides-Extra: bam2bw
|
|
29
|
+
Requires-Dist: biopython>=1.73; extra == 'bam2bw'
|
|
30
|
+
Requires-Dist: deflate>=0.9; extra == 'bam2bw'
|
|
31
|
+
Requires-Dist: isal>=1.0; extra == 'bam2bw'
|
|
32
|
+
Requires-Dist: pyfaidx>=0.8; extra == 'bam2bw'
|
|
33
|
+
Requires-Dist: pysam>=0.22; extra == 'bam2bw'
|
|
34
|
+
Requires-Dist: tqdm>=4.60; extra == 'bam2bw'
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: biopython>=1.73; extra == 'dev'
|
|
37
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: deflate>=0.9; extra == 'dev'
|
|
39
|
+
Requires-Dist: isal>=1.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: pybigtools<0.3,>=0.2.5; extra == 'dev'
|
|
41
|
+
Requires-Dist: pybigwig>=0.3.26; (sys_platform != 'win32') and extra == 'dev'
|
|
42
|
+
Requires-Dist: pyfaidx>=0.8; extra == 'dev'
|
|
43
|
+
Requires-Dist: pysam>=0.22; (sys_platform != 'win32') and extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
46
|
+
Requires-Dist: tqdm>=4.60; extra == 'dev'
|
|
47
|
+
Requires-Dist: twine>=4.0; extra == 'dev'
|
|
48
|
+
Provides-Extra: docs
|
|
49
|
+
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'docs'
|
|
50
|
+
Requires-Dist: sphinx>=7.0; extra == 'docs'
|
|
51
|
+
Provides-Extra: fast
|
|
52
|
+
Requires-Dist: deflate>=0.9; extra == 'fast'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# figwig
|
|
56
|
+
|
|
57
|
+
[](https://pepy.tech/projects/figwig) [](https://github.com/jmschrei/figwig/actions/workflows/python-package.yml) [](https://figwig.readthedocs.io/en/latest/?badge=latest)
|
|
58
|
+
|
|
59
|
+
[[docs](https://figwig.readthedocs.io/en/latest/index.html)][[release notes](https://figwig.readthedocs.io/en/latest/whats_new.html)]
|
|
60
|
+
|
|
61
|
+
A fast, multithreaded reader and writer of bigWig files, into and out of
|
|
62
|
+
numpy.
|
|
63
|
+
|
|
64
|
+
Loading training data for a genomics model means reading the signal under tens
|
|
65
|
+
or hundreds of thousands of windows: 1,000 bp around every peak and background
|
|
66
|
+
region of an experiment, say. figwig reads all of them in one call, straight
|
|
67
|
+
into a float32 array, from one bigWig or from several at once, and writes
|
|
68
|
+
bigWigs from the same windows, such as a model's predictions, or from
|
|
69
|
+
intervals. The common readers make one call per window, and each call holds
|
|
70
|
+
Python's GIL, so adding threads does not help them. figwig decompresses and
|
|
71
|
+
compresses with zlib or libdeflate and decodes with numba, all without the
|
|
72
|
+
GIL, so its threads run in parallel.
|
|
73
|
+
|
|
74
|
+
Its command, `figwig bam2bw`, turns SAM/BAM files of reads, or BED/tsv files
|
|
75
|
+
of fragments, into bigWigs of per-base counts. It is
|
|
76
|
+
[bam2bw](https://github.com/jmschrei/bam2bw) with the same arguments, outputs
|
|
77
|
+
and messages, with faster readers. figwig depends only on numpy and numba.
|
|
78
|
+
|
|
79
|
+
| | figwig | fastest other tool |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| Read 167,750 windows of 1,000 bp from an ATAC-seq bigWig | **0.135 s** on 8 threads | 1.25 s, pybigtools |
|
|
82
|
+
| Write 15.9 million per-base counts | **0.18 s** on 8 threads | 4.20 s, pyBigWig |
|
|
83
|
+
| Write 21.2 million intervals, with zoom levels | **0.55 s** on 8 threads | 5.47 s, pybigtools |
|
|
84
|
+
| Convert a 2.4 GB ATAC-seq BAM to two stranded bigWigs | **4.65 s**, 910 MB peak, at `-p 2` | 58.48 s, 3,039 MB peak, bam2bw 0.5.1 |
|
|
85
|
+
|
|
86
|
+
Measured on a 2x AMD EPYC 9575F with Python 3.13 and numba 0.68. The
|
|
87
|
+
[benchmarks page](https://figwig.readthedocs.io/en/latest/benchmarks.html) has
|
|
88
|
+
the full setup.
|
|
89
|
+
|
|
90
|
+
<details>
|
|
91
|
+
<summary><b>More numbers and plots</b></summary>
|
|
92
|
+
|
|
93
|
+
#### Reading
|
|
94
|
+
|
|
95
|
+
167,750 windows of 1,000 bp centred on the fold-0 training peaks and negatives
|
|
96
|
+
of ENCODE ATAC-seq experiment ENCSR123WME, read from the ATAC-seq bigWig
|
|
97
|
+
ENCFF830RWF (238 MB) and the DNase-seq bigWig ENCFF989SAK (645 MB) on tmpfs,
|
|
98
|
+
sorted by position, file opening included; median of three runs. The other
|
|
99
|
+
libraries' 8-thread runs split the windows into 8 chunks on a thread pool.
|
|
100
|
+
Every library returned the same values, once pyBigWig's NaN for bases without
|
|
101
|
+
an interval was set to 0.
|
|
102
|
+
|
|
103
|
+
| library | ATAC, 1 thread | ATAC, 8 threads | DNase, 1 thread | DNase, 8 threads |
|
|
104
|
+
|---|---|---|---|---|
|
|
105
|
+
| pybigtools 0.2.5, `values()` per window | 1.25 s | 1.42 s | 1.98 s | 2.21 s |
|
|
106
|
+
| pyBigWig 0.3.26, `values()` per window | 3.95 s | 4.08 s | 4.50 s | 4.64 s |
|
|
107
|
+
| pybbi 0.4.2, `stackup` | 9.61 s | 9.48 s | 10.75 s | 10.63 s |
|
|
108
|
+
| figwig 0.1.0 | 0.81 s | **0.135 s** | 1.85 s | **0.277 s** |
|
|
109
|
+
|
|
110
|
+
#### Writing
|
|
111
|
+
|
|
112
|
+
The plus-strand 5' ends of ENCODE ATAC-seq BAM ENCFF877LRY, as counts at
|
|
113
|
+
15,875,960 single bases, and the fold-change signal ENCFF932UQM, as 21,212,477
|
|
114
|
+
intervals, written from memory onto tmpfs at compression level 6, opening and
|
|
115
|
+
closing included; median of three runs. pybigtools always writes zoom levels.
|
|
116
|
+
|
|
117
|
+
| writer | counts | counts, zoom levels | signal | signal, zoom levels |
|
|
118
|
+
|---|---|---|---|---|
|
|
119
|
+
| pyBigWig 0.3.26 | 4.20 s | 12.80 s | 7.41 s | 10.48 s |
|
|
120
|
+
| pybigtools 0.2.5 | | 4.45 s | | 5.47 s |
|
|
121
|
+
| figwig, zlib, 1 thread | 4.25 s | 12.09 s | 6.21 s | 8.10 s |
|
|
122
|
+
| figwig, zlib, 8 threads | 0.53 s | 1.63 s | 0.78 s | 1.09 s |
|
|
123
|
+
| figwig, libdeflate, 1 thread | 1.07 s | 4.85 s | 1.80 s | 3.27 s |
|
|
124
|
+
| figwig, libdeflate, 8 threads | **0.18 s** | **0.75 s** | **0.30 s** | **0.55 s** |
|
|
125
|
+
|
|
126
|
+
figwig's files were the size of pyBigWig's. For the counts, its peak memory
|
|
127
|
+
was above pyBigWig's without zoom levels, 554 MB against 354 MB on one thread,
|
|
128
|
+
and below it with them, 739 MB on 8 threads against 1,089 MB.
|
|
129
|
+
|
|
130
|
+
#### figwig bam2bw
|
|
131
|
+
|
|
132
|
+
ENCODE ATAC-seq BAM ENCFF877LRY (2.4 GB) at default flags, and 18.9 million
|
|
133
|
+
scATAC-seq fragments with `-f -u`, from the page cache; figwig's median of
|
|
134
|
+
five runs at `-p 2` and one at `-p 8`, and one run of bam2bw, which reads one
|
|
135
|
+
file in one process whatever `-p` is.
|
|
136
|
+
|
|
137
|
+
| | BAM | fragments | peak memory, BAM | peak memory, fragments |
|
|
138
|
+
|---|---|---|---|---|
|
|
139
|
+
| bam2bw 0.5.1, `-p 2` | 58.48 s | 28.45 s | 3,039 MB | 2,866 MB |
|
|
140
|
+
| figwig bam2bw, `-p 2` | **4.65 s** | **1.73 s** | 910 MB | 1,061 MB |
|
|
141
|
+
| figwig bam2bw, `-p 8` | **1.82 s** | **1.31 s** | 949 MB | 1,180 MB |
|
|
142
|
+
|
|
143
|
+
Both also ran on every one of 591 public BAM, SAM, BED and TSV test files that
|
|
144
|
+
bam2bw takes, from 3 records to a 10 GB ATAC-seq BAM, under 5 to 9 sets of
|
|
145
|
+
flags each, timed once, 16 at a time. In all 3,781 runs that bam2bw
|
|
146
|
+
completed, figwig bam2bw gave the same exit code, messages and decoded
|
|
147
|
+
entries. Where bam2bw took a second or more, figwig bam2bw was a median 3.2
|
|
148
|
+
times faster; where bam2bw took under half a second, figwig bam2bw took a
|
|
149
|
+
median 0.12 s longer, mostly importing numba.
|
|
150
|
+
|
|
151
|
+

|
|
152
|
+
|
|
153
|
+

|
|
154
|
+
|
|
155
|
+
The memory runs were made before figwig bam2bw dropped the keys it had
|
|
156
|
+
counted while still reading a BAM. On the 10 GB BAM at `-p 1` its peak is now
|
|
157
|
+
2.9 GB, against bam2bw's 11.6 GB, and 4.9 GB with `-u -f`, against 20.2 GB.
|
|
158
|
+
|
|
159
|
+
#### Threads
|
|
160
|
+
|
|
161
|
+
The same reads, writes and conversions at 1 to 32 threads, one run at a time,
|
|
162
|
+
median of three. Reading gained up to 32 threads, writing with libdeflate up
|
|
163
|
+
to 8 or 16, and figwig bam2bw up to about 8.
|
|
164
|
+
|
|
165
|
+

|
|
166
|
+
|
|
167
|
+
</details>
|
|
168
|
+
|
|
169
|
+
## Installation
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pip install figwig
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Or, with [uv](https://docs.astral.sh/uv/):
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
uv add figwig
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
It needs Python 3.10 or later, numpy 1.23 or later, and numba 0.58 or later.
|
|
182
|
+
Optional extras:
|
|
183
|
+
|
|
184
|
+
- `figwig[fast]` adds the `deflate` package, which makes writing several times
|
|
185
|
+
faster.
|
|
186
|
+
- `figwig[bam2bw]` adds pysam, pyfaidx, biopython, tqdm, isal and deflate,
|
|
187
|
+
which `figwig bam2bw` needs. `figwig bam2bw` runs on Linux and macOS, since
|
|
188
|
+
pysam does not support Windows.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
pip install "figwig[fast]"
|
|
192
|
+
pip install "figwig[bam2bw]"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Development install
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
git clone https://github.com/jmschrei/figwig.git
|
|
199
|
+
cd figwig
|
|
200
|
+
uv sync --extra dev
|
|
201
|
+
uv run pytest
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Claude Code Skill
|
|
205
|
+
|
|
206
|
+
figwig ships a [Claude Code](https://claude.com/claude-code) skill that
|
|
207
|
+
teaches a coding agent to use figwig in any project: reading windows,
|
|
208
|
+
writing predictions, intervals and counts, converting reads with
|
|
209
|
+
`figwig bam2bw`, the rules a write follows, what each error means, and how
|
|
210
|
+
much threads gain. Install it into `~/.claude/skills/figwig` with:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
figwig install-skill
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
After upgrading figwig, run `figwig install-skill --force` to replace the
|
|
217
|
+
installed copy, which otherwise raises `FileExistsError`. `-d DIRECTORY`
|
|
218
|
+
installs into another skills directory, and `--symlink` links to the copy
|
|
219
|
+
inside the installed package instead of copying it.
|
|
220
|
+
|
|
221
|
+
## Python API
|
|
222
|
+
|
|
223
|
+
The examples read two public ENCODE bigWigs: the ATAC-seq signal of HG02943
|
|
224
|
+
(ENCFF830RWF, 238 MB) and the DNase-seq signal of dorsolateral prefrontal
|
|
225
|
+
cortex (ENCFF989SAK, 645 MB).
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
wget https://www.encodeproject.org/files/ENCFF830RWF/@@download/ENCFF830RWF.bigWig
|
|
229
|
+
wget https://www.encodeproject.org/files/ENCFF989SAK/@@download/ENCFF989SAK.bigWig
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### Reading windows
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
import numpy
|
|
236
|
+
from figwig import BigWigReader
|
|
237
|
+
|
|
238
|
+
bw = BigWigReader("ENCFF830RWF.bigWig")
|
|
239
|
+
chroms = numpy.array(["chr1", "chr1", "chr2"])
|
|
240
|
+
starts = numpy.array([1_000_000, 2_500_000, 300_000])
|
|
241
|
+
y = bw.read(chroms, starts, width=1000, n_jobs=8)
|
|
242
|
+
print(y.shape, y.dtype)
|
|
243
|
+
# (3, 1000) float32
|
|
244
|
+
print(y.sum(axis=1))
|
|
245
|
+
# [116. 43. 10.]
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Window `j` covers `[starts[j], starts[j] + width)` on `chroms[j]`, 0-based as
|
|
249
|
+
in BED files, and is written into row `j`, whatever order the windows are
|
|
250
|
+
given in. A base that no interval covers is `missing`, 0 unless given, and a
|
|
251
|
+
base past the end of its chromosome is NaN. A `BigWigReader` reads the file's
|
|
252
|
+
index once and keeps it, and can be pickled to DataLoader workers.
|
|
253
|
+
|
|
254
|
+
#### Reading several bigWigs into one array
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
import numpy
|
|
258
|
+
from figwig import read_bigwig
|
|
259
|
+
|
|
260
|
+
chroms = numpy.array(["chr1", "chr1", "chr2"])
|
|
261
|
+
starts = numpy.array([1_000_000, 2_500_000, 300_000])
|
|
262
|
+
y = read_bigwig(["ENCFF830RWF.bigWig", "ENCFF989SAK.bigWig"], chroms, starts,
|
|
263
|
+
width=1000)
|
|
264
|
+
print(y.shape)
|
|
265
|
+
# (3, 2, 1000)
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Channel `i` holds the values from the `i`-th file, in the
|
|
269
|
+
`(batch, channels, length)` layout that sequence models take, and every
|
|
270
|
+
file's work shares one pool of threads.
|
|
271
|
+
|
|
272
|
+
#### Writing windows
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
import numpy
|
|
276
|
+
from figwig import read_bigwig
|
|
277
|
+
from figwig import write_bigwig
|
|
278
|
+
|
|
279
|
+
chrom_sizes = {"chr1": 248_956_422, "chr2": 242_193_529}
|
|
280
|
+
chroms = numpy.array(["chr2", "chr1", "chr1"])
|
|
281
|
+
starts = numpy.array([300_000, 2_500_000, 1_000_000])
|
|
282
|
+
y_hat = numpy.random.default_rng(0).random((3, 2, 1000), dtype=numpy.float32)
|
|
283
|
+
|
|
284
|
+
write_bigwig(["plus.bw", "minus.bw"], chrom_sizes, chroms, starts, y_hat)
|
|
285
|
+
y = read_bigwig(["plus.bw", "minus.bw"], chroms, starts, width=1000)
|
|
286
|
+
print(numpy.array_equal(y, y_hat))
|
|
287
|
+
# True
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`write_bigwig` takes what `read_bigwig` gives, such as a model's predictions
|
|
291
|
+
for the same windows. A base whose value is `missing`, 0.0 unless given, or
|
|
292
|
+
NaN is left out of the file, so that reading with the same `missing` gives
|
|
293
|
+
the values back.
|
|
294
|
+
|
|
295
|
+
#### Writing a batch at a time
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
from figwig import BigWigReader
|
|
299
|
+
from figwig import BigWigWriter
|
|
300
|
+
|
|
301
|
+
chrom_sizes = {"chr1": 248_956_422, "chr2": 242_193_529}
|
|
302
|
+
with BigWigWriter("example.bw", chrom_sizes) as writer:
|
|
303
|
+
writer.write("chr1", [1000, 2000], [0.5, 2.0], ends=[1500, 2100])
|
|
304
|
+
writer.write("chr1", [5000, 5003, 5004], [[3], [1], [1]])
|
|
305
|
+
writer.write("chr2", [10_000], [[0.0, 1.5, 1.5, 0.0, 2.5]])
|
|
306
|
+
|
|
307
|
+
y = BigWigReader("example.bw").read(["chr1", "chr2"], [5000, 10_000], width=6)
|
|
308
|
+
print(y)
|
|
309
|
+
# [[3. 0. 0. 1. 1. 0. ]
|
|
310
|
+
# [0. 1.5 1.5 0. 2.5 0. ]]
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
`BigWigWriter` writes intervals (with `ends`), single bases (windows of width
|
|
314
|
+
1) and windows as they come, so a track larger than memory can be written a
|
|
315
|
+
batch at a time. Each call's items come after the last call's, in the order
|
|
316
|
+
of `chrom_sizes`. The header, index and zoom levels are written when the
|
|
317
|
+
writer is closed.
|
|
318
|
+
|
|
319
|
+
The documentation's [reading](https://figwig.readthedocs.io/en/latest/reading.html)
|
|
320
|
+
and [writing](https://figwig.readthedocs.io/en/latest/writing.html) guides
|
|
321
|
+
cover the rest: values and coordinates, chromosomes a file does not have,
|
|
322
|
+
PyTorch data loaders, binned values, the files figwig refuses and falling back
|
|
323
|
+
to another reader, compression, zoom levels, and files identical to
|
|
324
|
+
pyBigWig's.
|
|
325
|
+
|
|
326
|
+
## Command line
|
|
327
|
+
|
|
328
|
+
#### figwig bam2bw
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
figwig bam2bw my.bam -s hg38.chrom.sizes -n test-run -p 8 # test-run.+.bw, test-run.-.bw
|
|
332
|
+
figwig bam2bw fragments.tsv.gz -s hg38.chrom.sizes -n test-run -f -u -p 8 # test-run.bw
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
`figwig bam2bw` is bam2bw 0.5.1 with the same arguments, output files and
|
|
336
|
+
messages, except that `-p` is a number of cores, 1 unless given. By default
|
|
337
|
+
it counts the 5' end of every mapped read at each base, and writes the counts
|
|
338
|
+
of the two strands to two bigWigs; `-u` writes one, `-f` counts both ends of
|
|
339
|
+
each fragment, `-3p` the 3' ends, `-ps`, `-ns`, `-sf` and `-r` shift and scale
|
|
340
|
+
the counts, and `-z` writes zoom levels. A BAM file is inflated by libdeflate
|
|
341
|
+
and walked by a numba kernel on `-p` threads, and a BED/tsv file is scanned
|
|
342
|
+
by a numba kernel; SAM files, `--mate_pairs`, remote files and malformed
|
|
343
|
+
records go through bam2bw's own pysam or line loop, so that their result, or
|
|
344
|
+
their error, is bam2bw's. The bigWigs hold bam2bw's entries but not its bytes,
|
|
345
|
+
since figwig compresses them with libdeflate at level 1. `figwig bam2bw -h`
|
|
346
|
+
lists the arguments, [bam2bw's README](https://github.com/jmschrei/bam2bw)
|
|
347
|
+
has an example of each, and the
|
|
348
|
+
[documentation](https://figwig.readthedocs.io/en/latest/bam2bw.html) says how
|
|
349
|
+
files are read and shared across cores.
|
|
350
|
+
|
|
351
|
+
#### figwig install-skill
|
|
352
|
+
|
|
353
|
+
Installs the Claude Code skill; see [above](#claude-code-skill).
|
|
354
|
+
|
|
355
|
+
## Origin
|
|
356
|
+
|
|
357
|
+
figwig began as the bigWig reader inside
|
|
358
|
+
[tangermeme](https://github.com/jmschrei/tangermeme)'s `extract_loci`
|
|
359
|
+
(PR #107). It was checked there against pybigtools, bit for bit, on the
|
|
360
|
+
training and validation sets of 92 Cherimoya models and on 3,131 synthetic
|
|
361
|
+
cases.
|