#Copyright 2001 R.Gentleman, all rights reserved
#functions to look up particular genes at different sites
# Modifications to htmlpage and getQuery4XX functions added
# 7-12-04 by J. MacDonald
UniGeneQuery <- function(query, UGaddress="UniGene/",
type="CID") {
if (missing(query))
stop("No query, cannot proceed!")
##they are of the form HH.xxxx, where HH specifies the species
q1 <- strsplit(query, "\\.")
if( length(q1[[1]]) == 2 ) {
id <- sapply(q1, function(x) x[2])
species <- sapply(q1, function(x) x[1])
}
ncbiURL <- .getNcbiURL()
## Build up the query URL
query <- paste(ncbiURL, UGaddress,
"clust.cgi?ORG=",species,"&", type, "=",id, sep="")
return(query)
}
entrezGeneByID <- function(query) {
if (missing(query))
stop("No query, cannot proceed!")
ncbiURL <- .getNcbiURL()
## Build up the query URL
query <- paste(ncbiURL, "/sites/entrez?db=gene&cmd=search&term=",query, sep="")
return(query)
}
entrezGeneQuery <- function(query) {
if (missing(query))
stop("No query, cannot proceed!")
ncbiURL <- .getNcbiURL()
## Build up the query URL
str = ""
##reduce the set of parameters so that they are all one concatenated thing
for(i in seq_len(length(query))){
if(i==1){str=query[i]}else{
str = paste(str,"%20",query[i],sep="")
}
}
query <- paste(ncbiURL, "/sites/entrez?db=gene&cmd=search&term=",str, sep="")
return(query)
}
pmidQuery <- function(query) {
if (missing(query))
stop("No query, cannot proceed!")
query <- paste(query,collapse="%2c")
ncbiURL <- .getNcbiURL()
query <- paste(ncbiURL,"/entrez/query.fcgi?cmd=Retrieve&db=PubMed&",
"list_uids=",query,"&dopt=Abstract&tool=bioconductor",sep="")
return(query)
}
genbank <- function(..., disp=c("data","browser"),
type=c("accession", "uid"),
pmaddress=.efetch("gene",disp,type)) {
params <- list(...)
params <- unlist(params)
disp <- match.arg(disp)
type <- match.arg(type)
if (length(params) == 0) {
stop("No Gene ID, cannot proceed")
}
ncbiURL <- .getNcbiURL()
## Build up the query URL
args <- paste(params,collapse="%2c")
## See if we need to transform accession based arguments
err <- args
args <- .transformAccession(args, disp, type,db="genbank")
if (is.null(args)) {
print(paste("No XML records available for accession number",err))
return(NULL)
}
id <- .getIdTag(disp,type)
query <- paste(ncbiURL, pmaddress, id, args, sep="")
## Determine if we are displaying this data in a browser or
## returning an XMLDocument object
if (disp == "data") {
return(.handleXML(query))
}
else {
browseURL(query)
}
}
## bad query string:
## query = "http://www.ncbi.nih.gov/entrez/utils/pmfetch.fcgi?report=xml&mode=text&tool=bioconductor&db=Nucleotide&id=571320,4103966"
pubmed <- function(..., disp=c("data","browser"),
type=c("uid","accession"),
pmaddress=.efetch("PubMed",disp,type)) {
params <- list(...)
params <- unlist(params)
disp <- match.arg(disp)
type <- match.arg(type)
if (length(params) == 0) {
stop("No PMID, cannot proceed")
}
ncbiURL <- .getNcbiURL()
## Build up the query URL
args <- paste(params,collapse="%2c")
## See if we need to transform accession based arguments
err <- args
args <- .transformAccession(args, disp, type,"pubmed")
if (is.null(args)) {
message("No XML records available for accession number ", err)
return(NULL)
}
id <- .getIdTag(disp,type)
query <- paste(ncbiURL, pmaddress, id, args, sep="")
## Determine if we are displaying this data in a browser or
## returning an XMLDocument object
if (disp == "data") {
return(.handleXML(query))
}
else {
browseURL(query)
}
}
## A replacement for RCurl::getURL()
##
## Oct 13, 2020: RCurl::getURL() started to fail recently on Windows for
## some HTTPS requests e.g. we started to see the following error on all
## the Bioconductor Windows build machines (tokay1, riesling1, tokay2):
## > library(RCurl)
## > query <- "https://www.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=gene&to$
## > doc <- RCurl::getURL(query)
## Error in function (type, msg, asError = TRUE) :
## error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
## The reason is not clear but we suspect a server-side issue with the SSL
## certificate that only manifests itself with RCurl::getURL() on Windows.
## httr::GET() doesn't seem to be affected so starting with annotate 1.67.2
## accessionToUID() and blastSequences() use this instead of RCurl::getURL().
getURL2 <- function(url)
{
response <- httr::GET(url)
rawToChar(response$content)
}
accessionToUID <- function(...,db=c("genbank","pubmed")) {
#require(XML)
## Passed an accession #, returns a pubmed UID
accNum <- list(...)
accNum <- unlist(accNum)
accNum <- paste(accNum,collapse="+OR+")
db <- match.arg(db)
## Certain functions will be passing in a single string of comma
## deliminated Accession #s. Change the commas to "+OR+"
accNum <- gsub("\\,","+OR+",accNum)
if (db == "genbank") {
db <- "gene"
}
else {
db <- "PubMed"
}
query <- paste(.getNcbiURL(), "entrez/eutils/esearch.fcgi?db=", db,
"&tool=bioconductor&term=",accNum,sep="")
## parse using XML package
Sys.sleep(0.15) # avoid HTTP Error 429 "Too Many Requests"
doc <- xmlParse(getURL2(query)) # RCurl::getURL() has issues, see above
res <- xpathApply(doc=doc, path="/eSearchResult/IdList/Id",
fun=xmlValue)
retVal <- unlist(res)
if (length(retVal)==0){retVal <- NULL} else {
retVal <- paste(retVal, collapse=",")
}
return(retVal)
}
.handleXML <- function(query,handlers=NULL) {
## In the case of an error retrieving proper XML output,
## will return NA to the calling function
options(show.error.messages = FALSE)
on.exit(options(show.error.messages = TRUE))
## get the XML file contents from URL, and remove extra
## text strings before <xml...
Sys.sleep(0.15) # avoid HTTP Error 429 "Too Many Requests"
query <- paste(scan(query, what="", sep="\n"), "\n", collapse="\n")
query <- sub("^[^<]*<(.*)", "<\\1",query)
retVal <- NULL
xml <- try(xmlTreeParse(query,asText=TRUE,handlers=NULL,asTree=TRUE))
if (inherits(xml,"try-error") == TRUE) {
return(NA)
}
return(xml)
}
.getNcbiURL <- function() {
## Returns the URL for NCBI, which should be located in Annotate's
## option set
BioCOpt <- getOption("BioC")
if (!is.null(BioCOpt)) {
ncbiURL <- BioCOpt$annotate$urls$ncbi
}
if (!exists("ncbiURL")) {
ncbiURL <- "https://eutils.ncbi.nlm.nih.gov"
## old one: "http://www.ncbi.nih.gov/"
}
return(ncbiURL)
}
.getIdTag <- function(disp=c("data","browser"),
type=c("uid","accession")) {
disp <- match.arg(disp)
type <- match.arg(type)
if (disp == "data") {
return("&id=")
}
else {
if (type == "uid") {
return("&list_uids=")
}
else {
return("&term=")
}
}
}
## TODO: retire this method by replacing it with .efetch (NCBI is no longer supporting URLs of this ilk)
## .pmfetch <- function(db="PubMed", disp=c("data","browser"),
## type=c("uid","accession")) {
## ## Returns the base query string for the pmfetch engine @ pubmed
## disp <- match.arg(disp)
## type <- match.arg(type)
## if (disp == "data") {
## base <-
## "entrez/utils/pmfetch.fcgi?report=xml&mode=text&tool=bioconductor&db="
## }
## else {
## base1 <- "entrez/query.fcgi?tool=bioconductor&cmd="
## if (type == "uid") {
## base2 <- "Retrieve&db="
## }
## else {
## base2 <- "Search&db="
## }
## base <- paste(base1,base2,sep="")
## }
## return(paste(base,db,sep=""))
## }
## Needed to replace the aging (and obsoleted by NCBI) pmfetch...
.efetch <- function(db="PubMed", disp=c("data","browser"),
type=c("uid","accession")) {
## Returns the base query string for the efetch engine
disp <- match.arg(disp)
type <- match.arg(type)
if (disp == "data") {
base <-
"entrez/eutils/efetch.fcgi?tool=bioconductor&rettype=xml&retmode=text&db="
}
else {
base1 <- "entrez/query.fcgi?tool=bioconductor&cmd="
if (type == "uid") {
base2 <- "Retrieve&db="
}
else {
base2 <- "Search&db="
}
base <- paste(base1,base2,sep="")
}
return(paste(base,db,sep=""))
}
.transformAccession <- function(args, disp, type, db) {
## Used to change accession ID arguments to query functions
## into UIDs if necessary. Returns NULL if there aren't any left.
if ((disp == "data")&&(type=="accession")) {
args <- accessionToUID(args,db=db)
}
return(args)
}
pmAbst2HTML <- function(absts, filename, title, frames = FALSE,
table.center=TRUE) {
## Currently just a very naive implementation of a pmid2html type
## of thing. Intended to be temporary just while I'm testing some
## of this stuff.
if (!is.list(absts)) {
if (is(absts,"pubMedAbst"))
absts <- list(absts)
else
stop("'absts' parameter does not seem to be valid.")
}
## Assign a default filename. If we're using frames, then
## 'filename' is really just the base filename, so make it empty
if (missing(filename))
if (frames)
fileName <- ""
else
filename <- "absts.html"
if (missing(title))
title <- "BioConductor Abstract List"
nrows = length(absts)
pmids <- unlist(lapply(absts,pmid))
dates <- unlist(lapply(absts,pubDate))
queries <- unlist(lapply(absts,
function(x){pm <- pmid(x);out<-pmidQuery(pm);out}))
titles <- unlist(lapply(absts, articleTitle))
## If we're using frames, need to point the anchors to
## the main frame, otherwise not.
anchors <- makeAnchor(queries, titles, toMain=frames)
topText <- paste("<html>\n<head>\n<title>", title, "</title>",
"\n</head>\n<body bgcolor=#708090>\n",
"<H1 ALIGN=CENTER>", title, "</H1>\n",
"</body></title>", sep="")
head <- c("Article Title", "Publication Date")
headOut <- paste("<TH>", head, "</TH>", collapse="\n")
if (frames) {
top <- new("HTMLPage", fileName=paste(filename,"Top.html",sep=""),
pageText= topText)
tableHeader <- paste("<TR>",headOut,"</TR>", sep="\n")
sideText <- paste("<TABLE BORDER=1>", tableHeader, sep="\n")
tds <- paste("<TD>",anchors,"</TD><TD>",dates,"</TD>",sep="",
collapse="\n</TR>\n<TR>\n")
tds <- paste("<TR>",tds,"</TR>")
sideText <- paste(sideText, tds)
if (table.center)
sideText <- paste("<CENTER>",sideText,"</CENTER>", sep="\n")
sideText <- paste("<html>", "<head>",
"<title>BioConductor Abstract List</title>",
"</head>","<body bgcolor=#708090>",
sideText, "</body>", "</html>", sep="\n")
side <- new("HTMLPage",
fileName=paste(filename,"Side.html",sep=""),
pageText=sideText)
metaText <- paste("<meta HTTP-EQUIV=\"REFRESH\" CONTENT=\"1;",
queries[1],"\">",sep="")
mainText <- paste("<html>", "<head>",
"<title>BioConductor Abstract List</title>",
"</head>","<body bgcolor=#708090>",
metaText,
"</body>","</html>", sep="\n")
main <- new("HTMLPage",
fileName=paste(filename,"Main.html",sep=""),
pageText=mainText)
page <- new("FramedHTMLPage", topPage=top, sidePage=side, mainPage=main,
fileName=paste(filename,"index.html",sep=""),
pageTitle=title)
toFile(page)
}
else {
outfile <- file(filename,"w")
cat(topText, file = outfile)
if( table.center )
cat("<CENTER> \n", file=outfile)
cat("<TABLE BORDER=1>", file = outfile, sep = "\n")
cat("<TR>",headOut,"</TR>", file=outfile, sep="\n")
tds <- paste("<TD>",anchors,"</TD><TD>",dates,"</TD>",sep="")
for (td in tds)
cat("<TR>", td, "</TR>", file=outfile,sep="\n")
cat("</TABLE>",file=outfile)
if( table.center )
cat("</CENTER> \n", file=outfile)
cat("</body>", "</html>", sep = "\n", file = outfile)
close(outfile)
}
invisible(NULL)
}
htmlpage <- function (genelist, filename, title, othernames, table.head,
table.center=TRUE, repository = list("en"), ...){
if(!is.list(repository))
stop("The repository argument must be a list!", call. = FALSE)
chklen <- function(x){
if(is.data.frame(x) || is.matrix(x)) dim(x)[1]
else length(x)
}
getRows <- function(x){
paste("<P>", x, "</P>", collapse="", sep="")
}
if(is.data.frame(genelist))
len.vec <- chklen(genelist)
else
if(is.list(genelist))
len.vec <- sapply(genelist, chklen)
else
stop("The 'genelist' should be either a data.frame or a list",
call.=FALSE)
if(!missing(othernames)) {
if(is.data.frame(othernames))
len.vec <- c(len.vec, chklen(othernames))
else if( is.list(othernames))
len.vec <- c(len.vec, sapply(othernames, chklen))
else
stop("The 'othernames' should be either a data.frame or a list",
call.=FALSE)
}
if(any(len.vec != len.vec[1]))
stop(paste("Some items in either", genelist, "or", othernames,
"have mis-matched lengths.\nPlease check this",
"discrepancy and re-run.\n"), .call=FALSE)
out <- mapply(getCells, genelist, repository, ..., SIMPLIFY=TRUE)
if (!missing(othernames)) {
if(is.data.frame(othernames))
out <- data.frame(out, othernames)
else
if (is.list(othernames)) {
## if othernames is a list, we have to ensure we handle
## the contents of the list correctly
## e.g., cbind()ing a factor will coerce things incorrectly
## here we just put everything in another list that we can
## then coerce to a data.frame
others <- vector("list", length(othernames))
for(i in seq(along=othernames)){
if(is.data.frame(othernames[[i]]))
others[[i]] <- othernames[[i]]
else
if(is.list(othernames[[i]])){
## if othernames[[i]] is a list, the assumption
## here is that we want a multi-line table entry
## in the HTML page
others[[i]] <- sapply(othernames[[i]],
getRows)
}else{
others[[i]] <- othernames[[i]]
}
}
out <- data.frame(out, as.data.frame(others))
}
}
colnames(out) <- table.head
out <- xtable(out, caption=if(!missing(title)) title, ...)
print(out, type="html", file=filename, caption.placement="top",
include.rownames=FALSE, sanitize.text.function=function(x) x,
...)
}
getCells <- function(ids, repository = "ug", ...){
# This function allows us to insert multiple links in each cell by
# building up the HTML more incrementally. Passing a list of character
# vectors will result in multiple links per cell. Otherwise we get one link per cell.
if(is.list(ids)){
out <- vector()
temp <- lapply(ids, getQueryLink, repository=repository, ...)
for(i in seq(along = ids)){
if(temp[i] != " ")
out[i] <- paste("<P><A HREF=\"", temp[[i]], "\">",
ids[[i]], "</A></P>", sep = "", collapse="")
else
out[i] <- temp[i]
}
}else{
temp <- getQueryLink(ids, repository, ...)
blanks <- temp == " "
out <- paste(" <A HREF=\"", temp, "\">",
ids, "</A>", sep = "")
out[blanks] <- " "
}
return(out)
}
## getQueryLink <-function (ids, repository = "ug", ...){
## switch(tolower(repository), ug = return(getQuery4UG(ids)),
## gb = return(getQuery4GB(ids)), sp = return(getQuery4SP(ids)),
## omim = return(getQuery4OMIM(ids)), fb = return(getQuery4FB(ids)),
## en = return(getQuery4EN(ids)), tr = return(getQuery4TR(ids)),
## go = return(getQuery4GO(ids)), ens = return(getQuery4ENSEMBL(ids, ...)),
## random = return(getQuery4Random(ids)), stop("Unknown repository name"))
## }
## Code from Martin Morgan that allows end user to add arbitrary
## repository
## the interface: set, get, clear
setRepository <- function(repository, FUN, ..., verbose=TRUE)
{
## checs on repository, FUN, then...
if (verbose && exists(repository, .repositories))
warning("replacing repository '", repository, "'")
.repositories[[repository]] <- FUN
}
getRepositories <- function()
{
ls(.repositories)
}
clearRepository <- function(repository, verbose=TRUE)
{
if (!(length(repository) == 1 && is.character(repository)))
stop("argument 'repository' must be character(1)")
## check repository, then
if (exists(repository, .repositories))
rm(list=repository, envir=.repositories)
else if (verbose)
warning("undefined repository '", repository, "'")
}
## this should be backward compatible
getQueryLink <- function (ids, repository = "ug", ...)
{
if (!exists(repository, .repositories))
stop("unknown repository '", repository, "'")
.repositories[[repository]](ids, ...)
}
getTDRows <- function (ids, repository = "ug", ...){
# Modification of Jianhua's original code to allow for multiple links per cell.
out <- paste("<TD>", getCells(ids, repository), "</TD>", sep="")
return(out)
}
getQuery4GO <- function(ids, ...) {
##GO IDs
blanks <- ids == " "
AMIGO_URL <- "http://amigo.geneontology.org/cgi-bin/amigo/term_details?term="
out <- paste(AMIGO_URL, ids, sep = "")
out[blanks] = " "
return(out)
}
getQuery4Affy <- function (ids, ...){
# Affy IDs are all over the map, so there is no good way to catch any garbage input.
# Here we have to rely on the end user to filter out garbage by passing an empty cell.
blanks <- ids == " "
out <- paste("https://www.affymetrix.com/LinkServlet?&probeset=",
ids, sep="")
out[blanks] <- " "
return(out)
}
getQuery4UG <- function (ids, ...){
# Slight modification of Jianhua's original code, replacing error message with
# empty cells in the table.
if(is.factor(ids))
ugs <- strsplit(as.character(ids), "\\.")
else
ugs <- strsplit(ids, "\\.")
badUG <- function(x) if (length(x) != 2 || nchar(x[1]) < 2)
return(TRUE)
else return(FALSE)
bIDs <- sapply(ugs, badUG)
temp <- vector()
for( i in seq(along=ids)){
if(!bIDs[i])
temp[i] <- paste("https://www.ncbi.nlm.nih.gov/UniGene/clust.cgi?ORG=",
ugs[[i]][1], "&CID=", ugs[[i]][2], sep = "")
else
temp[i] <- " "
}
return(temp)
}
getQuery4EN <- function (ids, ...){
## Here we rely on Entrez Gene IDs being all numeric to filter out garbage
## that will result in busted links.
if(is.factor(ids)){
options(warn = -1)
ids <- as.numeric(as.character(ids))
options(warn = 0)
blanks <- is.na(ids)
}
if(is.character(ids)){
options(warn = -1)
ids <- as.numeric(ids)
options(warn = 0)
blanks <- is.na(ids)
}
if(is.numeric(ids))
blanks <- is.na(ids)
out <- paste("https://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=Retrieve&dopt=Graphics&list_uids=",
ids, sep = "")
out[blanks] <- " "
return(out)
}
getQuery4TR <- function(ids, ...){
## No automatic garbage checking. The ath1121501 has accnum values of 'multiple'
## that we can convert to blanks however.
blanks <- ids == " " || ids == "multiple"
out <- paste("http://www.arabidopsis.org/servlets/Search?type=general&search_action=detail&method=1&name=", ids,
"&sub_type=gene", sep="")
out[blanks] <- " "
return(out)
}
getQuery4GB <- function (ids, ...){
# GenBank ids can be either GB or RefSeq, so there is no good way to filter garbage.
# Again we rely on end user to pass blanks.
blanks <- ids == " "
out <- paste("https://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=Nucleotide&cmd=search&term=",
ids, sep="")
out[blanks] <- " "
return(out)
}
getQuery4SP <- function(ids, ...){
## SwissProt ids are not consistent enough to do any sort of garbage checking
## so here we rely on a blank being passed by the end user.
blanks <- ids == " "
## http://www.uniprot.org/uniprot?query=1&AC=P21108
out <- paste("http://www.uniprot.org/uniprot/", ids, sep="")
out[blanks] <- " "
return(out)
}
getQuery4OMIM <- function(ids, ...){
# Conversion here relies on the assumption that OMIM ids are all numeric
# so any non-numeric entry must be some sort of garbage that will result in
# a broken link.
if(is.factor(ids)){
options(warn = -1)
ids <- as.numeric(as.character(ids))
options(warn = 0)
blanks <- is.na(ids)
}
if(is.character(ids)){
options(warn = -1)
ids <- as.numeric(ids)
options(warn = 0)
blanks <- is.na(ids)
}
if(is.numeric(ids))
blanks <- is.na(ids)
out <- paste("http://www.omim.org/entry/", ids, sep="")
if(!is.null(blanks))
out[blanks] <- " "
return(out)
}
getQuery4FB <- function (ids, ...){
## Function to build links to flybase for drosophila arrays
## Here I rely on the flybase number starting with FBgn
## The end user can also pass an empty cell identifier
if(is.factor(ids))
fbs <- strsplit(as.character(ids), "FBgn")
else
fbs <- strsplit(ids, "FBgn")
badFB <- function(x) if(length(x) != 2 || nchar(x[1]) != 0)
return(TRUE) else return(FALSE)
bIDS <- sapply(fbs, badFB)
out <- paste("http://flybase.bio.indiana.edu/.bin/fbidq.html?",
ids, sep = "")
out[bIDS] <- " "
return(out)
}
getQuery4ENSEMBL <- function(ids, ...){
## function to build links to Ensembl
## Ensembl IDs can start with ENSG, ENSE, ENSP or ENST at the very least
ids[is.na(ids)] <- " "
if(is.factor(ids))
enids <- strsplit(as.character(ids), "ENS")
else
enids <- strsplit(ids, "ENS")
badENS <- function(x) if(length(x) !=2 || nchar(x[1]) != 0)
return(TRUE) else return(FALSE)
bIDS <- sapply(enids, badENS)
##FIXME: should we do some error checking on the species?
## it should be e.g., Homo_sapiens
if(!is.null(list(...)$species))
species <- list(...)$species
else
stop("To make links for Ensembl, you need to pass a 'species' argument.",
call. = FALSE)
out <- paste("http://www.ensembl.org/", species, "/Gene/Summary?g=",
ids, sep = "")
out[bIDS] <- " "
out
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.