-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
Prot2Exon/
├── src/ C++ binary
│ ├── main.cpp CLI entry point
│ ├── gtf_parser.{cpp,hpp} GTF → in-memory index (+ index serialise/deserialise)
│ ├── domain_mapper.{cpp,hpp} per-query mapping; emits per-feature rows
│ ├── output_writer.{cpp,hpp} TSV/BED writers + StreamingWriter
│ └── utils.{cpp,hpp} string utilities, attribute helpers
├── include/common.hpp shared types (Result, Segment, ...)
├── python/prot2exon/ Python wrapper
│ ├── _client.py Mapper (subprocess wrapper)
│ ├── _result.py MappingResult dataclass
│ ├── plot.py matplotlib + plotly renderer
│ ├── _interactive_html.py standalone interactive HTML viewer (+ Jupyter wrapper)
│ └── fetch.py `prot2exon fetch` subcommand
├── scripts/ helpers: prepare_from_interpro/uniprot/pfam, append_custom_proteins
├── notebooks/ walkthrough + paper figure notebooks
├── tests/run_tests.py end-to-end test suite (~109 assertions)
├── benchmarks/ 1M-query + scaling harness
├── examples/ small fixtures (tp53_isoforms.tsv, ...)
└── wiki/ these pages
GTF ──▶ gtf_parser ──▶ index (.idx)
│
BED queries ──▶ domain_mapper ──▶ vector<Result>
│
output_writer ──▶ TSVs + BEDs + run_metadata.json
- Streams the GTF line-by-line; no full DOM in memory.
- Resolves
gene_name(GENCODE/Ensembl) with a fallback togene(NCBI RefSeq). - Word-boundary attribute matching to avoid false-positive tag detection (e.g.
locus_tag "..."no longer trips atagsubstring check). - Extracts MANE Select, Ensembl_canonical, and CCDS tags when present.
- Serialises the parsed index to a single binary file (~25× smaller than the source GTF).
- Loads the index from disk (mmap-friendly, ~1.5 s for human).
- Per query, looks up the transcript, walks its CDS+intron+UTR features, and emits one
Resultper feature plus the global summary row. - Annotates each row with whether it overlaps the domain (
coding_overlap,inside_domain_genomic_span,outside,NA). -
CDS splitting: when a domain partially covers a CDS exon, the exon is emitted as two rows that share
feature_id/exon_numberbut differ infeature_part. This keeps the original CDS number stable while letting the plotter colour the two pieces differently. - Supports streaming via
process_domains_streaming(batch_size, callback)so the writer can drain results in chunks (see--batch-size).
- Per-result append helpers (
append_summary_row,append_isoform_rows, …) feed both the one-shot path and the streaming path. -
StreamingWriterflushes each batch immediately and frees its memory before the next batch starts. -
write_all()wraps the per-file write loops in#pragma omp parallel sectionsso the seven outputs are written concurrently when--threads > 1.
-
Mappershells out to the binary per call. It writes the BED to a temp dir, invokes the binary with the requested--outputflags, and reads the TSVs back as DataFrames. -
MappingResultowns the temp dir while alive — when the result goes out of scope, the dir is cleaned up (unless you callresult.write(...)to persist). - The plotter (
plot.py) takes either aMappingResult, a DataFrame, or a path; it deriveslist[Segment]perinput_idand dispatches to matplotlib, plotly, or_interactive_html.render_interactive_html.
All three plot paths consume the same Segment list (from _segments_from_dataframe or load_isoform_tsv). The renderer is chosen by which output flag you pass:
-
--out→ matplotlib (_draw_genomic,_draw_compact_genomic, or_draw_spliced) -
--html→ plotly (render_htmlwithBar+Scattergl+ rangeslider) -
--html-interactive→render_interactive_html(vanilla JS template in_interactive_html.py)
The JS template renders a shared-axis view (compact-mode collapses introns to 80 virtual bp) with a vCRE-style minimap and box-zoom on the main plot. Both file output (render_interactive_html) and Jupyter embedding (render_interactive_jupyter) share the same _render_to_string helper.
tests/run_tests.py is a single-file end-to-end suite that:
- Generates synthetic GTFs (
scripts/make_synthetic_gtf.py). - Builds an index.
- Runs the binary against handcrafted BED queries.
- Asserts on every output (~109 assertions covering coordinate conventions, CDS splitting, MANE Select, tag extraction, RefSeq dialect, custom-protein injection, plotly/interactive/jupyter renderers,
--batch-sizeequivalence, …).
Run with:
python3 tests/run_tests.pyExpect 109 passed, 2 failed — the two failures require matplotlib + pandas in the system python and aren't regressions.
1 - How to install
2 - Building an index
(fastCDS index, fastCDS fetch)
3 - Mapping
(fastCDS map)
4 - Plotting
(fastCDS plot)
6 - Performance and benchmarking
7 - Reference