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′-концу | | `strand_damage_profile_3prime.csv` | то же по 3′-концу |
| `end_enrichment.csv` | C>T/G>A % в первых/последних 1,3,5,10,20 основаниях, по R1/R2 | | `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_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) | | `CtoT_R1.png``GtoA_R2_3prime.png` | графики частоты по позиции в read (5′ и 3) |
### Как читать результат ### Как читать результат
- **Классическая FFPE-сигнатура**: пик `C>T` у 5-конца R1 и `G>A` у 3′-конца R2 — две цепи одного и того же дезаминирования цитозина. Проверяйте профили R1/R2 и по strand. - **Классическая FFPE-сигнатура**: пик `C>T` у 5-конца R1 и `G>A` у 3′-конца R2 — две цепи одного и того же дезаминирования цитозина. Проверяйте профили R1/R2 и по strand.
- Если C>T/G>A повышены равномерно по всей длине read (без пика у концов) — это не классическое end-associated повреждение, а другой артефакт/ошибки. - Если C>T/G>A повышены равномерно по всей длине read (без пика у концов) — это не классическое end-associated повреждение, а другой артефакт/ошибки.
- **Отличить настоящий вариант от дезаминирования** (`candidate_variants.tsv`): настоящий вариант имеет ожидаемый VAF, распределён по read (средняя позиция ~ середина), встречается на обеих цепях (strand bias не значим) и не привязан к концам. Дезаминирование концентрируется у концов read и на одной цепи. - **Отличить настоящий вариант от дезаминирования** (`candidate_variants.csv`): настоящий вариант имеет ожидаемый VAF, распределён по read (средняя позиция ~ середина), встречается на обеих цепях (strand bias не значим) и не привязан к концам. Дезаминирование концентрируется у концов read и на одной цепи.
## 2. Классификация относительно контролей ## 2. Классификация относительно контролей
+11 -10
View File
@@ -33,7 +33,8 @@ Outputs (in --outdir):
strand_damage_profile_3prime.csv (3' profile) strand_damage_profile_3prime.csv (3' profile)
end_enrichment.csv end_enrichment.csv
candidate_CtoT.bed / candidate_GtoA.bed (IGV tracks) 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.png CtoT_R2.png GtoA_R1.png GtoA_R2.png (5' plots)
CtoT_R1_3prime.png ... GtoA_R2_3prime.png (3' 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["is_ffpe_suspect"] = [x[0] for x in flags]
df["ffpe_reason"] = [x[1] for x in flags] df["ffpe_reason"] = [x[1] for x in flags]
df.to_csv(os.path.join(args.outdir, "candidate_variants.tsv"), df.to_csv(os.path.join(args.outdir, "candidate_variants.csv"),
index=False, sep="\t") index=False)
clean = df[~df["is_ffpe_suspect"]] clean = df[~df["is_ffpe_suspect"]]
damaged = df[df["is_ffpe_suspect"]] damaged = df[df["is_ffpe_suspect"]]
clean.to_csv(os.path.join(args.outdir, "clean_variants.tsv"), clean.to_csv(os.path.join(args.outdir, "clean_variants.csv"),
index=False, sep="\t") index=False)
damaged.to_csv(os.path.join(args.outdir, "ffpe_suspect_variants.tsv"), damaged.to_csv(os.path.join(args.outdir, "ffpe_suspect_variants.csv"),
index=False, sep="\t") index=False)
for name, subset, fname in [ for name, subset, fname in [
("clean", clean, "candidate_CtoT_clean.bed"), ("clean", clean, "candidate_CtoT_clean.bed"),
@@ -647,8 +648,8 @@ def write_beds_and_variants(d, args):
f.writelines(clean_ga) f.writelines(clean_ga)
return df return df
else: else:
open(os.path.join(args.outdir, "clean_variants.tsv"), "w").close() open(os.path.join(args.outdir, "clean_variants.csv"), "w").close()
open(os.path.join(args.outdir, "ffpe_suspect_variants.tsv"), "w").close() open(os.path.join(args.outdir, "ffpe_suspect_variants.csv"), "w").close()
return pd.DataFrame() return pd.DataFrame()
@@ -886,7 +887,7 @@ def main():
n_flag = int(flagged_df["is_ffpe_suspect"].sum()) n_flag = int(flagged_df["is_ffpe_suspect"].sum())
n_clean = len(flagged_df) - n_flag n_clean = len(flagged_df) - n_flag
print(f"variants flagged FFPE : {n_flag} / {len(flagged_df)} " 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__": if __name__ == "__main__":