ep-touche 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.
- ep_touche-0.1.0/.gitattributes +2 -0
- ep_touche-0.1.0/.github/workflows/ci.yml +48 -0
- ep_touche-0.1.0/.github/workflows/publish.yml +42 -0
- ep_touche-0.1.0/.gitignore +187 -0
- ep_touche-0.1.0/CLAUDE.md +150 -0
- ep_touche-0.1.0/LICENSE +21 -0
- ep_touche-0.1.0/PKG-INFO +177 -0
- ep_touche-0.1.0/README.md +155 -0
- ep_touche-0.1.0/docs/README.md +35 -0
- ep_touche-0.1.0/docs/api.md +163 -0
- ep_touche-0.1.0/docs/cli.md +497 -0
- ep_touche-0.1.0/docs/images/apa-flv-vs-dmso-obsoverexp.png +0 -0
- ep_touche-0.1.0/docs/images/apa-trp-vs-dmso-obsoverexp.png +0 -0
- ep_touche-0.1.0/docs/images/background-flv-vs-dmso.png +0 -0
- ep_touche-0.1.0/docs/images/background-trp-vs-dmso.png +0 -0
- ep_touche-0.1.0/docs/images/background-trp-vs-flv.png +0 -0
- ep_touche-0.1.0/docs/images/local-decay-violinplot.png +0 -0
- ep_touche-0.1.0/docs/micro-c-preprocessing.md +132 -0
- ep_touche-0.1.0/docs/reproducing-reference-plots.md +326 -0
- ep_touche-0.1.0/docs/testing-and-publishing.md +75 -0
- ep_touche-0.1.0/notes/benchmarks/benchmark_numba_kernels.py +375 -0
- ep_touche-0.1.0/notes/numba-implementation-plan.md +955 -0
- ep_touche-0.1.0/notes/touche-implementation-plan.md +873 -0
- ep_touche-0.1.0/pyproject.toml +43 -0
- ep_touche-0.1.0/scripts/_report.py +594 -0
- ep_touche-0.1.0/scripts/reference_replication.md +176 -0
- ep_touche-0.1.0/scripts/reference_replication.py +802 -0
- ep_touche-0.1.0/src/touche/__init__.py +12 -0
- ep_touche-0.1.0/src/touche/__main__.py +7 -0
- ep_touche-0.1.0/src/touche/anchors.py +27 -0
- ep_touche-0.1.0/src/touche/apa.py +581 -0
- ep_touche-0.1.0/src/touche/api.py +60 -0
- ep_touche-0.1.0/src/touche/backends.py +79 -0
- ep_touche-0.1.0/src/touche/background.py +417 -0
- ep_touche-0.1.0/src/touche/cli/__init__.py +5 -0
- ep_touche-0.1.0/src/touche/cli/__main__.py +7 -0
- ep_touche-0.1.0/src/touche/cli/apa.py +160 -0
- ep_touche-0.1.0/src/touche/cli/background.py +166 -0
- ep_touche-0.1.0/src/touche/cli/local_decay.py +270 -0
- ep_touche-0.1.0/src/touche/cli/main.py +32 -0
- ep_touche-0.1.0/src/touche/cli/preprocess.py +119 -0
- ep_touche-0.1.0/src/touche/cli/utils.py +59 -0
- ep_touche-0.1.0/src/touche/contacts.py +415 -0
- ep_touche-0.1.0/src/touche/instrumentation.py +75 -0
- ep_touche-0.1.0/src/touche/io.py +115 -0
- ep_touche-0.1.0/src/touche/local_decay.py +1020 -0
- ep_touche-0.1.0/src/touche/models.py +84 -0
- ep_touche-0.1.0/src/touche/numba/__init__.py +10 -0
- ep_touche-0.1.0/src/touche/numba/_kernel_imports.py +19 -0
- ep_touche-0.1.0/src/touche/numba/apa.py +212 -0
- ep_touche-0.1.0/src/touche/numba/background.py +313 -0
- ep_touche-0.1.0/src/touche/numba/local_decay.py +320 -0
- ep_touche-0.1.0/src/touche/numba/stats.py +66 -0
- ep_touche-0.1.0/src/touche/pair_stats.py +108 -0
- ep_touche-0.1.0/src/touche/pipelines.py +407 -0
- ep_touche-0.1.0/src/touche/preprocess.py +90 -0
- ep_touche-0.1.0/src/touche/stats.py +67 -0
- ep_touche-0.1.0/tests/fixtures/distiller_pairs.tsv +3 -0
- ep_touche-0.1.0/tests/test_apa.py +69 -0
- ep_touche-0.1.0/tests/test_apa_aggregate.py +160 -0
- ep_touche-0.1.0/tests/test_api.py +20 -0
- ep_touche-0.1.0/tests/test_background.py +85 -0
- ep_touche-0.1.0/tests/test_background_count.py +255 -0
- ep_touche-0.1.0/tests/test_contacts.py +215 -0
- ep_touche-0.1.0/tests/test_local_decay.py +642 -0
- ep_touche-0.1.0/tests/test_pair_stats.py +68 -0
- ep_touche-0.1.0/tests/test_pipelines.py +120 -0
- ep_touche-0.1.0/tests/test_preprocess.py +67 -0
- ep_touche-0.1.0/tests/test_stats.py +87 -0
- ep_touche-0.1.0/tests/test_version.py +15 -0
- ep_touche-0.1.0/uv.lock +1769 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Python ${{ matrix.python-version }}
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version:
|
|
20
|
+
- "3.10"
|
|
21
|
+
- "3.11"
|
|
22
|
+
- "3.12"
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- name: Check out repository
|
|
26
|
+
uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- name: Install uv
|
|
29
|
+
uses: astral-sh/setup-uv@v5
|
|
30
|
+
with:
|
|
31
|
+
enable-cache: true
|
|
32
|
+
|
|
33
|
+
- name: Set up Python
|
|
34
|
+
uses: actions/setup-python@v5
|
|
35
|
+
with:
|
|
36
|
+
python-version: ${{ matrix.python-version }}
|
|
37
|
+
|
|
38
|
+
- name: Install dependencies
|
|
39
|
+
run: uv sync --dev --extra legacy --python ${{ matrix.python-version }}
|
|
40
|
+
|
|
41
|
+
- name: Lint
|
|
42
|
+
run: uv run ruff check src tests
|
|
43
|
+
|
|
44
|
+
- name: Test
|
|
45
|
+
run: uv run pytest
|
|
46
|
+
|
|
47
|
+
- name: Build package
|
|
48
|
+
run: uv build
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types:
|
|
6
|
+
- published
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
name: Build and publish ep-touche
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
environment:
|
|
18
|
+
name: pypi
|
|
19
|
+
url: https://pypi.org/project/ep-touche/
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- name: Check out repository
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@v5
|
|
27
|
+
with:
|
|
28
|
+
enable-cache: true
|
|
29
|
+
|
|
30
|
+
- name: Set up Python
|
|
31
|
+
uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.12"
|
|
34
|
+
|
|
35
|
+
- name: Build distributions
|
|
36
|
+
run: uv build
|
|
37
|
+
|
|
38
|
+
- name: Check distributions
|
|
39
|
+
run: uvx twine check dist/*
|
|
40
|
+
|
|
41
|
+
- name: Publish to PyPI
|
|
42
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
**/.DS_Store
|
|
2
|
+
**/.vscode
|
|
3
|
+
_reference/
|
|
4
|
+
benchmark/
|
|
5
|
+
|
|
6
|
+
# Byte-compiled / optimized / DLL files
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*$py.class
|
|
10
|
+
|
|
11
|
+
# C extensions
|
|
12
|
+
*.so
|
|
13
|
+
|
|
14
|
+
# Distribution / packaging
|
|
15
|
+
.Python
|
|
16
|
+
build/
|
|
17
|
+
develop-eggs/
|
|
18
|
+
dist/
|
|
19
|
+
downloads/
|
|
20
|
+
eggs/
|
|
21
|
+
.eggs/
|
|
22
|
+
lib/
|
|
23
|
+
lib64/
|
|
24
|
+
parts/
|
|
25
|
+
sdist/
|
|
26
|
+
var/
|
|
27
|
+
wheels/
|
|
28
|
+
share/python-wheels/
|
|
29
|
+
*.egg-info/
|
|
30
|
+
.installed.cfg
|
|
31
|
+
*.egg
|
|
32
|
+
MANIFEST
|
|
33
|
+
|
|
34
|
+
# PyInstaller
|
|
35
|
+
# Usually these files are written by a python script from a template
|
|
36
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
37
|
+
*.manifest
|
|
38
|
+
*.spec
|
|
39
|
+
|
|
40
|
+
# Installer logs
|
|
41
|
+
pip-log.txt
|
|
42
|
+
pip-delete-this-directory.txt
|
|
43
|
+
|
|
44
|
+
# Unit test / coverage reports
|
|
45
|
+
htmlcov/
|
|
46
|
+
.tox/
|
|
47
|
+
.nox/
|
|
48
|
+
.coverage
|
|
49
|
+
.coverage.*
|
|
50
|
+
.cache
|
|
51
|
+
nosetests.xml
|
|
52
|
+
coverage.xml
|
|
53
|
+
*.cover
|
|
54
|
+
*.py,cover
|
|
55
|
+
.hypothesis/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
cover/
|
|
58
|
+
|
|
59
|
+
# Translations
|
|
60
|
+
*.mo
|
|
61
|
+
*.pot
|
|
62
|
+
|
|
63
|
+
# Django stuff:
|
|
64
|
+
*.log
|
|
65
|
+
local_settings.py
|
|
66
|
+
db.sqlite3
|
|
67
|
+
db.sqlite3-journal
|
|
68
|
+
|
|
69
|
+
# Flask stuff:
|
|
70
|
+
instance/
|
|
71
|
+
.webassets-cache
|
|
72
|
+
|
|
73
|
+
# Scrapy stuff:
|
|
74
|
+
.scrapy
|
|
75
|
+
|
|
76
|
+
# Sphinx documentation
|
|
77
|
+
docs/_build/
|
|
78
|
+
|
|
79
|
+
# PyBuilder
|
|
80
|
+
.pybuilder/
|
|
81
|
+
target/
|
|
82
|
+
|
|
83
|
+
# Jupyter Notebook
|
|
84
|
+
.ipynb_checkpoints
|
|
85
|
+
|
|
86
|
+
# IPython
|
|
87
|
+
profile_default/
|
|
88
|
+
ipython_config.py
|
|
89
|
+
|
|
90
|
+
# pyenv
|
|
91
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
92
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
93
|
+
# .python-version
|
|
94
|
+
|
|
95
|
+
# pipenv
|
|
96
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
97
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
98
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
99
|
+
# install all needed dependencies.
|
|
100
|
+
#Pipfile.lock
|
|
101
|
+
|
|
102
|
+
# UV
|
|
103
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
104
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
105
|
+
# commonly ignored for libraries.
|
|
106
|
+
#uv.lock
|
|
107
|
+
.uv-cache/
|
|
108
|
+
|
|
109
|
+
# poetry
|
|
110
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
111
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
112
|
+
# commonly ignored for libraries.
|
|
113
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
114
|
+
#poetry.lock
|
|
115
|
+
|
|
116
|
+
# pdm
|
|
117
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
118
|
+
#pdm.lock
|
|
119
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
120
|
+
# in version control.
|
|
121
|
+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
122
|
+
.pdm.toml
|
|
123
|
+
.pdm-python
|
|
124
|
+
.pdm-build/
|
|
125
|
+
|
|
126
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
127
|
+
__pypackages__/
|
|
128
|
+
|
|
129
|
+
# Celery stuff
|
|
130
|
+
celerybeat-schedule
|
|
131
|
+
celerybeat.pid
|
|
132
|
+
|
|
133
|
+
# SageMath parsed files
|
|
134
|
+
*.sage.py
|
|
135
|
+
|
|
136
|
+
# Environments
|
|
137
|
+
.env
|
|
138
|
+
.venv
|
|
139
|
+
env/
|
|
140
|
+
venv/
|
|
141
|
+
ENV/
|
|
142
|
+
env.bak/
|
|
143
|
+
venv.bak/
|
|
144
|
+
|
|
145
|
+
# Spyder project settings
|
|
146
|
+
.spyderproject
|
|
147
|
+
.spyproject
|
|
148
|
+
|
|
149
|
+
# Rope project settings
|
|
150
|
+
.ropeproject
|
|
151
|
+
|
|
152
|
+
# mkdocs documentation
|
|
153
|
+
/site
|
|
154
|
+
|
|
155
|
+
# mypy
|
|
156
|
+
.mypy_cache/
|
|
157
|
+
.dmypy.json
|
|
158
|
+
dmypy.json
|
|
159
|
+
|
|
160
|
+
# Pyre type checker
|
|
161
|
+
.pyre/
|
|
162
|
+
|
|
163
|
+
# pytype static type analyzer
|
|
164
|
+
.pytype/
|
|
165
|
+
|
|
166
|
+
# Cython debug symbols
|
|
167
|
+
cython_debug/
|
|
168
|
+
|
|
169
|
+
# PyCharm
|
|
170
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
171
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
172
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
173
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
174
|
+
#.idea/
|
|
175
|
+
|
|
176
|
+
# Ruff stuff:
|
|
177
|
+
.ruff_cache/
|
|
178
|
+
|
|
179
|
+
# PyPI configuration file
|
|
180
|
+
.pypirc
|
|
181
|
+
|
|
182
|
+
# Cursor
|
|
183
|
+
# Cursor is an AI-powered code editor.`.cursorignore` specifies files/directories to
|
|
184
|
+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
|
185
|
+
# refer to https://docs.cursor.com/context/ignore-files
|
|
186
|
+
.cursorignore
|
|
187
|
+
.cursorindexingignore
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What this is
|
|
6
|
+
|
|
7
|
+
`touche` (PyPI: `ep-touche`) is a Python package + CLI that refactors the
|
|
8
|
+
Danko Lab `E-P_contacts` R/shell reference workflows for high-resolution
|
|
9
|
+
chromatin contact (Micro-C) analysis into a dependency-light, faster
|
|
10
|
+
implementation. It starts from processed pairs files (from `distiller-nf` or
|
|
11
|
+
equivalent) — it does not do FASTQ alignment, dedup, or cooler generation.
|
|
12
|
+
|
|
13
|
+
The original reference implementation lives at `_reference/E-P_contacts/`
|
|
14
|
+
(R/awk/shell scripts). New Python implementations are expected to reproduce
|
|
15
|
+
its numeric behavior; when in doubt about expected output shape or a
|
|
16
|
+
threshold/default, check the corresponding reference script there before
|
|
17
|
+
changing behavior.
|
|
18
|
+
|
|
19
|
+
`touche` uses `polars` as its only dataframe library, both internally and at
|
|
20
|
+
the public `touche.api` surface (`pl.DataFrame`/`pl.LazyFrame`) — `pandas` is
|
|
21
|
+
not a dependency. CSV outputs have no implicit index column (polars has no
|
|
22
|
+
index concept); anywhere a row label matters (e.g. APA's pixel-bin matrices)
|
|
23
|
+
it's an explicit `bin_label` column instead.
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
Development uses `uv`.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
uv sync --dev # install package + dev deps
|
|
31
|
+
uv run touche --help # run the CLI
|
|
32
|
+
uv run pytest # run the full test suite
|
|
33
|
+
uv run pytest tests/test_apa.py # run one test file
|
|
34
|
+
uv run pytest tests/test_apa.py::test_name # run one test
|
|
35
|
+
uv run ruff check src tests # lint (this is what CI runs)
|
|
36
|
+
uv build # build sdist/wheel
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`mypy` is listed as a dev dependency but is not run in CI (`ci.yml` only runs
|
|
40
|
+
`ruff check` and `pytest`).
|
|
41
|
+
|
|
42
|
+
Numba is a core dependency (installed by `uv sync --dev`), so `backend="numba"`
|
|
43
|
+
code paths are always exercisable without an extra install step.
|
|
44
|
+
|
|
45
|
+
CI (`.github/workflows/ci.yml`) runs on Python 3.10/3.11/3.12: `uv sync --dev`,
|
|
46
|
+
`ruff check src tests`, `pytest`, `uv build`. See `docs/testing-and-publishing.md`
|
|
47
|
+
for the release/publish process (trusted PyPI publishing via `publish.yml`).
|
|
48
|
+
|
|
49
|
+
## Architecture
|
|
50
|
+
|
|
51
|
+
### Layering
|
|
52
|
+
|
|
53
|
+
- `touche.io` — `scan_pairs` builds a lazy `polars.LazyFrame` over pairs files
|
|
54
|
+
(canonical 9-column `touche` format vs. 10+ column `distiller`/pairtools
|
|
55
|
+
format, `source="auto"` sniffs the layout from the first data row's field
|
|
56
|
+
count). All downstream code reads pairs through this module.
|
|
57
|
+
- `touche.models` — shared frozen dataclasses: `ContactIndex` (numpy arrays
|
|
58
|
+
for one chromosome: `pos_a`, `pos_b`, strand, mapq), `PairStats`,
|
|
59
|
+
`NamedPath`/`NamedDepth` (used for `NAME=PATH` / `NAME=INTEGER` CLI
|
|
60
|
+
arguments across treatment/control commands).
|
|
61
|
+
- `touche.contacts` — builds `ContactIndex` per chromosome from a pairs file
|
|
62
|
+
and reads/writes chromosome-sharded NPZ caches (`build_contact_indexes`,
|
|
63
|
+
`build_npz_cache`, `load_npz_cache`, `write_npz_cache`). This is the
|
|
64
|
+
in-memory numeric representation almost every compute function operates on.
|
|
65
|
+
`build_npz_cache`'s default (non-`"all"`) path spools the scanned pairs to a
|
|
66
|
+
local Parquet file once, then materializes and writes one chromosome's rows
|
|
67
|
+
at a time — peak memory is bounded by the largest single chromosome, not the
|
|
68
|
+
whole file.
|
|
69
|
+
- `touche.preprocess` — pairs filtering/conversion (mapq + cis/trans filters,
|
|
70
|
+
distiller→touche format conversion).
|
|
71
|
+
- `touche.pair_stats` — QC accumulation (row counts, cis/trans, mapq
|
|
72
|
+
pass/fail, per-chromosome, distance histogram) shared by `preprocess qc`,
|
|
73
|
+
`preprocess summarize`, and cache building (so a large file is scanned once
|
|
74
|
+
for both the cache and its QC).
|
|
75
|
+
- Domain modules — `touche.local_decay`, `touche.apa`, `touche.background`:
|
|
76
|
+
each exposes an in-memory `compute_*` function operating on `ContactIndex`
|
|
77
|
+
objects/anchors, plus a file-driven wrapper (e.g. `call_local_decay`,
|
|
78
|
+
`aggregate_apa`, `count_ep_and_background`) that reads inputs, calls the
|
|
79
|
+
compute function, and writes output files.
|
|
80
|
+
- `touche.pipelines` — `run_*_pipeline` functions that chain the file-driven
|
|
81
|
+
wrappers for a full command-group workflow (e.g. call → assign → plot for
|
|
82
|
+
local-decay) and write a `manifest.json` (inputs, parameters, outputs,
|
|
83
|
+
metrics, `touche` version, elapsed time, optional per-step timings).
|
|
84
|
+
- `touche.api` — the curated notebook-facing re-export surface (`import
|
|
85
|
+
touche.api as tt`); update `__all__` here when adding a new public
|
|
86
|
+
compute/plot function intended for interactive use.
|
|
87
|
+
- `touche.cli/` — one argparse module per command group (`preprocess.py`,
|
|
88
|
+
`local_decay.py`, `background.py`, `apa.py`), wired together in `main.py`.
|
|
89
|
+
Each subcommand's `func` callback maps CLI args to the corresponding
|
|
90
|
+
domain/pipeline function and prints a JSON summary via `cli/utils.py`.
|
|
91
|
+
- `touche.backends` / `touche.numba/` — Numba acceleration, a core
|
|
92
|
+
dependency. `touche.numba` is a subpackage split by the domain that uses
|
|
93
|
+
each kernel (`touche.numba.apa`, `.background`, `.local_decay`, `.stats`);
|
|
94
|
+
numba is never imported at package import time — only when a
|
|
95
|
+
numba-accelerated function is actually called, so every `from
|
|
96
|
+
touche.numba.<domain> import ...` happens inside a function body, never at
|
|
97
|
+
a domain module's own top level. Counting (APA matrix/1D signal,
|
|
98
|
+
EP/background pairs, local-decay's observed-count helper) always uses its
|
|
99
|
+
Numba kernel — each was verified exact-equivalent to the plain NumPy
|
|
100
|
+
implementation it replaced (see `notes/numba-implementation-plan.md`), so
|
|
101
|
+
there's no `backend` choice exposed for it. `lowess_backend`
|
|
102
|
+
(`"numba"`/`"statsmodels"`) and `fisher_backend` (`"numba"`/`"scipy"`) are
|
|
103
|
+
different: each numba path is a validated but inexact approximation of its
|
|
104
|
+
alternative, so both choices remain exposed, defaulting to `"numba"`.
|
|
105
|
+
- `touche.instrumentation` — the shared `Instrumentation` dataclass
|
|
106
|
+
(`progress`, `profile`) threaded through compute/pipeline functions as the
|
|
107
|
+
`progress=` argument. `instrument.iter(...)` wraps iterables with `tqdm`
|
|
108
|
+
when enabled; `instrument.step("name")` is a context manager that records
|
|
109
|
+
step timings when `profile=True`. CLI flags: `--progress`/`--profile`.
|
|
110
|
+
|
|
111
|
+
### Contact indexing strategies
|
|
112
|
+
|
|
113
|
+
Local-decay (and similar chromosome-scoped work) supports three
|
|
114
|
+
`index_strategy` values, most relevant when touching caching or performance
|
|
115
|
+
code:
|
|
116
|
+
|
|
117
|
+
- `cache` (default): build/reuse chromosome-sharded NPZ caches under
|
|
118
|
+
`--cache-dir` (or `contact_index_cache/` next to the output), loading one
|
|
119
|
+
chromosome shard at a time — lowest memory.
|
|
120
|
+
- `all`: read the whole pairs file once, hold every chromosome in memory —
|
|
121
|
+
fastest given enough RAM.
|
|
122
|
+
- `chromosome`: re-scan the pairs file once per bait chromosome, keeping only
|
|
123
|
+
one chromosome resident — no persistent cache files, but slow on gzipped
|
|
124
|
+
input.
|
|
125
|
+
|
|
126
|
+
### Pairs source formats
|
|
127
|
+
|
|
128
|
+
Most commands take `--source {auto,distiller,touche}`. `touche` format is the
|
|
129
|
+
canonical 9-column layout this package writes (`preprocess filter-pairs`/
|
|
130
|
+
`convert-pairs`); `distiller` is pairtools/distiller-nf's 10+ column layout
|
|
131
|
+
(leading read_id column). `auto` infers from field count — don't rely on
|
|
132
|
+
`auto` when column counts could plausibly overlap between formats.
|
|
133
|
+
|
|
134
|
+
### Repository conventions
|
|
135
|
+
|
|
136
|
+
- `docs/` — human-facing usage guides a `touche` user should read directly
|
|
137
|
+
(CLI reference, API guide, preprocessing, reproducing reference plots,
|
|
138
|
+
testing/publishing). Keep these current when changing CLI flags or public
|
|
139
|
+
API signatures.
|
|
140
|
+
- `notes/` — agent-facing implementation plans, benchmark logs, and design
|
|
141
|
+
sketches. Do not put user-facing documentation here, and don't move scratch
|
|
142
|
+
planning into `docs/` unless it's rewritten for users.
|
|
143
|
+
- `scripts/` — standalone, runnable tools promoted out of `notes/` once
|
|
144
|
+
they're more than a one-off benchmark log (e.g. `reference_replication.py`,
|
|
145
|
+
which downloads the upstream E-P_contacts example data and replicates its
|
|
146
|
+
reference workflows end to end). Not part of the `touche` package build.
|
|
147
|
+
- `_reference/E-P_contacts/` — the original reference workflows being ported;
|
|
148
|
+
treat as read-only prior art, not something to modify.
|
|
149
|
+
- Manifests, cache directories, and other generated outputs (`.cache/`,
|
|
150
|
+
`contact_index_cache/`, `results/`) are run artifacts, not source.
|
ep_touche-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Adam Youlin He
|
|
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.
|
ep_touche-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ep-touche
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Tools for preprocessing and analyzing high-resolution chromatin contact data.
|
|
5
|
+
Project-URL: Homepage, https://github.com/adamyhe/touche
|
|
6
|
+
Project-URL: Repository, https://github.com/adamyhe/touche
|
|
7
|
+
Project-URL: Issues, https://github.com/adamyhe/touche/issues
|
|
8
|
+
Author: Adam He
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Requires-Dist: matplotlib>=3.7
|
|
13
|
+
Requires-Dist: numba>=0.59
|
|
14
|
+
Requires-Dist: numpy>=1.24
|
|
15
|
+
Requires-Dist: polars>=1.0
|
|
16
|
+
Requires-Dist: scipy>=1.10
|
|
17
|
+
Requires-Dist: seaborn>=0.12
|
|
18
|
+
Requires-Dist: tqdm>=4.65
|
|
19
|
+
Provides-Extra: legacy
|
|
20
|
+
Requires-Dist: statsmodels>=0.14; extra == 'legacy'
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# touche
|
|
24
|
+
|
|
25
|
+
[](https://pypi.org/project/ep-touche/)
|
|
26
|
+
[](https://github.com/adamyhe/touche/actions/workflows/ci.yml)
|
|
27
|
+
[](https://pepy.tech/projects/ep-touche)
|
|
28
|
+
|
|
29
|
+
Python API and CLI tools for analyzing enhancer-promoter contacts (touches) from high-resolution chromatin contact data, refactored from the [Danko Lab E-P_contacts reference workflows](https://github.com/Danko-Lab/E-P_contacts).
|
|
30
|
+
|
|
31
|
+
`touche` starts from processed pairs files. Raw FASTQ processing, alignment,
|
|
32
|
+
deduplication, and cooler generation should be handled by an external workflow
|
|
33
|
+
such as [distiller-nf](https://github.com/open2c/distiller-nf).
|
|
34
|
+
|
|
35
|
+
## Status
|
|
36
|
+
|
|
37
|
+
The current implementation includes CLI tools+API for:
|
|
38
|
+
|
|
39
|
+
- Micro-C pairs conversion, filtering, QC, and chromosome-sharded NPZ caches
|
|
40
|
+
- local-decay contact calling, pair-type assignment, and plotting
|
|
41
|
+
- Aggregated peak analysis (APA) aggregation and inter-sample APA comparison
|
|
42
|
+
- enhancer/promoter local-background counting and treatment comparison
|
|
43
|
+
- pipeline `run` wrappers that preserve intermediate outputs and write JSON
|
|
44
|
+
manifests
|
|
45
|
+
|
|
46
|
+
## Installation
|
|
47
|
+
|
|
48
|
+
Install with `pip` from PyPI (package name is `ep-touche`):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install ep-touche
|
|
52
|
+
touche --help
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`uv` can also install and run the package:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
uv add ep-touche
|
|
59
|
+
uv run touche --help
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`local-decay` also supports a statsmodels-backed LOWESS path
|
|
63
|
+
(`lowess_backend="statsmodels"`) for exact reference comparisons
|
|
64
|
+
(at the cost of being much slower than our custom implementation).
|
|
65
|
+
Install the optional `legacy` extra only if you need that backend:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install ep-touche[legacy]
|
|
69
|
+
# or: uv sync --extra legacy
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Older CPUs and Rosetta
|
|
73
|
+
|
|
74
|
+
Polars publishes an `lts-cpu` wheel for older CPUs and for x86-64 Python on
|
|
75
|
+
Apple Silicon under Rosetta. Because `polars-lts-cpu` provides the same
|
|
76
|
+
`import polars` module but is a different Python distribution, it does not
|
|
77
|
+
automatically satisfy `ep-touche`'s normal `polars>=1.0` dependency. If the
|
|
78
|
+
standard Polars wheel does not run on your machine, install `ep-touche`, then
|
|
79
|
+
replace Polars in that environment:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install ep-touche
|
|
83
|
+
pip uninstall polars
|
|
84
|
+
pip install "polars-lts-cpu>=1.0"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## CLI Overview
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
touche preprocess --help
|
|
91
|
+
touche local-decay --help
|
|
92
|
+
touche apa --help
|
|
93
|
+
touche background --help
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Available command groups:
|
|
97
|
+
|
|
98
|
+
- `touche preprocess`: convert/filter pairs, write QC summaries, and build NPZ
|
|
99
|
+
caches.
|
|
100
|
+
- `touche local-decay`: call observed/expected contacts, assign pair types, plot
|
|
101
|
+
distributions, or run the full local-decay workflow.
|
|
102
|
+
- `touche apa`: aggregate APA matrices, compare treatment/control APAs, or run a
|
|
103
|
+
paired APA workflow.
|
|
104
|
+
- `touche background`: count EP/background contacts, compare treatment ratios,
|
|
105
|
+
or run the full EP/background workflow.
|
|
106
|
+
|
|
107
|
+
See the [CLI reference](docs/cli.md) for examples, common options, and expected
|
|
108
|
+
outputs.
|
|
109
|
+
|
|
110
|
+
## Typical workflow
|
|
111
|
+
|
|
112
|
+
Start from analysis-ready `.pairs` or `.pairs.gz` files produced by distiller-nf
|
|
113
|
+
or an equivalent workflow.
|
|
114
|
+
|
|
115
|
+
1. Filter or convert pairs with `touche preprocess`.
|
|
116
|
+
2. For real or repeated local-decay runs, build a position-only cache with
|
|
117
|
+
`touche preprocess build-cache --no-metadata`.
|
|
118
|
+
3. Use the `run` wrappers for end-to-end analyses:
|
|
119
|
+
`touche local-decay run`, `touche apa run`, and `touche background run`.
|
|
120
|
+
4. Use individual subcommands such as `local-decay call` or `background count`
|
|
121
|
+
when debugging or replacing one stage.
|
|
122
|
+
|
|
123
|
+
Many of the computation-heavy steps use `numba` acceleration and parallelism.
|
|
124
|
+
Set `NUMBA_NUM_THREADS` before running to control CPU usage (default is to use
|
|
125
|
+
all threads on machine):
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
NUMBA_NUM_THREADS=8 touche background run ...
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Python API
|
|
132
|
+
|
|
133
|
+
For notebooks and custom scripts, import the provisional API surface:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
import touche.api as tt
|
|
137
|
+
|
|
138
|
+
indexes = tt.build_contact_indexes("sample.nodups_30_intra.pairs.gz", source="touche")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The API is organized around reading pairs and anchors once, running in-memory
|
|
142
|
+
compute functions such as `compute_apa`, `compute_local_decay`, and
|
|
143
|
+
`compute_ep_and_background`, then displaying or saving returned Matplotlib
|
|
144
|
+
figures as needed. Long-running CLI and API calls support optional progress
|
|
145
|
+
bars and lightweight profiling. See the [API guide](docs/api.md) for examples.
|
|
146
|
+
|
|
147
|
+
## Documentation
|
|
148
|
+
|
|
149
|
+
Detailed usage notes live under `docs/`:
|
|
150
|
+
|
|
151
|
+
- [Docs index](docs/README.md): human-facing guides and documentation
|
|
152
|
+
conventions.
|
|
153
|
+
- [CLI reference](docs/cli.md): command groups, common options, examples,
|
|
154
|
+
outputs, and run-wrapper manifests.
|
|
155
|
+
- [Micro-C preprocessing](docs/micro-c-preprocessing.md): distiller-nf boundary,
|
|
156
|
+
pairs format expectations, filtering, QC, and cache building.
|
|
157
|
+
- [API](docs/api.md): provisional in-memory APIs for notebooks, interactive analyses,
|
|
158
|
+
and custom scripts.
|
|
159
|
+
- [Reproducing reference plots](docs/reproducing-reference-plots.md): end-to-end
|
|
160
|
+
commands for the reference local-decay, APA, and EP/background plots.
|
|
161
|
+
- [Testing and publishing](docs/testing-and-publishing.md): CI, local checks,
|
|
162
|
+
and PyPI release workflow for the `ep-touche` distribution.
|
|
163
|
+
|
|
164
|
+
Implementation plans, experiment logs, and agent-facing notes belong in
|
|
165
|
+
`notes/`.
|
|
166
|
+
|
|
167
|
+
## Development
|
|
168
|
+
|
|
169
|
+
Development is managed with `uv`.
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
git clone https://github.com/adamyhe/touche.git
|
|
173
|
+
cd touche/
|
|
174
|
+
uv sync --dev
|
|
175
|
+
uv run touche --help
|
|
176
|
+
uv run pytest
|
|
177
|
+
```
|