8.4 KiB
Bttoxin_Shoter v1 workflow and formulas
This document describes how Bttoxin_Shoter converts BtToxin_Digger outputs into predicted target insect orders and strain-level scores, and the rationale behind each step.
Inputs
- Digger outputs (from tests/output/Results/Toxins):
- All_Toxins.txt (tab-separated summary across strains)
- Specificity data (from BPPRC, placed in Data/):
- Data/toxicity-data.csv (positive activity records)
- Optional reference FASTA:
- Data/holotype_fasta_sequences.txt (holotype representatives; not required for v1 scoring)
Outputs (default under output_dir / shotter_outputs)
- toxin_support.tsv Per-hit contributions and metadata.
- strain_target_scores.tsv Per-strain target-order scores (0–1) across all known orders.
- strain_scores.json Same as TSV in JSON form.
- If CSV contains target_species:
- strain_target_species_scores.tsv
- strain_species_scores.json
CLI (scoring)
python scripts/bttoxin_shoter.py \
--toxicity_csv Data/toxicity-data.csv \
--all_toxins tests/output/Results/Toxins/All_Toxins.txt \
--output_dir shotter_outputs \
--min_identity 0.50 \
--min_coverage 0.60 \
--disallow_unknown_families \
--require_index_hit
Flags explained
- --min_identity, --min_coverage: filter weak hits (0–1)
- --allow_unknown_families/--disallow_unknown_families: keep or drop unparseable families
- --require_index_hit: keep only hits that can back-off to name/subfamily/family in the specificity index
High-level pipeline
flowchart TD
A["Genome .fna"]
subgraph B["BtToxin_Digger (Docker)"]
direction TB
B0["ORF/CDS prediction"]
B1t["Translate CDS to proteins"]
B2t["Toxin identification (BLAST/HMM)"]
B0 --> B1t --> B2t
end
A --> B0
B2t --> AT[All_Toxins.txt]
B2t --> LG[*.list / *.gbk]
C[BPPRC specificity CSV] --> D[Build specificity index]
AT --> E[Per-hit parsing]
D --> F[Per-hit scoring]
E --> F
F --> G[Per-strain combination]
G --> H[Outputs: toxin_support.tsv, strain_target_scores.tsv, strain_scores.json]
ASCII fallback:
-
Genome -> Digger: ORF/CDS prediction -> Translate to proteins -> Toxin identification (BLAST/HMM) -> All_Toxins.txt, *.list, *.gbk
-
toxicity-data.csv -> Build index
-
All_Toxins -> Per-hit parsing -> Per-hit scoring (with index) -> Strain-level combine -> Outputs
-
是否把基因序列转成“识别好的”蛋白序列 是的。在本项目的用法中我们用核酸输入运行 BtToxin_Digger(见 scripts/test_bttoxin_digger.py 的
sequence_type="nucl")。Digger 会在容器里做 ORF/CDS 预测,把核酸翻译成蛋白,再用 BLAST/HMM 对蛋白进行毒素识别。识别结果被汇总到All_Toxins.txt,其中包含每条蛋白与某个毒素条目的匹配信息(如Identity、Aln_length、Hit_length、HMM等;参见 scripts/bttoxin_shoter.py 的解析逻辑)。 -
*.list*.gbk的用途*.list:每个菌株(样本)的毒素命中列表,便于快速查看此菌株命中了哪些毒素名称/家族、对应的蛋白 ID/坐标等,常用于人工复核与回溯。*.gbk:带注释的 GenBank 文件,包含序列和注释特征(CDS、蛋白翻译、坐标等),便于在基因组浏览器或其他注释/二次分析工具中查看与下游使用。
-
后续靶点分析/打分是否需要
*.list*.gbk不需要。本仓库的打分脚本scripts/bttoxin_shoter.py只读取All_Toxins.txt(见 docs/shotter_workflow.md 的流程图,只有All_Toxins.txt被接入打分环节)。*.list和*.gbk是 Digger 的配套产物,适合做人工检查、回溯坐标与提取序列,但不作为打分脚本的输入。
Name and family parsing
- Extract family/subfamily keys from names (e.g., Cry1Ac1 -> family Cry1, subfamily Cry1A). Names like
5618-Cry1Iaare supported. - Hit IDs such as
Xxx-otherare normalized by removing the-othersuffix.
Specificity index from CSV (positive-only)
- Keep only rows where
activity == Yes. - Compute a potency weight per row:
- If
lc50present: normalize within unit buckets by inverted percentile:potency = 1 - rank_percentile(lc50). - If
percentage_mortalitypresent: map to coarse weights- ≥80% or phrases like "greater than 80%" -> 0.90
- 50–80% (or 60–80%, 60–100%) -> 0.65
- 0–60%, 0–50%, 25%, or vague "some"/"stunting" -> 0.25
- Otherwise default positive evidence -> 0.55
- If
- Aggregate to distributions P(order | name), P(order | subfamily), P(order | family) by summing potencies per
target_orderthen normalizing to 1. - Unit harmonization rationale: diet incorporation studies often report
ppmroughly equivalent toµg/g. We placeppm, µg/g, ug/g, μg/ginto oneug_per_gbucket for within-bucket normalization. Other units stay in their own buckets.
Partner protein logic
- Some families require partners for activity (e.g., Vip1/Vip2, Vpa/Vpb). A hit from such a family is down-weighted by 0.2 unless a partner family is also present in the same strain with a non-trivial similarity weight (≥0.3).
- This is applied at family prefix level and is independent of CSV
partnerproteintext.
Similarity weight (per hit)
Let id = identity (0–1), cov = alignment coverage, hmm = HMM flag.
- Base identity component:
- if
id ≥ 0.78andcov ≥ 0.80:base = 1.0 - elif
0.45 ≤ id < 0.78:base = (id - 0.45) / (0.78 - 0.45) - else:
base = 0.0
- if
- Combine with coverage and HMM bonus:
w_hit = min(1, base * cov + (0.1 if hmm else 0))
- Rationale: 0.45 and 0.78 are the conventional Bt nomenclature thresholds for family and subfamily; coverage ≥0.8 protects against partial hits; HMM bonus rewards domain-level confirmation without overpowering identity/coverage.
Per-hit order contributions and species (optional)
- For each hit, get a distribution
P(order | name/family)from the index, with back-off: name -> subfamily -> family. If still unknown, contributions are sent to theotherbucket. - Hit contribution to an order:
c(order) = w_hit × P(order | name/family). - If
target_speciesis present in the CSV, compute in parallel on species:c(species) = w_hit × P(species | ·)
Strain-level combination
- Across all hits for a strain, we use noisy-OR:
Score(strain, order) = 1 - Π_hits (1 - c(order))
- This stays in [0,1], increases with multiple concordant hits, and avoids double-counting.
Special buckets and Top columns
other: used when a hit has a parsable family (e.g., Cry1, Vip3) but no mapping evidence is found in the specificity index at any level (name/subfamily/family).unknown: used when the hit's family cannot be parsed from its name, so no meaningful back-off is possible.- TopOrder/TopScore (per hit and per strain): the max contributing order and its score. Strain-level tops prefer canonical orders over
other/unknownwhen present.
Files and dataclasses
- Dataclasses:
ToxinHit(strain, protein_id, hit_id, identity, aln_length, hit_length, coverage, hmm, family, name_key, partner_fulfilled, weight, order_contribs, top_order, top_score)- Methods:
to_tsv_row,save_list_tsv(...)
- Methods:
StrainScores(strain, order_scores, top_order, top_score)- Methods:
to_tsv_row,save_list_tsv(...),save_list_json(...)
- Methods:
StrainSpeciesScores(strain, species_scores, top_species, top_species_score)(if species dimension is present)- Methods:
to_tsv_row,save_list_tsv(...),save_list_json(...)
- Methods:
Plotting and report
Use scripts/plot_shotter.py to render heatmaps and write a Markdown report.
python scripts/plot_shotter.py \
--strain_scores shotter_outputs/strain_target_scores.tsv \
--toxin_support shotter_outputs/toxin_support.tsv \
--species_scores shotter_outputs/strain_target_species_scores.tsv \
--out_dir shotter_outputs \
--merge_unresolved \
--per_hit_strain <Strain> \
--report_mode paper \
--lang en
Options
- --merge_unresolved: merge
other+unknownintounresolvedfor visualization only (computation unchanged) - --per_hit_strain: pick one strain to show per-hit × order heatmap (interpretation aid)
- --report_mode: paper or summary; --lang: zh/en
Notes and limitations
- Only positive activity records are used from the specificity CSV; negative records are ignored per design.
- The partner list is heuristic; extend as needed.
- If no CSV evidence exists for a family, hits are routed to
otherand do not inflate canonical orders. - v2 can add HMM family models and phylogenetic placement for improved back-off.