# Parnassius project ###### tags: `RADSeq` `STACKS` --- author: Emma Fetterly --- **Resources:** 1. Link to STACKS website: https://catchenlab.life.illinois.edu/stacks/ 2. Bioinformatics guide by Eric C. Anderson https://eriqande.github.io/eca-bioinf-handbook/shell-programming.html 3. Speciation & Population Genomics: a how-to-guide https://speciationgenomics.github.io/mapping_reference/ 4. Surm script how-to from NU https://services.northwestern.edu/TDClient/30/Portal/KB/ArticleDet?ID=1964 5. Globus - file management https://www.globus.org/ # vcftools introduction Dylan's example code for filtering the popualtions.snps.vcf file: ``` vcftools --vcf --input.vcf --min-meanDP 5 --minDP 5 --max-meanDP 50 --maxDP 50 --mac 3 --remove-indels --max-alleles 2 --min-alleles 2 --max-missing 0.50 --recode ---out renamed.ouput.vcf ``` ### VCF Parameters: **Depth:** ``` --min-meanDP <float> --max-meanDP <float> ``` Includes only sites with mean depth values (over all included individuals) greater than or equal to the "--min-meanDP" value and less than or equal to the "--max-meanDP" value. One of these options may be used without the other. These options require that the "DP" FORMAT tag is included for each site. **Hardy-Weinberg Equlibrium:** ``` --hwe <float> ``` Assesses sites for Hardy-Weinberg Equilibrium using an exact test, as defined by Wigginton, Cutler and Abecasis (2005). Sites with a p-value below the threshold defined by this option are taken to be out of HWE, and therefore excluded. **Missing data:** ``` --max-missing <float> ``` Exclude sites on the basis of the proportion of missing data (defined to be between 0 and 1, where 0 allows sites that are completely missing and 1 indicates no missing data allowed). ``` --max-missing-count <integer> ``` Exclude sites with more than this number of missing genotypes over all individuals. **Phased:** ``` --phased ``` Excludes all sites that contain unphased genotypes. **MISCELLANEOUS FILTERING** ``` --minQ <float> ``` Includes only sites with Quality value above this threshold. # VCF filtering: Preliminary analysis following the workflow from https://speciationgenomics.github.io/filtering_vcfs/ to determine stats from this dataset 1. making a new VCF directory in the PASM direrectory and move the minimal filteritng and 80 filtered fiels into it ``` mkdir vcf ``` 2. make a directory for vcf tools output and make shortcuts for the vcf file and output unzip the VCF files ``` gunzip r80_8_filtered.vcf.gz ``` ``` mkdir vcftools full_vcf=/projects/p32037/PASM/r80_8_filtered.vcf OUT=/projects/p32037/PASM/vcftools ``` Calculate: Allele frequency `vcftools --vcf $full_vcf --freq2 --out $OUT --max-alleles 2` Mean depth per indiv `vcftools --vcf $full_vcf --depth --out $OUT` Mean depth per site `vcftools --vcf $full_vcf --site-mean-depth --out $OUT` Site quality `vcftools --vcf $full_vcf --site-quality --out $OUT` Proportion missing data/indiv `vcftools --vcf $full_vcf --missing-indv --out $OUT` Proportion missing data/site `vcftools --vcf $full_vcf --missing-site --out $OUT` Het and inbred per indiv `vcftools --vcf $full_vcf --het --out $OUT` ### Moving these outputs into R... 1. Variant quality Produced a file where the quality is -1 for each site, what is going on here? 2. Variant mean depth Based on this, it looks like we could set our **minimum to 10x and maximum depth to 50** ( ~ 2x our mean depth) | min | 1st Qu. | Median | Mean | 3rd Qu. | Max | | ---- | ------- | ------ | ----- | ------- | --- | | 1.00 | 10.50 | 18.40 | 26.52 | 29.82 | 3924.00 | ![Screenshot 2024-01-18 at 2.00.41 PM](https://hackmd.io/_uploads/HkGFQWvtT.png) 3. Variant missingness The mean here is 0.6899 and medium is 0.733 which seems very high - we may have to use a low % missing data here. (50% call rate?) | min | 1st Qu. | Median | Mean | 3rd Qu. | Max | | ---- | ------- | ------ | ----- | ------- | --- | | 0.000 | 0.5556 | 0.7333 | 0.6899 | 0.889 | 0.9333 | ![Screenshot 2024-01-18 at 2.06.08 PM](https://hackmd.io/_uploads/rkE6VWPYT.png) 4. Minor allele frequency Maybe set this to 0.1 or 0.15 based on the data? | min | 1st Qu. | Median | Mean | 3rd Qu. | Max | | ---- | ------- | ------ | ----- | ------- | --- | | 0.01351 | 0.1000 | 0.18750 | 0.22612 | 0.35000 | 0.5 | ![Screenshot 2024-01-18 at 2.10.38 PM](https://hackmd.io/_uploads/H1k0S-wKT.png) --- ### Individual based statistics 1. Mean depth per individual The range is pretty extreme here 2.071 - 127.826 suggestting an issue with individual sequencing depth. | min | 1st Qu. | Median | Mean | 3rd Qu. | Max | | ---- | ------- | ------ | ----- | ------- | --- | | 2.071 | 8.997 | 29.206 | 32.607 | 49.057| 127.826 | ![Screenshot 2024-01-18 at 2.12.31 PM](https://hackmd.io/_uploads/Bk1rUZDta.png) 2. Proportion of missing data per individual The proportion of missing data per individual is large 0.35 - 0.96 | min | 1st Qu. | Median | Mean | 3rd Qu. | Max | | ---- | ------- | ------ | ----- | ------- | --- | | 0.3576 | 0.4575 | 0.7652 | 0.6899 | 0.8497 | 0.9611 | ![Screenshot 2024-01-18 at 2.13.17 PM](https://hackmd.io/_uploads/SyAPIbPt6.png) 3. Heterozygosity and inbreeding coefficient per individual Range of -0.17 to 0.39 | min | 1st Qu. | Median | Mean | 3rd Qu. | Max | | ---- | ------- | ------ | ----- | ------- | --- | | -0.17667 | 0.03222 | 0.06950 | 0.0.08637 | 0.12000 | 0.39499 | ![Screenshot 2024-01-18 at 2.14.02 PM](https://hackmd.io/_uploads/S1oqU-vK6.png) Based on these reuslts, here are some settings that may be useful, althoug I have concerns about the quality and missingness metrics `MAF=0.15` `MISS=0.75` `MIN_DEPTH=10` `MAX_DEPTH=50` # Applying VCF filters Operating in the reference_stacks directory first attempt, output as populations_stackstry1.ouput.vcf and using the populations.snps.vcf file from the popualtions run (this has all individuals/all populations) ran using the "default parameters" from Dylan's notes and from the analysis above First load the vcftools module `module load vcftools/0.1.17` Apply the filters.... ``` vcftools --vcf populations.snps.vcf --min-meanDP 5 --minDP 10 --max-meanDP 50 --maxDP 50 --mac 3 --remove-indels --max-alleles 2 --min-alleles 2 --max-missing 0.50 --recode --out populations_stackstry1.ouput.vcf ``` ``` vcftools --vcf r80_8_filtered.vcf --maf 0.05 --recode --out r80_8_filtered_maf.vcf VCFtools - 0.1.17 (C) Adam Auton and Anthony Marcketta 2009 Parameters as interpreted: --vcf populations.snps.vcf --mac 3 --max-alleles 2 --maxDP 50 --max-meanDP 50 --min-alleles 2 --minDP 5 --min-meanDP 5 --max-missing 0.8 --out populations_stackstry1.ouput.vcf --recode --remove-indels After filtering, kept 45 out of 45 Individuals Outputting VCF file... After filtering, kept 0 out of a possible 23789 Sites No data left for analysis! Run Time = 1.00 seconds ``` 0 sites kept...not great! trying again but changing --max-missing to 0.5 ``` vcftools --vcf populations.snps.vcf --min-meanDP 5 --minDP 10 --max-meanDP 50 --maxDP 50 --mac 3 --remove-indels --max-alleles 2 --min-alleles 2 --max-missing 0.50 --recode --out populations_stackstry2.ouput.vcf ``` Output: ``` (base) [ewf7555@quser32 reference_stacks]$ vcftools --vcf populations.snps.vcf --min-meanDP 5 --minDP 10 --max-meanDP 50 --maxDP 50 --mac 3 --remove-indels --max-alleles 2 --min-alleles 2 --max-missing 0.50 --recode --out populations_stackstry2.ouput.vcf VCFtools - 0.1.17 (C) Adam Auton and Anthony Marcketta 2009 Parameters as interpreted: --vcf populations.snps.vcf --mac 3 --max-alleles 2 --maxDP 50 --max-meanDP 50 --min-alleles 2 --minDP 10 --min-meanDP 5 --max-missing 0.5 --out populations_stackstry2.ouput.vcf --recode --remove-indels After filtering, kept 45 out of 45 Individuals Outputting VCF file... After filtering, kept 145 out of a possible 23789 Sites Run Time = 1.00 seconds ``` Trying again with 0.49 ``` (base) [ewf7555@quser34 reference_stacks]$ vcftools --vcf populations.snps.vcf --min-meanDP 5 --minDP 10 --max-meanDP 50 --maxDP 50 --mac 3 --remove-indels --max-alleles 2 --min-alleles 2 --max-missing 0.49 --recode --out populations_stackstry3.ouput.vcf VCFtools - 0.1.17 (C) Adam Auton and Anthony Marcketta 2009 Parameters as interpreted: --vcf populations.snps.vcf --mac 3 --max-alleles 2 --maxDP 50 --max-meanDP 50 --min-alleles 2 --minDP 10 --min-meanDP 5 --max-missing 0.49 --out populations_stackstry3.ouput.vcf --recode --remove-indels After filtering, kept 45 out of 45 Individuals Outputting VCF file... After filtering, kept 145 out of a possible 23789 Sites Run Time = 0.00 seconds ``` This is the same output, i don't think that 145 sites is good enough. Some populations have a lot of missing data...particualary GM and MW Remove GM and MW? - would have to re run gstacks and popualtions to do this (?) Maybe not.... Changed max missing to 0.6 and min DP to 5, adding MAF to 0.2 ``` (base) [ewf7555@quser34 reference_stacks]$ vcftools --vcf populations.snps.vcf --min-meanDP 5 --minDP 5 --max-meanDP 50 --maxDP 50 --mac 3 --remove-indels --max-alleles 2 --min-alleles 2 --max-missing 0.6 --maf 0.2 --recode --out populations_stackstry3.ouput.vcf Parameters as interpreted: --vcf populations.snps.vcf --mac 3 --maf 0.2 --max-alleles 2 --maxDP 50 --max-meanDP 50 --min-alleles 2 --minDP 5 --min-meanDP 5 --max-missing 0.6 --out populations_stackstry3.ouput.vcf --recode --remove-indels After filtering, kept 45 out of 45 Individuals Outputting VCF file... After filtering, kept 13 out of a possible 23789 Sites ``` # Troubleshooting ## Notes on removing "Bad apples" Primarily from Cerca et al. 2021 "Removing the bad apples: A simple bioinformatic mehtod to improve loci-reocvery in de novo RADseq data for non model organisms" https://doi.org/10.1111/2041-210X.13562 Steps they used: 1. Run STACKs with the complete dataset (all individuals) - this is called the "unclean" dataset 2. Run STACKs for each popualtion individually, then use vcftools to investigate missingness (--missing-indv, depth coverage --depth) 3. With the whole dataset in mind, we labelled individuals as to keep or remove (bad apples), following a general strategy which included: (a) retaining a minimum of two individuals per population or species; (b) designating a threshold for missing data, based on the average missing data for each whole dataset(≥40% missing data for Stygocapitella, ≥30% for Euhadra, ≥65% for Dendrilla, ≥40% for Anthochaera). ## Zoe's code for Clarkia data This is after running the denovo_map.pl (no filtering) ``` #### Quality filtering for CB. /data/Dimensions/clarkia/sv/cb/snp.calling/final/filter vcftools --vcf populations.snps.vcf --missing-indv # It looks like one indiviudal CB-58 failed and CB-73 and CB-77 did not do well. Remove them to keep 32 individuals # Remove individuals with lots of missing data vcftools --vcf populations.snps.vcf --remove rm.ind --recode --recode-INFO-all --out subset #Includes only sites with mean depth values (over all included individuals) greater than or equal to 15 vcftools --vcf subset.recode.vcf --min-meanDP 15 --recode --recode-INFO-all --out fil1 # kept 3568 #Exclude sites on the basis of the proportion of missing data (defined to be between 0 and 1, where 0 allows sites that are completely missing and 1 indicates no missing data allowed). Here 10% or less missing data is allowed vcftools --vcf subset.recode.vcf --max-missing 0.90 --recode --recode-INFO-all --out fil4 # kept 2492 #Filter with all parameters including mean depth vcftools --vcf subset.recode.vcf --min-meanDP 15 --mac 3 --max-missing 0.90 --hwe 0.05 --recode --recode-INFO-all --out filtered.final.subset #kept 458 ``` So trying this appraoch with my data, starting with the populations.snps.vcf file Checking CACO data for missing individuals: Doing this filter in a new directory `mkdir zfilter` `vcftools --vcf populations.snps.vcf --missing-indv` insepcting the output file out.imiss, it looks like there are quite a few with greater than 50% missing data... Making a list of these individuals ``` awk '$5 > 0.5' out.imiss | cut -f1 > lowDP.indv ##Output file - 32 individuals have greater than 50% missing data INDV DP830.sort DP831.sort DP838.sort GM544.sort GM556.sort GM559.sort GM564.sort HP801.sort HP803.sort HP805.sort HP807.sort IB1506B.sort IB1519.sort IB1522B.sort IB1524B.sort IB1528B.sort IB2687.sort MW537.sort MW538.sort MW542.sort MW543.sort PS608B.sort PS613A.sort PS614A.sort PS615A.sort SP772B.sort SP790.sort SP796B.sort SR908B.sort SR912.sort SR914.sort SR922.sort ``` Maybe see how many have 80% missing data? ``` awk '$5 > 0.8' out.imiss | cut -f1 > verylowDP.indv #looks like 17 individuals had 80% missing INDV DP830.sort DP831.sort DP838.sort GM544.sort GM556.sort GM559.sort GM564.sort HP801.sort HP803.sort HP805.sort HP807.sort IB1522B.sort IB1524B.sort MW537.sort MW538.sort MW542.sort MW543.sort ``` 90%?? ``` awk '$5 > 0.9' out.imiss | cut -f1 > superlowDP.indv #Output 8 individuals INDV GM544.sort GM556.sort GM559.sort GM564.sort MW537.sort MW538.sort MW542.sort MW543.sort ``` Looks like GM and MW are not great in general. Why would entire popualtions not sequence well?? I guess we will remove them, and continue on for now ``` # Remove individuals with lots of missing data vcftools --vcf populations.snps.vcf --remove superlowDP.indv --recode --recode-INFO-all --out subset Excluding individuals in 'exclude' list After filtering, kept 37 out of 45 Individuals Outputting VCF file... After filtering, kept 23789 out of a possible 23789 Sites ``` **Mean depth values** Mean depth of 15 ``` #Includes only sites with mean depth values (over all included individuals) greater than or equal to 15 vcftools --vcf subset.recode.vcf --min-meanDP 15 --recode --recode-INFO-all --out fil1 # kept 5077 sites ``` Mean depth of 5 ``` (base) [ewf7555@quser34 zfilter]$ vcftools --vcf subset.recode.vcf --min-meanDP 5 --recode --recode-INFO-all --out fil7 VCFtools - 0.1.17 (C) Adam Auton and Anthony Marcketta 2009 Parameters as interpreted: --vcf subset.recode.vcf --recode-INFO-all --min-meanDP 5 --out fil7 --recode After filtering, kept 37 out of 37 Individuals Outputting VCF file... After filtering, kept 12512 out of a possible 23789 Sites Run Time = 1.00 seconds ``` **Now on to the missing data...** missing data is 10% ``` #Exclude sites on the basis of the proportion of missing data (defined to be between 0 and 1, where 0 allows sites that are completely missing and 1 indicates no missing data allowed). Here 10% or less missing data is allowed vcftools --vcf subset.recode.vcf --max-missing 0.90 --recode --recode-INFO-all --out fil4 # 577 out of a possible 23789 Sites ``` Missing data is 10% but mean depth is 5 vcftools --vcf subset.recode.vcf --min-meanDP 5 --maf --max-missing 0.90 --maf 0.15 --hwe 0.05 --recode --recode-INFO-all --out filtered.final2.subset **Final filtering** try # 1 with Zoe's parameters ``` #Filter with all parameters including mean depth vcftools --vcf subset.recode.vcf --min-meanDP 15 --mac 3 --max-missing 0.90 --hwe 0.05 --recode --recode-INFO-all --out filtered.final.subset #kept 424 (Zoe's kept 458) ``` Jeremie's idea: min depth is 5 maf is 0.15 hwe 0.05 no max missing at all! ``` vcftools --vcf subset.recode.vcf --min-meanDP 5 --maf --maf 0.15 --hwe 0.05 --recode --recode-INFO-all --out filtered.final2.subset (base) [ewf7555@quser34 zfilter]$ vcftools --vcf subset.recode.vcf --min-meanDP 5 --maf 0.15 --hwe 0.05 --recode --recode-INFO-all --out filtered.final2.subset VCFtools - 0.1.17 (C) Adam Auton and Anthony Marcketta 2009 Parameters as interpreted: --vcf subset.recode.vcf --recode-INFO-all --maf 0.15 --max-alleles 2 --hwe 0.05 --min-meanDP 5 --out filtered.final2.subset --recode After filtering, kept 37 out of 37 Individuals Outputting VCF file... After filtering, kept 5151 out of a possible 23789 Sites Run Time = 1.00 seconds ``` Jeremie's idea: min depth is 5 maf is 0.15 no hwe no max missing at all! ``` (base) [ewf7555@quser34 zfilter]$ vcftools --vcf subset.recode.vcf --min-meanDP 5 --maf 0.15 --recode --recode-INFO-all --out filtered.final3.subset VCFtools - 0.1.17 (C) Adam Auton and Anthony Marcketta 2009 Parameters as interpreted: --vcf subset.recode.vcf --recode-INFO-all --maf 0.15 --min-meanDP 5 --out filtered.final3.subset --recode After filtering, kept 37 out of 37 Individuals Outputting VCF file... After filtering, kept 6616 out of a possible 23789 Sites Run Time = 1.00 seconds ``` ``` vcftools --vcf subset.recode.vcf --min-meanDP 5 --maf 0.15 --recode --recode-INFO-all --out filtered.final3.subset ``` jeremie thoughts! Make a data set that is hardy weinberg and a set that is not if the linkage is evenly distribted then we don't have to filter for linakage **Checked to see what the R2** ``` vcftools --vcf filtered.final.subset.recode.vcf --plink --out filtered.plink plink --file filtered.plink --r2 --noweb ``` Looking at linkage...there are a lot of pairs/loci that are linked (with an R2 above 0.8 going up to 1) Following https://speciationgenomics.github.io/pca/ ``` Checking output with plink and pruning for likage --vcf filtered.final.subset.recode.vcf --double-id --allow-extra-chr \--set-missing-var-ids @:# \ --indep-pairwise 50 10 0.1 --out plink_zfilter #Output 192637 MB RAM detected; reserving 96318 MB for main workspace. --vcf: plink_zfilter-temporary.bed + plink_zfilter-temporary.bim + plink_zfilter-temporary.fam written. 424 variants loaded from .bim file. 37 people (0 males, 0 females, 37 ambiguous) loaded from .fam. Ambiguous sex IDs written to plink_zfilter.nosex . Using 1 thread (no multithreaded calculations invoked. Before main variant filters, 37 founders and 0 nonfounders present. Calculating allele frequencies... done. Total genotyping rate is 0.964686. 424 variants and 37 people pass filters and QC. Note: No phenotypes present. Pruned 15 variants from chromosome 27, leaving 10. Pruned 31 variants from chromosome 28, leaving 15. Pruned 7 variants from chromosome 29, leaving 8. Pruned 16 variants from chromosome 30, leaving 12. Pruned 0 variants from chromosome 31, leaving 1. Pruned 31 variants from chromosome 32, leaving 13. Pruned 25 variants from chromosome 33, leaving 10. Pruned 23 variants from chromosome 34, leaving 10. Pruned 33 variants from chromosome 35, leaving 13. Pruned 17 variants from chromosome 36, leaving 8. Pruned 37 variants from chromosome 37, leaving 10. Pruned 21 variants from chromosome 38, leaving 10. Pruned 33 variants from chromosome 39, leaving 14. Pruned 0 variants from chromosome 40, leaving 1. Pruning complete. 289 of 424 variants removed. Marker lists written to plink_zfilter.prune.in and plink_zfilter.prune.out . Segmentation fault ``` ``` plink --vcf filtered.final.subset.recode.vcf --double-id --allow-extra-chr --set-missing-var-ids @:# --extract plink_zfilter.prune.in --make-bed --pca --out CACO_zfil #Output 192637 MB RAM detected; reserving 96318 MB for main workspace. --vcf: CACO_zfil-temporary.bed + CACO_zfil-temporary.bim + CACO_zfil-temporary.fam written. 424 variants loaded from .bim file. 37 people (0 males, 0 females, 37 ambiguous) loaded from .fam. Ambiguous sex IDs written to CACO_zfil.nosex . --extract: 135 variants remaining. Using up to 51 threads (change this with --threads). Before main variant filters, 37 founders and 0 nonfounders present. Calculating allele frequencies... done. Total genotyping rate is 0.964765. 135 variants and 37 people pass filters and QC. Note: No phenotypes present. Relationship matrix calculation complete. --pca: Results saved to CACO_zfil.eigenval and CACO_zfil.eigenvec . --make-bed to CACO_zfil.bed + CACO_zfil.bim + CACO_zfil.fam ... done. Segmentation fault ``` Going to R to see what we have here... --- ``` ### Filtering for SNP panel. Using the 458 SNPs called - has maf 17%, in HWE, 10% missing data and mean depth 15X. /data/clarkia/sv/cb/snp.panel #### Now have to filter original fasta file to get filtered fasta sequences./data/Dimensions/clarkia/sv/cb/snp.panel/fasta.filter mkdir fasta.filter cp populations.loci.fa fasta.filter/ cp filtered.final.subset.recode.vcf fasta.filter/ cd fasta.filter cut -f 1 filtered.final.subset.recode.vcf | sed 's/[\t]/,/g' > keep.col.one #only keep first column of the vcf file that has the SNPs that passed quality filtering sed '1,15d' keep.col.one > remove.headers #remove all the headers rows of the fasta file sed -e 's/^/>CLocus_/' remove.headers > list.to.keep #add the fasta label to be able to match below grep -w -A 1 -f list.to.keep populations.loci.fa --no-group-separator > filtered.fasta.fa #sort the original fasta to only keep the high quality ones #### Now we need to sort fasta file to get SNPs with at least 50 bp on either side of SNP. First get the length of characters in each line of the file. Then combine them together awk '{ print length }' filtered.fasta.fa > count # get the count of each line in the fasta file sed -n '1~2!p' count > length #keep every other line, so you only have the length of the sequence (not the locus ID) paste -d \\n list.to.keep length > length.locus #paste the locus Id and the legnth of that locus #### Now get the position of each cut -f 2 filtered.final.subset.recode.vcf | sed 's/[\t]/,/g' > keep.col.two # only keep the second column of the vcf file that hast he high quality SNPs sed '1,15d' keep.col.two > positions #remove headers of the vcf file #### Combine the locus ID, length and position paste list.to.keep length positions | column -s $'\t' -t > length.position #combine and have them formatted into tabulated columns #### Keep SNPs that have 50 bp on either side. Keep every line where column 3 (position) has is greater than 50, meaning there are mpre than 50 bp before the SNP. Then calcualte the difference between columne 2 (length) and column 3 (position) so that you only keep the loci with a difference greater than 50 meaning that there are at least 50 bp after the SNP. We have 346 loci. awk '(NR>0) && ($3 > 50 ) ' length.position > right.50 awk 'BEGIN { OFS = "\t" } { $5 = $2 - $3 } 1' right.50 > difference awk '(NR>0) && ($4 > 50 ) ' difference > right.left.50 #### Filter original fasta file to only keep these 360 loci cut -f 1 right.left.50 | sed 's/[\t]/,/g' > filtered.id grep -w -A 1 -f filtered.id populations.loci.fa --no-group-separator > final.filtered.fasta.fa ### Now we must filter to remove SNPs that are not the same between replicates. Need to filter the vcf file to include just the 346 filtered loci. cat filtered.id | cut -d"_" -f2 > filtered.chrom #get only the chromosome number sed '1,14d' filtered.final.subset.recode.vcf > allvcf.headers #### Copy the text below into a new file called vcfkeeping. These are the column names that we want. #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT CB-110 CB-110.2 CB-24 CB-24.2 CB-65 CB-65.2 CB-96 CB-96.2 #### Filter the full vcf file without headers to only keep the columns we want. cut -f"$(head -1 allvcf.headers | tr '\t' '\n' | nl | grep -Fwf vcfkeeping | awk '{print $1}' | paste -sd,)" allvcf.headers > rm.ind.vcf #### Keep only those 346 filtered loci grep -w -F -f filtered.chrom rm.ind.vcf > reps.filtered.vcf #for some reason this is keeping ten extra loci #so try adding prefix to chromosome number to first column in each file sed -e 's/^/chr/' filtered.chrom > filtered.chr sed -e 's/^/chr/' rm.ind.vcf > rm.ind.chr.vcf #try again grep -w -F -f filtered.chr rm.ind.chr.vcf > reps.filtered.vcf #now remove the chr string awk -F'chr' '{print $2}' reps.filtered.vcf > replicate.vcf #copy and paste header from previous file into new file ( sed 1q rm.ind.chr.vcf; sed 1d replicate.vcf ) > replicates.vcf && mv replicates.vcf replicate.vcf #### Now insert the vcf header manually (from the original vcf). Then use populations to make a genepop file to upload into R (locally). This will remove loci that are variable in other individuals but not variable in the replicates, so we are left with 310. populations -V /data/Dimensions/clarkia/sv/cb/snp.panel/replicates.filter/replicate.vcf -O /data/Dimensions/clarkia/sv/cb/snp.panel/replicates.filter -M /data/Dimensions/clarkia/sv/cb/snp.calling/final/popmap --genepop ##### I compared the loci that aren't the same in replicates in excel after uploading the genepop file. Note that you will loose some loci because if they aren't variable in the replicates, they won't be included in the genepop file. We of the starting 348 loci have 310 variable loci in the replicates to compare. The ID in the genepop file match up with the ids in the vcf file that you used to generate the genepop file. Make sure to use the GenePop ID from the replicate genepop file since this has ONLY the variable loci that you can compare. I then made a list of those to exclude. Now we have 202 SNPs. You will need to get the fasta loci ID from the genepop ID using the vcf file (the genepop file is ordered 1...x) ### Final filtering. /data/Dimensions/clarkia/sv/cb/snp.panel/replicates.filter. Using the loci that we are keeping. Make a list.to.keep with their locus ids then filter the original fasta file. grep -w -A 1 -f list.to.keep populations.loci.fa --no-group-separator > final.fasta.fa #sort the original fasta to only keep the high quality ones #### Now filter the vcf file. cat list.to.keep | cut -d"_" -f2 > snps.keep #get only the chromosome number sed '1,14d' filtered.final.subset.recode.vcf > allvcf.headers #remove header sed -e 's/^/chr/' allvcf.headers > allvcf.headers.chr #add 'chr' sed -e 's/^/chr/' snps.keep > snps.keep.chr #add 'chr' grep -w -F -f snps.keep.chr allvcf.headers.chr > filtered.chr #filter awk -F'chr' '{print $2}' filtered.chr > filtered #now remove the chr string #copy and paste header from previous file into new file ( sed 1q allvcf.headers; sed 1d filtered ) > filtered2 && mv filtered2 filtered.vcf #### Filter out linked loci. /data/Dimensions/clarkia/sv/cb/snp.panel/linkage.filter ## Had to reformat the vcf file to include a header bgzip -c filtered.vcf > filtered2.vcf.gz tabix -p vcf filtered2.vcf.gz /usr/local/libexec/bcftools/bcftools +prune -m 0.6 -w 100 filtered2.vcf.gz -Ob -o final.vcf #can't get this to work ## Checked to see what the R2 vcftools --vcf filtered.vcf --plink --out filtered.plink plink --file filtered.plink --r2 --noweb #### There are two pairs or loci that are linked (i.e. have an R2 above 80). Remove them and filter the vcf file. We have 200 SNPs sed '1,14d' filtered.final.subset.recode.vcf > allvcf.headers #remove header sed -e 's/^/chr/' allvcf.headers > allvcf.headers.chr #add 'chr' sed -e 's/^/chr/' list.to.keep > snps.keep.chr #add 'chr' grep -w -F -f snps.keep.chr allvcf.headers.chr > filtered.chr #filter awk -F'chr' '{print $2}' filtered.chr > filtered #now remove the chr string #copy and paste header from previous file into new file ( sed 1q allvcf.headers; sed 1d filtered ) > filtered2 && mv filtered2 filtered.vcf #### Run populations. Upload this gene pop file into R to look at heterozygosity of each locus at each population. Decided to keep all 310 loci for now. We can use the final.fasta.fa file to begin developing CB SNP panel. populations -V /data/Dimensions/clarkia/sv/cb/snp.panel/linkage.filter/filtered.vcf -O /data/Dimensions/clarkia/sv/cb/snp.panel/linkage.filter/ -M /data/Dimensions/clarkia/sv/cb/snp.panel/popmap.nr --genepop #### Only keeping a subset of loci that are highly variable across all three populations. Filter final vcf file to only get those highly variable SNPs and remove replicates. /data/Dimensions/clarkia/sv/cb/snp.panel/final.filter ##### Run populations again to run genepop file in R populations -V /data/Dimensions/clarkia/sv/cb/snp.panel/final.filter/filtered.vcf -O /data/Dimensions/clarkia/sv/cb/snp.panel/final.filter/ -M /data/Dimensions/clarkia/sv/cb/snp.panel/popmap.nr --genepop --vcf ##### Filter the final vcf using the 111 most variable SNPs /data/Dimensions/clarkia/sv/cb/snp.panel/final.filter/hs.filter sed -e 's/^/chr/' filtered.vcf > allvcf.headers.chr #add 'chr' sed -e 's/^/chr/' list.to.keep > snps.keep.chr #add 'chr' grep -w -F -f snps.keep.chr allvcf.headers.chr > filtered.chr #filter awk -F'chr' '{print $2}' filtered.chr > filtered #now remove the chr string #copy and paste header from previous file into new file ( sed 1q filtered.vcf; sed 1d filtered ) > filtered2 && mv filtered2 final.vcf ##### Run populations again populations -V /data/Dimensions/clarkia/sv/cb/snp.panel/final.filter/hs.filter/final.vcf -O /data/Dimensions/clarkia/sv/cb/snp.panel/final.filter/hs.filter -M /data/Dimensions/clarkia/sv/cb/snp.panel/popmap.nr --genepop --vcf #### Get SNP info for all final SNPs and make master spreadsheet with all SNP info. vcftools --vcf final.p.snps.vcf --missing-indv #Generates a file reporting the missingness on a per-site basis. The file has the suffix ".lmiss". vcftools --vcf final.p.snps.vcf --missing-site #Generates a file containing the mean depth per individual. This file has the suffix ".idepth" vcftools --vcf final.p.snps.vcf --depth #Generates a file containing the mean depth per site averaged across all individuals. This output file has the suffix ".ldepth.mean". vcftools --vcf final.p.snps.vcf --site-mean-depth ##### Format for submission to sequencing facility ###### Filter fasta to get those we want sed -e 's/^/>CLocus_/' list.to.keep > final.list.to.keep # Make list of loci we want to keep w/ correct format grep -w -A 1 -f final.list.to.keep populations.loci.fa --no-group-separator > final.fasta.fa # fitler original fasta ###### Re-formatting fasta file so that the locus name is in the first column and the sequence is in the second. paste -d " " - - < final.fasta.fa > final.fasta2 ###### Now doing some re-formatting for the submission form to Minnesota. Need to get the SNP with the major and minor alleles into the fasta file. Make a file with the sequence in the first column, position in the second column, and [allele1/allele2] in the third column. Then run code below (had to get help on this in Stack Exchange). awk -F"\t" '{printf "%s%s%s%s",substr($1,1,$2-1),$3,substr($1,$2+1),ORS}' snp > submission.txt ``` **Bedtools intersect** bedtools intersect -a -b -a = BAM/BED/GFF/VCF file “A”. Each feature in A is compared to B in search of overlaps. Use “stdin” if passing A with a UNIX pipe. -b = One or more BAM/BED/GFF/VCF file(s) “B”. Use “stdin” if passing B with a UNIX pipe. use bedtools slop to input a buffersize around each SNP bedtools slop -i input.vcf -g genome_file.txt -b 1000 | bedtools intersect -a - -b annotations.gff -wa -wb > intersect_1000_output.txt **First we need to create a genome .txt file** ``` samtools faidx /projects/p32037/PASM/genome/ncbi_dataset/data/GCA_907164705.1/GCA_907164705.1_Parnassius_apollo_genomic.fna cut -f1,2 /projects/p32037/PASM/genome/ncbi_dataset/data/GCA_907164705.1/GCA_907164705.1_Parnassius_apollo_genomic.fna > genome_file.txt ``` **Bash script: "snp_annotation.sh"** ``` #!/bin/bash #SBATCH --account=p32037 #SBATCH --partition=normal #SBATCH --time=2:00:00 #SBATCH --nodes=1 #SBATCH --ntasks-per-node=1 #SBATCH --mem-per-cpu=10GB #SBATCH --job-name=PASM_intersect_1000 #SBATCH --mail-type=ALL #SBATCH --mail-user=emmafetterly2025@u.northwestern.edu #SBATCH --error=PASM_intersect_1000.error #SBATCH --output=PASM_intersect_1000.out # Input argument GENOME_FILE=/projects/p32037/PASM/genome_file.txt # Convert VCF to BED format awk 'BEGIN {FS="\t"; OFS="\t"} !/^#/ {print $1, $2-1, $2, $3}' lfmm_filtered_vcf.vcf > temp_input.bed # Expand SNP regions by 10,000 bp and intersect with annotations bedtools slop -i temp_input.bed -g "$GENOME_FILE" -b 10000 | \ bedtools intersect -a - -b /projects/p32037/PASM/genome/ncbi_dataset/data/GCA_907164705.1/genomic.gff -wao > intersect_output_10000.tsv # Remove the temporary BED file rm temp_input.bed # Confirmation message echo "Intersection completed. Results saved to intersect_output_10000." ```