0
|
1 #!/usr/bin/env Rscript
|
|
2
|
|
3 suppressPackageStartupMessages(library("adegenet"))
|
|
4 suppressPackageStartupMessages(library("ape"))
|
7
|
5 suppressPackageStartupMessages(library("data.table"))
|
|
6 #suppressPackageStartupMessages(library("dbplyr"))
|
|
7 suppressPackageStartupMessages(library("dplyr"))
|
0
|
8 suppressPackageStartupMessages(library("ggplot2"))
|
|
9 suppressPackageStartupMessages(library("knitr"))
|
4
|
10 suppressPackageStartupMessages(library("optparse"))
|
|
11 suppressPackageStartupMessages(library("poppr"))
|
|
12 suppressPackageStartupMessages(library("RColorBrewer"))
|
7
|
13 suppressPackageStartupMessages(library("RPostgres"))
|
|
14 #suppressPackageStartupMessages(library("tidyr"))
|
4
|
15 suppressPackageStartupMessages(library("vcfR"))
|
|
16 suppressPackageStartupMessages(library("vegan"))
|
0
|
17
|
|
18 option_list <- list(
|
7
|
19 make_option(c("--database_connection_string"), action="store", dest="database_connection_string", help="Corals (stag) database connection string"),
|
|
20 make_option(c("--input_affy_metadata"), action="store", dest="input_affy_metadata", help="Affymetrix 96 well plate input file"),
|
4
|
21 make_option(c("--input_pop_info"), action="store", dest="input_pop_info", help="Population information input file"),
|
7
|
22 make_option(c("--input_vcf"), action="store", dest="input_vcf", help="VCF input file"),
|
|
23 make_option(c("--output_mlg_id"), action="store", dest="output_mlg_id", help="Mlg Id data output file"),
|
|
24 make_option(c("--output_stag_db_report"), action="store", dest="output_stag_db_report", help="stag db report output file")
|
0
|
25 )
|
|
26
|
|
27 parser <- OptionParser(usage="%prog [options] file", option_list=option_list);
|
|
28 args <- parse_args(parser, positional_arguments=TRUE);
|
|
29 opt <- args$options;
|
|
30
|
|
31 get_file_path = function(file_name) {
|
|
32 file_path = paste("output_plots_dir", file_name, sep="/");
|
|
33 return(file_path);
|
|
34 }
|
|
35
|
8
|
36 get_database_connection <- function(db_conn_string) {
|
|
37 # Instantiate database connection.
|
|
38 # The connection string has this format:
|
|
39 # postgresql://user:password@host/dbname
|
|
40 conn_items <- strsplit(db_conn_string, "://")[[1]];
|
|
41 string_needed <- conn_items[2];
|
|
42 items_needed <- strsplit(string_needed, "@")[[1]];
|
|
43 user_pass_string <- items_needed[1];
|
|
44 host_dbname_string <- items_needed[2];
|
|
45 user_pass_items <- strsplit(user_pass_string, ":")[[1]];
|
|
46 host_dbname_items <- strsplit(host_dbname_string, "/")[[1]];
|
|
47 user <- user_pass_items[1];
|
|
48 pass <- user_pass_items[2];
|
|
49 host <- host_dbname_items[1];
|
|
50 dbname <- host_dbname_items[2];
|
|
51 # FIXME: is there a way to not hard-code the port?
|
|
52 conn <- DBI::dbConnect(RPostgres::Postgres(), host=host, port='5432', dbname=dbname, user=user, password=pass);
|
|
53 return (conn);
|
|
54 }
|
|
55
|
3
|
56 # Read in VCF input file.
|
2
|
57 vcf <- read.vcfR(opt$input_vcf);
|
0
|
58
|
4
|
59 #Missing GT in samples submitted
|
|
60 gt <- extract.gt(vcf, element="GT", as.numeric=FALSE);
|
8
|
61 myMiss <- apply(gt, MARGIN=2, function(x){ sum(is.na(x))});
|
|
62 myMiss <- (myMiss / nrow(vcf)) * 100;
|
|
63 miss <- data.frame(myMiss);
|
7
|
64
|
|
65 hets <- apply(gt, MARGIN=2, function(x) {sum(lengths(regmatches(x, gregexpr("0/1", x))))} );
|
|
66 hets <- (hets / nrow(vcf)) * 100;
|
|
67 ht <- data.frame(hets);
|
|
68
|
|
69 refA <- apply(gt, MARGIN=2, function(x) {sum(lengths(regmatches(x, gregexpr("0/0", x))))} );
|
|
70 refA <- (refA / nrow(vcf)) * 100;
|
|
71 rA <- data.frame(refA);
|
4
|
72
|
7
|
73 altB <- apply(gt, MARGIN=2, function(x) {sum(lengths(regmatches(x, gregexpr("1/1", x))))} );
|
|
74 altB <- (altB / nrow(vcf)) * 100;
|
|
75 aB <- data.frame(altB);
|
|
76
|
|
77 # Convert VCF file into a genind for the Poppr package.
|
|
78 # TODO: probably should not hard-code 2 cores.
|
|
79 gl <- vcfR2genlight(vcf, n.cores=2);
|
8
|
80 gind <- new("genind", (as.matrix(gl)));
|
7
|
81
|
0
|
82 # Add population information to the genind object.
|
7
|
83 poptab <- read.table(opt$input_pop_info, check.names=FALSE, header=T, na.strings=c("", "NA"));
|
8
|
84 gind@pop <- as.factor(poptab$region);
|
7
|
85
|
|
86 # Convert genind object to a genclone object.
|
8
|
87 obj2 <- as.genclone(gind);
|
7
|
88
|
|
89 # Calculate the bitwise distance between individuals.
|
8
|
90 xdis <- bitwise.dist(obj2);
|
0
|
91
|
7
|
92 # Multilocus genotypes (threshold of 1%).
|
8
|
93 mlg.filter(obj2, distance=xdis) <- 0.01;
|
|
94 m <- mlg.table(obj2, background=TRUE, color=TRUE);
|
0
|
95
|
|
96 # Create table of MLGs.
|
8
|
97 id <- mlg.id(obj2);
|
7
|
98 dt <- data.table(id, keep.rownames=TRUE);
|
|
99 setnames(dt, c("id"), c("user_specimen_id"));
|
|
100
|
|
101 # Read user's Affymetrix 96 well plate csv file.
|
|
102 pinfo <- read.csv(opt$input_affy_metadata, stringsAsFactors=FALSE);
|
|
103 pinfo <- pinfo$user_specimen_id;
|
|
104 pi <- data.table(pinfo);
|
|
105 setnames(pi, c("pinfo"), c("user_specimen_id"));
|
|
106
|
8
|
107 # Connect to database.
|
|
108 conn <- get_database_connection(opt$database_connection_string);
|
7
|
109
|
|
110 # Import the sample table.
|
8
|
111 mD <- tbl(conn, "sample");
|
7
|
112
|
|
113 # Select user_specimen_id and mlg columns.
|
8
|
114 smlg <- mD %>% select(user_specimen_id, coral_mlg_clonal_id, symbio_mlg_clonal_id);
|
7
|
115
|
|
116 # Convert to dataframe.
|
|
117 sm <- data.frame(smlg);
|
|
118 sm[sm==""] <- NA;
|
|
119
|
|
120 # Convert missing data into data table.
|
8
|
121 mi <-setDT(miss, keep.rownames=TRUE)[];
|
7
|
122 # Change names to match db.
|
|
123 setnames(mi, c("rn"), c("user_specimen_id"));
|
|
124 setnames(mi, c("myMiss"), c("percent_missing_data_coral"));
|
|
125 # Round missing data to two digits.
|
|
126 mi$percent_missing <- round(mi$percent_missing, digits=2);
|
|
127
|
|
128 # Convert heterozygosity data into data table.
|
|
129 ht <-setDT(ht, keep.rownames=TRUE)[];
|
|
130 # Change names to match db.
|
|
131 setnames(ht, c("rn"), c("user_specimen_id"));
|
|
132 setnames(ht, c("hets"), c("percent_mixed_coral"));
|
|
133 # Round missing data to two digits.
|
|
134 ht$percent_mixed<-round(ht$percent_mixed, digits=2);
|
|
135
|
|
136 # Convert refA data into data.table.
|
|
137 rA <-setDT(rA, keep.rownames=TRUE)[];
|
|
138 # Change names to match db.
|
|
139 setnames(rA, c("rn"), c("user_specimen_id"));
|
|
140 setnames(rA, c("refA"), c("percent_reference_coral"));
|
|
141 # round missing data to two digits.
|
|
142 rA$percent_reference<-round(rA$percent_reference, digits=2);
|
|
143
|
|
144 # Convert altB data into data table.
|
|
145 aB <-setDT(aB, keep.rownames=TRUE)[];
|
|
146 # Change names to match db.
|
|
147 setnames(aB, c("rn"), c("user_specimen_id"));
|
|
148 setnames(aB, c("altB"), c("percent_alternative_coral"));
|
|
149 # Round missing data to two digits.
|
|
150 aB$percent_alternative<-round(aB$percent_alternative, digits=2);
|
|
151
|
|
152 #convert mlg id to data.table format
|
|
153 dt <- data.table(id, keep.rownames=TRUE);
|
|
154 # Change name to match db.
|
|
155 setnames(dt, c("id"), c("user_specimen_id"));
|
|
156
|
|
157 # Transform.
|
|
158 df3 <- dt %>%
|
|
159 group_by(row_number()) %>%
|
|
160 dplyr::rename(group='row_number()') %>%
|
|
161 unnest (user_specimen_id) %>%
|
|
162 # Join with mlg table.
|
|
163 left_join(sm %>%
|
|
164 select("user_specimen_id","coral_mlg_clonal_id"), by='user_specimen_id');
|
|
165
|
|
166 # If found in database, group members on previous mlg id.
|
|
167 uniques <- unique(df3[c("group", "coral_mlg_clonal_id")]);
|
|
168 uniques <- uniques[!is.na(uniques$coral_mlg_clonal_id),];
|
|
169 na.mlg <- which(is.na(df3$coral_mlg_clonal_id));
|
|
170 na.group <- df3$group[na.mlg];
|
|
171 df3$coral_mlg_clonal_id[na.mlg] <- uniques$coral_mlg_clonal_id[match(na.group, uniques$group)];
|
|
172
|
|
173 # Determine if the sample mlg matched previous genotyped sample.
|
|
174 df4<- df3 %>%
|
|
175 group_by(group) %>%
|
|
176 mutate(DB_match = ifelse(is.na(coral_mlg_clonal_id),"no_match","match"));
|
|
177
|
|
178 # Create new mlg id for samples that did not match those in the database.
|
|
179 none <- unique(df4[c("group", "coral_mlg_clonal_id")]);
|
|
180 none <- none[is.na(none$coral_mlg_clonal_id),];
|
|
181 na.mlg2 <- which(is.na(df4$coral_mlg_clonal_id));
|
|
182 n.g <- df4$group[na.mlg2];
|
|
183 ct <- length(unique(n.g));
|
|
184
|
|
185 # List of new group ids, the sequence starts at the number of
|
|
186 # ids present in df4$coral_mlg_clonal_ids plus 1. Not sure if
|
|
187 # the df4 file contains all ids. If it doesn't then look below
|
|
188 # to change the seq() function.
|
|
189 n.g_ids <- sprintf("HG%04d", seq((sum(!is.na(unique(df4["coral_mlg_clonal_id"]))) + 1), by=1, length=ct));
|
|
190 # This is a key for pairing group with new ids.
|
|
191 rat <- cbind(unique(n.g), n.g_ids);
|
|
192 # this for loop assigns the new id iteratively for all that have NA.
|
|
193 for (i in 1:length(na.mlg2)) {
|
|
194 df4$coral_mlg_clonal_id[na.mlg2[i]] <- n.g_ids[match(df4$group[na.mlg2[i]], unique(n.g))];
|
|
195 }
|
|
196
|
|
197 # Merge data frames for final table.
|
|
198 report_user <- pi %>%
|
|
199 # Join with the second file (only the first and third column).
|
|
200 left_join(df4 %>%
|
|
201 select("user_specimen_id","coral_mlg_clonal_id","DB_match"),
|
|
202 by='user_specimen_id') %>%
|
|
203 # Join with the second file (only the first and third column).
|
|
204 left_join(mi %>%
|
|
205 select("user_specimen_id","percent_missing_coral"),
|
|
206 by='user_specimen_id') %>%
|
|
207 # Join with the second file (only the first and third column).
|
|
208 left_join(ht %>%
|
|
209 select("user_specimen_id","percent_mixed_coral"),
|
|
210 by='user_specimen_id') %>%
|
|
211 # Join with the second file (only the first and third column);
|
|
212 left_join(rA %>%
|
|
213 select("user_specimen_id","percent_reference_coral"),
|
|
214 by='user_specimen_id') %>%
|
|
215 # Join with the second file (only the first and third column).
|
|
216 left_join(aB %>%
|
|
217 select("user_specimen_id","percent_alternative_coral"),
|
|
218 by='user_specimen_id') %>%
|
|
219 mutate(DB_match = ifelse(is.na(DB_match), "failed", DB_match))%>%
|
|
220 mutate(coral_mlg_clonal_id=ifelse(is.na(coral_mlg_clonal_id), "failed", coral_mlg_clonal_id))%>%
|
|
221 ungroup() %>%
|
|
222 select(-group);
|
|
223
|
|
224 write.csv(report_user, file=paste(opt$output_stag_db_report), quote=FALSE);
|
0
|
225
|
4
|
226 # Rarifaction curve.
|
0
|
227 # Start PDF device driver.
|
4
|
228 dev.new(width=10, height=7);
|
|
229 file_path = get_file_path("geno_rarifaction_curve.pdf");
|
|
230 pdf(file=file_path, width=10, height=7);
|
7
|
231 rarecurve(m, ylab="Number of expected MLGs", sample=min(rowSums(m)), border=NA, fill=NA, font=2, cex=1, col="blue");
|
|
232 dev.off();
|
|
233
|
|
234 # Genotype accumulation curve, sample is number of
|
|
235 # loci randomly selected for to make the curve.
|
|
236 dev.new(width=10, height=7);
|
|
237 file_path = get_file_path("geno_accumulation_curve.pdf");
|
|
238 pdf(file=file_path, width=10, height=7);
|
|
239 genotype_curve(gind, sample=5, quiet=TRUE);
|
|
240 dev.off();
|
0
|
241
|
4
|
242 # Create a phylogeny of samples based on distance matrices.
|
|
243 cols <- palette(brewer.pal(n=12, name='Set3'));
|
|
244 set.seed(999);
|
|
245 # Start PDF device driver.
|
|
246 dev.new(width=10, height=7);
|
|
247 file_path = get_file_path("nj_phylogeny.pdf");
|
|
248 pdf(file=file_path, width=10, height=7);
|
|
249 # Organize branches by clade.
|
8
|
250 tree <- obj2 %>%
|
7
|
251 aboot(dist=provesti.dist, sample=10, tree="nj", cutoff=50, quiet=TRUE) %>%
|
|
252 ladderize();
|
4
|
253 plot.phylo(tree, tip.color=cols[obj2$pop],label.offset=0.0125, cex=0.7, font=2, lwd=4);
|
|
254 # Add a scale bar showing 5% difference..
|
|
255 add.scale.bar(length=0.05, cex=0.65);
|
|
256 nodelabels(tree$node.label, cex=.5, adj=c(1.5, -0.1), frame="n", font=3, xpd=TRUE);
|
7
|
257 dev.off();
|
0
|
258
|