replace TSV with CSV for variant outputs

This commit is contained in:
2026-09-06 18:47:00 +03:00
parent 0f40945d58
commit 4e19fbdb8a
2 changed files with 14 additions and 12 deletions
+3 -2
View File
@@ -72,14 +72,15 @@ python3 -m venv --system-site-packages .venv
| `strand_damage_profile_3prime.csv` | то же по 3′-концу |
| `end_enrichment.csv` | C>T/G>A % в первых/последних 1,3,5,10,20 основаниях, по R1/R2 |
| `candidate_CtoT.bed`, `candidate_GtoA.bed` | позиции для IGV; имя = `ref>alt;depth;alt;VAF` |
| `candidate_variants.tsv` | контекст каждой позиции: VAF, средняя позиция в read, strand bias, BQ, раскладка R1/R2 |
| `candidate_variants.csv` | контекст каждой позиции: VAF, средняя позиция в read, strand bias, BQ, раскладка R1/R2 |
| `clean_variants.csv` / `ffpe_suspect_variants.csv` | разделение на чистые и подозрительные |
| `CtoT_R1.png``GtoA_R2_3prime.png` | графики частоты по позиции в read (5′ и 3) |
### Как читать результат
- **Классическая FFPE-сигнатура**: пик `C>T` у 5-конца R1 и `G>A` у 3′-конца R2 — две цепи одного и того же дезаминирования цитозина. Проверяйте профили R1/R2 и по strand.
- Если C>T/G>A повышены равномерно по всей длине read (без пика у концов) — это не классическое end-associated повреждение, а другой артефакт/ошибки.
- **Отличить настоящий вариант от дезаминирования** (`candidate_variants.tsv`): настоящий вариант имеет ожидаемый VAF, распределён по read (средняя позиция ~ середина), встречается на обеих цепях (strand bias не значим) и не привязан к концам. Дезаминирование концентрируется у концов read и на одной цепи.
- **Отличить настоящий вариант от дезаминирования** (`candidate_variants.csv`): настоящий вариант имеет ожидаемый VAF, распределён по read (средняя позиция ~ середина), встречается на обеих цепях (strand bias не значим) и не привязан к концам. Дезаминирование концентрируется у концов read и на одной цепи.
## 2. Классификация относительно контролей
+11 -10
View File
@@ -33,7 +33,8 @@ Outputs (in --outdir):
strand_damage_profile_3prime.csv (3' profile)
end_enrichment.csv
candidate_CtoT.bed / candidate_GtoA.bed (IGV tracks)
candidate_variants.tsv (per-position context)
candidate_variants.csv (per-position context)
clean_variants.csv / ffpe_suspect_variants.csv
CtoT_R1.png CtoT_R2.png GtoA_R1.png GtoA_R2.png (5' plots)
CtoT_R1_3prime.png ... GtoA_R2_3prime.png (3' plots)
"""
@@ -616,15 +617,15 @@ def write_beds_and_variants(d, args):
df["is_ffpe_suspect"] = [x[0] for x in flags]
df["ffpe_reason"] = [x[1] for x in flags]
df.to_csv(os.path.join(args.outdir, "candidate_variants.tsv"),
index=False, sep="\t")
df.to_csv(os.path.join(args.outdir, "candidate_variants.csv"),
index=False)
clean = df[~df["is_ffpe_suspect"]]
damaged = df[df["is_ffpe_suspect"]]
clean.to_csv(os.path.join(args.outdir, "clean_variants.tsv"),
index=False, sep="\t")
damaged.to_csv(os.path.join(args.outdir, "ffpe_suspect_variants.tsv"),
index=False, sep="\t")
clean.to_csv(os.path.join(args.outdir, "clean_variants.csv"),
index=False)
damaged.to_csv(os.path.join(args.outdir, "ffpe_suspect_variants.csv"),
index=False)
for name, subset, fname in [
("clean", clean, "candidate_CtoT_clean.bed"),
@@ -647,8 +648,8 @@ def write_beds_and_variants(d, args):
f.writelines(clean_ga)
return df
else:
open(os.path.join(args.outdir, "clean_variants.tsv"), "w").close()
open(os.path.join(args.outdir, "ffpe_suspect_variants.tsv"), "w").close()
open(os.path.join(args.outdir, "clean_variants.csv"), "w").close()
open(os.path.join(args.outdir, "ffpe_suspect_variants.csv"), "w").close()
return pd.DataFrame()
@@ -886,7 +887,7 @@ def main():
n_flag = int(flagged_df["is_ffpe_suspect"].sum())
n_clean = len(flagged_df) - n_flag
print(f"variants flagged FFPE : {n_flag} / {len(flagged_df)} "
f"-> ffpe_suspect_variants.tsv / clean_variants.tsv")
f"-> ffpe_suspect_variants.csv / clean_variants.csv")
if __name__ == "__main__":