Files
PlantAI-dev/scripts/run_finalize_members.py
2026-08-03 18:42:47 +08:00

129 lines
4.9 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
import argparse
from pathlib import Path
import sys
def _prompt_str(msg: str, default: str) -> str:
s = input(f"{msg} [{default}]: ").strip()
return default if s == "" else s
def _prompt_float(msg: str, default: float, min_v: float | None = None, max_v: float | None = None) -> float:
while True:
s = input(f"{msg} [{default}]: ").strip()
if s == "":
return default
try:
v = float(s)
if min_v is not None and v < min_v:
print(f" 值不能小于 {min_v},请重输。")
continue
if max_v is not None and v > max_v:
print(f" 值不能大于 {max_v},请重输。")
continue
return v
except ValueError:
print(" 请输入数字,或直接回车使用默认值。")
def _prompt_int(msg: str, default: int, min_v: int | None = None) -> int:
while True:
s = input(f"{msg} [{default}]: ").strip()
if s == "":
return default
try:
v = int(s)
if min_v is not None and v < min_v:
print(f" 值不能小于 {min_v},请重输。")
continue
return v
except ValueError:
print(" 请输入整数,或直接回车使用默认值。")
def _prompt_bool(msg: str, default: bool) -> bool:
d = "Y/n" if default else "y/N"
while True:
s = input(f"{msg} ({d}): ").strip().lower()
if s == "":
return default
if s in ("y", "yes"):
return True
if s in ("n", "no"):
return False
print(" 请输入 y 或 n,或直接回车使用默认值。")
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--hmm-id", required=True, help="hmm pipeline 输出的 *.domtblout.filter.id")
ap.add_argument("--blast-id", required=True, help="blast pipeline 输出的 *.blastout.filter.id")
ap.add_argument("--pep", required=True, help="目标物种全蛋白 fasta(Ft.pep.fasta)")
ap.add_argument("--pfam", required=True, help="Pfam-A.hmm 路径")
ap.add_argument("--out", required=True, help="输出目录")
ap.add_argument("--prefix", required=True, help="前缀,如 Ft.SPL")
ap.add_argument("--required", default="PF03110", help="必需 Pfam(逗号分隔),默认 PF03110")
ap.add_argument("--cpu", type=int, default=8)
ap.add_argument("--dom-i-evalue", type=float, default=1e-5)
ap.add_argument("--hmm-cov", type=float, default=0.5)
ap.add_argument("--cut-ga", action="store_true", help="hmmscan 使用 --cut_ga(Pfam GA 阈值)")
ap.add_argument("--interactive", action="store_true", help="交互式设置阈值(回车=默认值)")
args = ap.parse_args()
if args.interactive:
print("\n[Interactive] 可直接回车使用默认阈值:")
args.required = _prompt_str("必需Pfam(逗号分隔)", args.required)
args.dom_i_evalue = _prompt_float("dom_i_evalue 最大值", args.dom_i_evalue, min_v=0.0)
args.hmm_cov = _prompt_float("required域 HMM覆盖度下限(0-1)", args.hmm_cov, min_v=0.0, max_v=1.0)
args.cpu = _prompt_int("hmmscan CPU线程数", args.cpu, min_v=1)
args.cut_ga = _prompt_bool("是否启用 hmmscan --cut_ga", args.cut_ga)
print()
# 让脚本可以从项目根目录运行
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from pipelines.merge_candidates import merge_hmm_blast_ids
from pipelines.fasta_utils import read_id_set, extract_fasta_by_ids
from pipelines.domain_scan_pipeline import run_hmmscan_pfam_pipeline
out_dir = Path(args.out).resolve()
out_dir.mkdir(parents=True, exist_ok=True)
# 1) merge candidates
m = merge_hmm_blast_ids(args.hmm_id, args.blast_id, str(out_dir), args.prefix)
# 2) extract candidates pep
ids = read_id_set(m.merged_id)
candidates_fa = (out_dir / f"{args.prefix}.candidates.pep.fa").resolve()
n = extract_fasta_by_ids(args.pep, ids, str(candidates_fa))
# 3) pfam hmmscan + required domain filter
required = [x.strip() for x in args.required.split(",") if x.strip()]
d = run_hmmscan_pfam_pipeline(
pfam_hmm=args.pfam,
query_fasta=str(candidates_fa),
out_dir=str(out_dir),
prefix=args.prefix,
required_pfams=required,
dom_i_evalue_max=args.dom_i_evalue,
hmm_coverage_min=args.hmm_cov,
cpu=args.cpu,
use_cut_ga=args.cut_ga,
)
print("=== DONE ===")
print(f"merged candidates: {m.merged_count} (hmm={m.hmm_count}, blast={m.blast_count}, both={m.both_count})")
print(f"candidates pep written: {n} -> {candidates_fa}")
print(f"domains tsv: {d.domains_tsv}")
print(f"final id: {d.final_id}")
print(f"final tsv: {d.final_tsv}")
print(f"final_count: {d.final_count}")
if __name__ == "__main__":
main()