Thank you so much. Your code works great.
Dear All,
I have a VCF file and I want to change part of the header:
##contig=<ID=1,length=195471971>
##contig=<ID=10,length=130694993>
##contig=<ID=11,length=122082543>
##contig=<ID=12,length=120129022>
##contig=<ID=13,length=120421639>
##contig=<ID=14,length=124902244>
##contig=<ID=15,length=104043685>
##contig=<ID=16,length=98207768>
##contig=<ID=17,length=94987271>
##contig=<ID=18,length=90702639>
##contig=<ID=19,length=61431566>
##contig=<ID=2,length=182113224>
##contig=<ID=3,length=160039680>
##contig=<ID=4,length=156508116>
##contig=<ID=5,length=151834684>
##contig=<ID=6,length=149736546>
##contig=<ID=7,length=145441459>
##contig=<ID=8,length=129401213>
##contig=<ID=9,length=124595110>
##contig=<ID=MT,length=16299>
##contig=<ID=X,length=171031299>
##contig=<ID=Y,length=91744698>
to
##contig=<ID=chr1,length=195471971>
##contig=<ID=chr10,length=130694993>
##contig=<ID=chr11,length=122082543>
##contig=<ID=chr12,length=120129022>
##contig=<ID=chr13,length=120421639>
##contig=<ID=chr14,length=124902244>
##contig=<ID=chr15,length=104043685>
##contig=<ID=chr16,length=98207768>
##contig=<ID=chr17,length=94987271>
##contig=<ID=chr18,length=90702639>
##contig=<ID=chr19,length=61431566>
##contig=<ID=chr2,length=182113224>
##contig=<ID=chr3,length=160039680>
##contig=<ID=chr4,length=156508116>
##contig=<ID=chr5,length=151834684>
##contig=<ID=chr6,length=149736546>
##contig=<ID=chr7,length=145441459>
##contig=<ID=chr8,length=129401213>
##contig=<ID=chr9,length=124595110>
##contig=<ID=chrM,length=16299>
##contig=<ID=chrX,length=171031299>
##contig=<ID=chrY,length=91744698>
and also change the field of #CHROM correspondingly.
I am wondering if there are any tools or easy ways to achieve this. Thank you in advance.
4 answers
I have not tested/validated the commands, but think you need two steps: 1) change the header(s)
bcftools view --header-only $INPUT_FILE | sed 's/##contig=<ID=/##contig=<ID=chr/' | sed 's/##contig=<ID=chrMT/##contig=<ID=chrM/' > $OUTPUT_FILE
and 2) change the data field (as questioned by @charlesberkn).
bcftools view --no-header $INPUT_FILE | sed 's/^/chr/' | sed 's/^chrMT/chrM/' >> $OUTPUT_FILE
PS: Thanks to Pierre for pointing toward the special handling of chrM(T)!
If the code works, please up-vote and set the answer as "accepted" to let other people with the same problem know this is working solution - thanks
You can use a command line tool like `sed` to find/replace, or you can use something like PyVCF if you know python.
Example sed command: sed -i 'backup' 's/ID\=/ID\=chr/g' file.vcf
Do you also want to change the first column in all the rows too?
Little python script would do it:
import os
import re
for file_name in os.listdir("."): #Open directory (working)
if file_name.endswith(".vcf"): #Read in all fasta file names
file_list = re.split(r"[.]", file_name)
file_name_without_vcf =(file_list[0])
vcf_content =open(file_name)
output = open(file_name_without_vcf + "_edit.vcf", "w")
for line in vcf_content:
if line.startswith("##contig"):
output.write(line.replace("ID=", "ID=chr"))
else:
output.write(line)
Here's an updated answer for people with the same query: Create a tab-delimited file mapping old to new contig names and then use bcftools annotate --rename-chrs.
bcftools view -H file.vcf | grep "^##contig" | sed -Ee 's/##contig=<ID=([^,]+),.*/\1/' | sed 's/^MT$/M/' > old_contigs.txt
paste old_contigs.txt <(sed -Ee 's/^/chr/' old_contigs.txt) > contig_map.tsv
bcftools annotate --rename-chrs contig_map.tsv file.vcf > output.vcf
rm old_contigs.txt contig_map.tsv
Log in to answer this question.