更新 .gitignore,添加 06.gene_trees 目录;重构 macse.sh 脚本,移除 fs_lr 参数;删除多个不再使用的脚本;添加 check_frameshift.py 和 get_og_seqs.py 脚本以处理阅读框移位和提取单拷贝OG序列;更新 pixi.toml 和 pixi.lock 文件以添加 paml 依赖。

This commit is contained in:
2025-12-20 01:57:25 +08:00
parent e8ba2ed962
commit dba4833905
15 changed files with 433 additions and 117 deletions
+128
View File
@@ -0,0 +1,128 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Check and process frameshift in alignment files.
"""
import shutil
import pandas as pd
from pathlib import Path
from Bio import SeqIO
from Bio.SeqRecord import SeqRecord
from Bio.Seq import Seq
import sys
import argparse
def parse_frameshift_list(fs_list: Path) -> pd.DataFrame:
"""
Parse a frameshift list file into a pandas DataFrame.
Args:
fs_list (Path): Path to the frameshift list file.
Returns:
pd.DataFrame: DataFrame containing the frameshift information.
"""
try:
df = pd.read_csv(fs_list, sep=",", header=0)
except Exception as e:
print(f"Error reading frameshift list file {fs_list}: {e}")
sys.exit(1)
return df
def get_alignment_files(aln_dir: Path, ext: str) -> list[Path]:
"""
Get a list of alignment files in a directory with a specific extension.
Args:
aln_dir (Path): Path to the directory containing alignment files.
ext (str): Extension of the alignment files.
Returns:
list[Path]: List of Paths to the alignment files.
"""
try:
aln_files = list(aln_dir.glob(f"*{ext}"))
except Exception as e:
print(f"Error accessing alignment files in {aln_dir}: {e}")
sys.exit(1)
return aln_files
def main(alignment_dir: str, ext: str, frameshift_list: str, outdir: str):
aln_dir = Path(alignment_dir)
fs_list_path = Path(frameshift_list)
out_dir = Path(outdir)
out_dir.mkdir(parents=True, exist_ok=True)
fs_df = parse_frameshift_list(fs_list_path)
aln_files = get_alignment_files(aln_dir, ext)
good_aln_count = 0
keep_fs_count = 0
discard_count = 0
for file in aln_files:
if str(file) not in fs_df["alignment_file"].values.tolist():
try:
shutil.copy(file, out_dir / file.name)
good_aln_count += 1
continue
except Exception as e:
print(f"Error copying file {file} to {out_dir}: {e}")
sys.exit(1)
if (
fs_df.loc[
fs_df["alignment_file"] == str(file), "possible_attributions"
].values[0]
== "Framshift only in Ziziphus jujuba or Elaeagnus pungens"
):
try:
records = []
for record in SeqIO.parse(file, "fasta"):
seq = str(record.seq).replace("!", "-")
id = record.id
records.append(SeqRecord(seq=Seq(seq), id=id, description=""))
print(
f"Keep the alignment file with frameshift: {file}. Due to frameshift only in outgroup."
)
keep_fs_count += 1
SeqIO.write(records, out_dir / file.name, "fasta")
except Exception as e:
print(f"Error processing file {file}: {e}")
sys.exit(1)
else:
discard_count += 1
print("Frameshift processing completed successfully.")
print(f"Number of good alignments copied: {good_aln_count}")
print(f"Number of alignments with frameshift kept: {keep_fs_count}")
print(f"Number of alignments with frameshift discarded: {discard_count}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Check and process frameshift in alignment files."
)
parser.add_argument(
"-a",
"--alignment_dir",
required=True,
help="Directory containing alignment files",
)
parser.add_argument(
"-e", "--ext", default=".nal", help="Extension of alignment files"
)
parser.add_argument(
"-f",
"--frameshift_list",
required=True,
help="CSV file listing frameshift information",
)
parser.add_argument(
"-o", "--outdir", required=True, help="Output directory for processed files"
)
args = parser.parse_args()
main(args.alignment_dir, args.ext, args.frameshift_list, args.outdir)