comparison pubmed_by_queries.R @ 0:ff904894ccaa draft default tip

"planemo upload for repository https://github.com/galaxyproject/tools-iuc/tools/simtext commit 63a5e13cf89cdd209d20749c582ec5b8dde4e208"
author iuc
date Wed, 24 Mar 2021 08:32:54 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:ff904894ccaa
1 #!/usr/bin/env Rscript
2 #tool: pubmed_by_queries
3 #
4 #This tool uses a set of search queries to download a defined number of abstracts or
5 #PMIDs for search query from PubMed. PubMed's search rules and syntax apply.
6 #
7 #Input: Tab-delimited table with search queries in a column starting with "ID_",
8 #e.g. "ID_gene" if search queries are genes.
9 #
10 #Output: Input table with additional columns
11 #with PMIDs or abstracts (--abstracts) from PubMed.
12 #
13 #Usage:
14 #$pubmed_by_queries.R [-h] [-i INPUT] [-o OUTPUT] [-n NUMBER] [-a] [-k KEY]
15 #
16 #optional arguments:
17 # -h, --help show this help message and exit
18 # -i INPUT, --input INPUT input file name. add path if file is not in working directory
19 # -o OUTPUT, --output OUTPUT output file name. [default "pubmed_by_queries_output"]
20 # -n NUMBER, --number NUMBER number of PMIDs or abstracts to save per ID [default "5"]
21 # -a, --abstract if abstracts instead of PMIDs should be retrieved use --abstracts
22 # -k KEY, --key KEY if ncbi API key is available, add it to speed up the download of PubMed data.
23 # For usage in Galaxy add the API key to the Galaxy user-preferences (User/ Preferences/ Manage Information).
24
25 if ("--install_packages" %in% commandArgs()) {
26 print("Installing packages")
27 if (!require("argparse")) install.packages("argparse", repo = "http://cran.rstudio.com/") ;
28 if (!require("easyPubMed")) install.packages("easyPubMed", repo = "http://cran.rstudio.com/") ;
29 }
30
31 suppressPackageStartupMessages(library("argparse"))
32 suppressPackageStartupMessages(library("easyPubMed"))
33
34 parser <- ArgumentParser()
35 parser$add_argument("-i", "--input",
36 help = "Input fie name. add path if file is not in working directory")
37 parser$add_argument("-o", "--output", default = "pubmed_by_queries_output",
38 help = "Output file name. [default \"%(default)s\"]")
39 parser$add_argument("-n", "--number", type = "integer", default = 5,
40 help = "Number of PMIDs (or abstracts) to save per ID. [default \"%(default)s\"]")
41 parser$add_argument("-a", "--abstract", action = "store_true", default = FALSE,
42 help = "If abstracts instead of PMIDs should be retrieved use --abstracts ")
43 parser$add_argument("-k", "--key", type = "character",
44 help = "If ncbi API key is available, add it to speed up the download of PubMed data. For usage in Galaxy add the API key to the Galaxy user-preferences (User/ Preferences/ Manage Information).")
45 parser$add_argument("--install_packages", action = "store_true", default = FALSE,
46 help = "If you want to auto install missing required packages.")
47 args <- parser$parse_args()
48
49 if (!is.null(args$key)) {
50 if (file.exists(args$key)) {
51 credentials <- read.table(args$key, quote = "\"", comment.char = "")
52 args$key <- credentials[1, 1]
53 }
54 }
55
56 max_web_tries <- 100
57
58 data <- read.delim(args$input, stringsAsFactors = FALSE)
59
60 id_col_index <- grep("ID_", names(data))
61
62
63 fetch_pmids <- function(data, number, pubmed_search, query, row, max_web_tries) {
64 my_pubmed_url <- paste("https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?",
65 "db=pubmed&retmax=", number,
66 "&term=", pubmed_search$OriginalQuery,
67 "&usehistory=n", sep = "")
68 # get ids
69 idxml <- c()
70 for (i in seq(max_web_tries)) {
71 tryCatch({
72 id_connect <- suppressWarnings(url(my_pubmed_url, open = "rb", encoding = "UTF8"))
73 idxml <- suppressWarnings(readLines(id_connect, warn = FALSE, encoding = "UTF8"))
74 suppressWarnings(close(id_connect))
75 break
76 }, error = function(e) {
77 print(paste("Error getting URL, sleeping", 2 * i, "seconds."))
78 print(e)
79 Sys.sleep(time = 2 * i)
80 })
81 }
82 pmids <- c()
83 for (i in seq(length(idxml))) {
84 if (grepl("^<Id>", idxml[i])) {
85 pmid <- custom_grep(idxml[i], tag = "Id", format = "char")
86 pmids <- c(pmids, as.character(pmid[1]))
87 }
88 }
89 if (length(pmids) > 0) {
90 data[row, sapply(seq(length(pmids)), function(i) {
91 paste0("PMID_", i)
92 })] <- pmids
93 cat(length(pmids), " PMIDs for ", query, " are added in the table.", "\n")
94 }
95 return(data)
96 }
97
98
99 fetch_abstracts <- function(data, number, query, pubmed_search) {
100 efetch_url <- paste("https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?",
101 "db=pubmed&WebEnv=", pubmed_search$WebEnv, "&query_key=", pubmed_search$QueryKey,
102 "&retstart=", 0, "&retmax=", number,
103 "&rettype=", "null", "&retmode=", "xml", sep = "")
104 api_key <- pubmed_search$APIkey
105 if (!is.null(api_key)) {
106 efetch_url <- paste(efetch_url, "&api_key=", api_key, sep = "")
107 }
108 # initialize
109 out_data <- NULL
110 try_num <- 1
111 t_0 <- Sys.time()
112 # Try to fetch results
113 while (is.null(out_data)) {
114 # Timing check: kill at 3 min
115 if (try_num > 1) {
116 Sys.sleep(time = 2 * try_num)
117 cat("Problem to receive PubMed data or error is received. Please wait. Try number:",
118 try_num, "\n")
119 }
120 t_1 <- Sys.time()
121 if (as.numeric(difftime(t_1, t_0, units = "mins")) > 3) {
122 message("Killing the request! Something is not working. Please, try again later",
123 "\n")
124 return(data)
125 }
126 # ENTREZ server connect
127 out_data <- tryCatch({
128 tmp_connect <- suppressWarnings(url(efetch_url,
129 open = "rb",
130 encoding = "UTF8"))
131 suppressWarnings(readLines(tmp_connect,
132 warn = FALSE,
133 encoding = "UTF8"))
134 }, error = function(e) {
135 print(e)
136 }, finally = {
137 try(suppressWarnings(close(tmp_connect)),
138 silent = TRUE)
139 })
140 # Check if error
141 if (!is.null(out_data) &&
142 class(out_data) == "character" &&
143 grepl("<ERROR>", substr(paste(utils::head(out_data, n = 100),
144 collapse = ""), 1, 250))) {
145 out_data <- NULL
146 }
147 try_num <- try_num + 1
148 }
149 if (is.null(out_data)) {
150 message("Killing the request! Something is not working. Please, try again later",
151 "\n")
152 return(data)
153 } else {
154 return(out_data)
155 }
156 }
157
158
159 process_xml_abstracts <- function(out_data) {
160 xml_data <- paste(out_data, collapse = "")
161 # articles to list
162 xml_data <- strsplit(xml_data, "<PubmedArticle(>|[[:space:]]+?.*>)")[[1]][-1]
163 xml_data <- sapply(xml_data, function(x) {
164 #trim extra stuff at the end of the record
165 if (!grepl("</PubmedArticle>$", x))
166 x <- sub("(^.*</PubmedArticle>).*$", "\\1", x)
167 # Rebuid XML structure and proceed
168 x <- paste("<PubmedArticle>", x)
169 gsub("[[:space:]]{2,}", " ", x)
170 },
171 USE.NAMES = FALSE, simplify = TRUE)
172 #titles
173 titles <- sapply(xml_data, function(x) {
174 x <- custom_grep(x, tag = "ArticleTitle", format = "char")
175 x <- gsub("</{0,1}i>", "", x, ignore.case = T)
176 x <- gsub("</{0,1}b>", "", x, ignore.case = T)
177 x <- gsub("</{0,1}sub>", "", x, ignore.case = T)
178 x <- gsub("</{0,1}exp>", "", x, ignore.case = T)
179 if (length(x) > 1) {
180 x <- paste(x, collapse = " ", sep = " ")
181 } else if (length(x) < 1) {
182 x <- NA
183 }
184 x
185 },
186 USE.NAMES = FALSE, simplify = TRUE)
187 # abstracts
188 abstract_text <- sapply(xml_data, function(x) {
189 custom_grep(x, tag = "AbstractText", format = "char")
190 },
191 USE.NAMES = FALSE, simplify = TRUE)
192 abstracts <- sapply(abstract_text, function(x) {
193 if (length(x) > 1) {
194 x <- paste(x, collapse = " ", sep = " ")
195 x <- gsub("</{0,1}i>", "", x, ignore.case = T)
196 x <- gsub("</{0,1}b>", "", x, ignore.case = T)
197 x <- gsub("</{0,1}sub>", "", x, ignore.case = T)
198 x <- gsub("</{0,1}exp>", "", x, ignore.case = T)
199 } else if (length(x) < 1) {
200 x <- NA
201 } else {
202 x <- gsub("</{0,1}i>", "", x, ignore.case = T)
203 x <- gsub("</{0,1}b>", "", x, ignore.case = T)
204 x <- gsub("</{0,1}sub>", "", x, ignore.case = T)
205 x <- gsub("</{0,1}exp>", "", x, ignore.case = T)
206 }
207 x
208 },
209 USE.NAMES = FALSE, simplify = TRUE)
210 #add title to abstracts
211 if (length(titles) == length(abstracts)) {
212 abstracts <- paste(titles, abstracts)
213 }
214 return(abstracts)
215 }
216
217
218 pubmed_data_in_table <- function(data, row, query, number, key, abstract) {
219 if (is.null(query)) {
220 print(data)
221 }
222 pubmed_search <- get_pubmed_ids(query, api_key = key)
223 if (as.numeric(pubmed_search$Count) == 0) {
224 cat("No PubMed result for the following query: ", query, "\n")
225 return(data)
226 } else if (abstract == FALSE) { # fetch PMIDs
227 data <- fetch_pmids(data, number, pubmed_search, query, row, max_web_tries)
228 return(data)
229 } else if (abstract == TRUE) { # fetch abstracts and title text
230 out_data <- fetch_abstracts(data, number, query, pubmed_search)
231 abstracts <- process_xml_abstracts(out_data)
232 #add abstracts to data frame
233 if (length(abstracts) > 0) {
234 data[row, sapply(seq(length(abstracts)),
235 function(i) {
236 paste0("ABSTRACT_", i)
237 })] <- abstracts
238 cat(length(abstracts), " abstracts for ", query, " are added in the table.",
239 "\n")
240 }
241 return(data)
242 }
243 }
244
245 for (i in seq(nrow(data))) {
246 data <- tryCatch(pubmed_data_in_table(data = data,
247 row = i,
248 query = data[i, id_col_index],
249 number = args$number,
250 key = args$key,
251 abstract = args$abstract), error = function(e) {
252 print("main error")
253 print(e)
254 Sys.sleep(5)
255 })
256 }
257
258 write.table(data, args$output, append = FALSE, sep = "\t", row.names = FALSE, col.names = TRUE, quote = FALSE)