Nothing
#' Filter nodes & edges for extracting networks
#'
#' This function allows extracting and filtering network-data based on fixed threshold (\code{limInt}) and add sandwich-nodes (nodes inter-connecting initial nodes) out of node-based queries.
#'
#'
#' @param lst (list, composed of multiple matrix or data.frames ) main input (each list-element should have same number of columns)
#' @param filtCol (integer, length=1) which column of \code{lst} should be usd to filter using thresholds \code{limInt} and \code{sandwLim}
#' @param limInt (numeric, length=1) filter main edge-scores according to \code{filterAsInf}
#' @param sandwLim (numeric, length=1) filter sandwich connection edge-scores accodring to \code{filterAsInf}
#' @param filterAsInf (logical) filter as 'inferior or equal' or 'superior or equal'
#' @param outFormat (character) may be 'matrix' for tabular output, 'all' as list with matrix and list of node-names
#' @param remOrphans (logical) remove networks consisting only of 2 connected edges
#' @param remRevPairs (logical) remove duplicate edges due to reverse massping (eg A - B and B - A); NOTE : use only when edges don't have orientation !
#' @param elemNa (character) used only for messages
#' @param silent (logical) suppress messages
#' @param callFrom (character) allow easier tracking of message(s) produced
#' @param debug (logical) display additional messages for debugging
#' @return This function returns a matrix or data.frame
#' @seealso in \code{\link[base]{cbind}}
#' @examples
#'
#' lst2 <- list('121'=data.frame(ID=as.character(c(141,221,228,229,449)),11:15),
#' '131'=data.frame(ID=as.character(c(228,331,332,333,339)),11:15),
#' '141'=data.frame(ID=as.character(c(121,151,229,339,441,442,449)),c(11:17)),
#' '151'=data.frame(ID=as.character(c(449,141,551,552)),11:14),
#' '161'=data.frame(ID=as.character(171),11), '171'=data.frame(ID=as.character(161),11),
#' '181'=data.frame(ID=as.character(881:882),11:12) )
#'
#' lst2 <- list('121'=data.frame(ID=as.character(c(141,221,228,229,449)),11:15, 21:25),
#' '131'=data.frame(ID=as.character(c(228,331,332,333,339)),11:15, 21:25),
#' '141'=data.frame(ID=as.character(c(121,151,229,339,441,442,449)), c(11:17), 21:27),
#' '151'=data.frame(ID=as.character(c(449,141,551,552)), 11:14, 21:24),
#' '161'=data.frame(ID=as.character(171), 11,21), '171'=data.frame(ID=as.character(161), 11,21),
#' '181'=data.frame(ID=as.character(881:882), 11:12,21:22) )
#'
#' (te1 <- filterNetw(lst2, limInt=90, remOrphans=FALSE))
#' (te2 <- filterNetw(lst2, limInt=90, remOrphans=TRUE))
#'
#' (te3 <- filterNetw(lst2, limInt=13, remOrphans=FALSE))
#' (te4 <- filterNetw(lst2, limInt=13, remOrphans=TRUE))
#'
#'
#' @export
filterNetw <- function(lst, filtCol=3, limInt=5000, sandwLim=5000, filterAsInf=TRUE, outFormat="matrix", remOrphans=TRUE, remRevPairs=TRUE, elemNa="genes", silent=FALSE, callFrom=NULL, debug=FALSE) {
##
fxNa <- .composeCallName(callFrom, newNa="filterNetw")
if(!isTRUE(silent)) silent <- FALSE
if(isTRUE(debug)) silent <- FALSE else debug <- FALSE
if(any(sapply(c("mat","matr","matrix","all"), identical, outFormat))) {asMatrix <- TRUE} else {asMatrix <- FALSE}
if(length(names(lst)) <1) stop("Invalid format of 'lst' : has NO names")
## check input list for duplicate queries
lstNa <- names(lst)
chDu <- duplicated(lstNa, fromLast=FALSE)
if(any(chDu)) { lst <- lst[-1*which(chDu)]
if(!silent) message(fxNa,"Entry has ",sum(chDu)," duplicate entry-names, removing duplicates")
lstNa <- names(lst) } # update
useID <- list(query=lstNa)
if(debug) {message(fxNa,"fiNe1 passed ini check")}
## check format
ch2dim <- sapply(lapply(lst, dim), length) ==2
## remove any non-matrix or data.frame
if(any(!ch2dim)) {
if(all(!ch2dim)) {lst <- list(); chDim <- NULL; warning(fxNa,"Invalid input, should be list of matrixes or data.frames !!")
} else { lst <- lst(which(ch2dim))
chDim <- lapply(lst, dim) # update
if(!silent) message(fxNa,"Note: ",sum(!ch2dim)," out of ",length(ch2dim)," list-elements are not matrix or data.frame, removing")
} } else chDim <- lapply(lst, dim)
colNa <- colnames(lst[[1]])
if(debug) {message(fxNa,"fiNe2, passed remove any non-matrix or data.frame")}
## check if add'l column for quality/intensity data available
chQ <- sapply(lst, function(x) ncol(x) >1)
## check filtCol argument (assume format of lst as checked)
msg <- "Invalid entry for 'filtCol': should be integer (of length=1) to designate which column to use or column-name"
if(length(filtCol) <1) {if(ncol(lst[[1]]) >1) {filtCol <- 2; message(fxNa,msg,"; setting to 2")} else stop(msg," -too short")}
if(length(filtCol) >1) {filtCol <- filtCol[1]; message(fxNa,msg," -use 1st")}
if(!is.numeric(filtCol)) {filtCol <- which(colnames(lst[[1]])==filtCol)
if(length(filtCol) <1) {filtCol <- 2; message(fxNa, msg,"; setting to 2")}
} else { if(filtCol > ncol(lst[[1]]) | filtCol <2) {
filtCol <- 2; message(fxNa, msg,"; setting to 2")} }
## check input format if filtering can be applied (reset 'limInt' to NULL if can't be used)
if(length(limInt)==1 && is.numeric(limInt) && !any(is.na(limInt))) { # valid threshod for filtering
chDimQ <- all(sapply(chDim, function(x) x[2]) >1)
if(!chDimQ) { limInt <- sandwLim <- NULL
if(!silent) message(fxNa,"Data have no second column with numeric data for filtering, ignoring 'limInt' and 'sandwLim'")
} } else limInt <- NULL
if(debug) message(fxNa,"fiNe3, check input format if filtering can be applied")
## check if reverse-(direct)mapping has same score - only if .filterNetw is not launched (.filterNetw does this check, too)
if(remRevPairs && !asMatrix && all(chQ)) { # run only if no conversion to matrix, otherwise do this check after lrbind()
sepCha <- "__"
chRe <- cbind(pri=rep(names(lst), sapply(lst,nrow)), sec=lrbind(lst) )
chR2 <- paste(chRe[,2], chRe[,1], sep=sepCha) %in% paste(chRe[,1], chRe[,2], sep=sepCha)
if(any(chR2)) { if(!all(chR2)) chRe <- chRe[which(chR2),] # data with any reverse mapping only
tmp <- apply(as.matrix(chRe[,1:2]), 1, function(x) paste(sort(x), sep=sepCha))
tmp <- paste(tmp[1,], tmp[2,], sep=sepCha)
if(debug) {message(fxNa,"fiNe4, opional check if reverse-(direct)mapping has same score")}
tmp2 <- by(as.matrix(chRe), tmp, function(x) length(unique(x[,3])) ==1)
if(any(!tmp2)) warning(fxNa,"Reverse value for ",sum(!tmp2)," pairs incoherent !! (",
pasteC(sub(sepCha,"& ", names(tmp2)[utils::head(which(!tmp2))])),")")
} }
## filter all for thresh limInt, subseq filter sandwLim, establish list of all connected nodes
if(all(chQ) && length(limInt)==1 && is.numeric(limInt) && !any(is.na(limInt))) { # valid threshod for filtering
lst <- lapply(lst, function(x) x[which(if(!isFALSE(filterAsInf)) x[,filtCol] <= limInt else x[,filtCol] >= limInt),])
chDi <- sapply(lst, function(x) length(dim(x)) <2)
if(any(chDi)) lst[which(chDi)] <- lapply(lst[which(chDi)], function(x) matrix(x, nrow=1, dimnames=list(NULL,colNa))) # reset to matrix-type if lost at filtering
chN <- sapply(lst, length)
if(all(chN <1)) warning(fxNa,"NOTHING remaining after filtering for 'limInt'=",limInt," !!")
if(debug) {message(fxNa,"fiNe5, filter all for thresh limInt")}
## now check for possible sandwLim filter
if(any(sapply(c("def","default","auto"), identical, sandwLim))) sandwLim <- limInt
if(length(sandwLim)!=1 | !is.numeric(sandwLim) | any(is.na(sandwLim))) sandwLim <- NULL
if(debug) { message(fxNa,"fiNe6, check for possible sandwLim filter")}
} else sandwLim <- NULL
## extract 2nd nodes, apply sandwLim (if applicable)
lst <- lapply(lst, function(x) if(length(sandwLim) <1 || ncol(x) <2) x[which(x[,1] %in% useID$query),] else x[which(x[,1] %in% useID$query |
if(!isFALSE(filterAsInf)) x[,filtCol] <= sandwLim else x[,filtCol] >= sandwLim ),])
chDi <- sapply(lst, function(x) length(x) >0 && length(dim(x)) <2) # in case of list of matrixes, some may become simple vectors due to indexing
if(any(chDi)) lst[which(chDi)] <- lapply(lst[which(chDi)], function(x) matrix(x, nrow=1, dimnames=list(NULL,colNa))) # reset to matrix-type if lost at filtering
all2nd <- unlist(lapply(lst, function(x) x[,1]), use.names=FALSE) # extr 2nd node IDs (after add'l filtering)
if(debug) {message(fxNa,"fiNe7, extracting 2nd nodes, apply sandwLim")}
## remove empty (due to filtering)
chLe <- sapply(lst, length) >0
if(any(!chLe)) { lst <- lst[which(chLe)]
if(all(!chLe)) { if(!silent) message(fxNa,"NOTHING remaining after filtering !!")
} else if(!silent) message(fxNa,"Removed ",sum(!chLe)," out of ",length(chLe)," queries without data passing filtering")
lstNa <- names(lst) # update
useID <- list(query=lstNa) # update
}
## look for Sandwich nodes/genes
useID$sandwID <- NULL
## a sandwich node/gene has too aoocur at min 2x in query-results (and may not be part of init query)
chDup <- duplicated(all2nd, fromLast=FALSE) & !(all2nd %in% lstNa) # needed to be defined as sandwich
useID$sandwID <- if(any(chDup)) unique(all2nd[which(chDup)]) else NULL
if(debug) {message(fxNa,"fiNe8, sandwich nodes/genes")}; fiNe8 <- list(lst=lst,all2nd=all2nd,useID=useID,chDup=chDup,chLe=chLe,filtCol=filtCol, limInt=limInt,chQ=chQ)
## filter to keep connected network only (and reduce all to IDs & filtCol)
useID2 <- if(length(limInt) ==1) unique(unlist(useID)) else useID$query
lst <- lapply(lst, function(x) {y <- which(x[,1] %in% useID2); if(length(y) >0) {if(length(y) >1) x[y,c(1,filtCol)] else {
z <- data.frame(x[y,1], x[y,filtCol]); colnames(z) <- colnames(x)[c(1,filtCol)]; z} }})
chLe <- sapply(lst, length)
if(any(chLe <1)) { lst <- lst[which(chLe >0)]
if(!silent) message(fxNa,"",sum(chLe <1)," element(s) had no data remaining after filtering ..." )
}
if(debug) {message(fxNa,"fiNe9, filter to keep connected network only")}
if(length(lst) <1) message(fxNa,"NOTE: NOTHING remaining after filtering for connected networks ") else {
if(!isFALSE(asMatrix)) {
## convert to matrix, remove duplicates
lst <- .filterNetw(lst, remOrphans=remOrphans, reverseCheck=remRevPairs, filtCol=filtCol, callFrom=fxNa, silent=silent, debug=debug)
isSandw <- lst[,2] %in% useID$sandwID
lst <- cbind(lst, toSandw=if(is.data.frame(lst)) isSandw else as.numeric(isSandw))
if(!isFALSE(remRevPairs)) {
te1x <- apply(as.matrix(lst[,c(1,filtCol)]), 1, sort) ## need to sort le/ri !!
lst <- lst[which(!duplicated(paste(te1x[1,], te1x[2,]), fromLast=FALSE)),] # corrected for duplicate pairs
}
} else {
## prepare output as list
lst <- lapply(lst, function(x) {ch1 <- x[,1] %in% unlist(useID)
if(sum(ch1) >0) { if(sum(ch1) >0) x[which(ch1),] else matrix(x[which(ch1),], nrow=1, dimnames=list(NULL, colnames(x)))} else NULL })
if(!silent) message(fxNa,"Network of ",sum(useID$query %in% lstNa)," (init) ",elemNa," plus ",
sum(useID$sandwID %in% lstNa)," sandw-",elemNa ) #
}
}
if(any(sapply(c("all"), identical, outFormat))) lst <- list(useID=useID, netw=lst)
lst }
#' Filter nodes & edges for extracting networks (main)
#'
#' This function allows extracting and filtering network-data based on fixed threshold (\code{limInt}) and add sandwich-nodes (nodes inter-connecting initial nodes) out of node-based queries.
#'
#'
#' @param lst (list, composed of multiple matrix or data.frames ) main input (each list-element should have same number of columns)
#' @param remOrphans (logical) remove networks consisting only of 2 connected edges
#' @param reverseCheck (logical)
#' @param filtCol (integer, length=1) which column of \code{lst} should be usd to filter using thresholds \code{limInt} and \code{sandwLim}
#' @param silent (logical) suppress messages
#' @param callFrom (character) allow easier tracking of message(s) produced
#' @param debug (logical) display additional messages for debugging
#' @return This function returns a matrix or data.frame
#' @seealso \code{\link{filterNetw}} and other CRAN package dedeicated to networks
#' @examples
#' ab <- 1:10
#' @export
.filterNetw <- function(lst, remOrphans=TRUE, reverseCheck=TRUE, filtCol=2, callFrom=NULL, silent=FALSE, debug=FALSE) {
##
fxNa <- .composeCallName(callFrom, newNa=".filterNetw")
sepCha <- "__" # characters used in paste when fusing 2 nodes
lstLe <- sapply(lst, nrow)
names(lstLe) <- names(lst)
## transform list to matrix/data.frame
lst <- lrbind(lst, silent=TRUE)
if(any(dim(lst) <1) && length(dim(lst)) <2) stop("Invalid input format ! Bizzare, lrbind() did NOT manage to produce a matrix or data.frame")
colnames(lst)[1] <- "Node2"
if(ncol(lst) >1) colnames(lst)[2] <- "edgeScore"
lst <- data.frame(Node1=rep(names(lstLe), lstLe), lst)
if(debug) {message(fxNa,".fiNe.1 transform list to matrix/data.frame")}
## check for (reverse-)pairs
chR2 <- paste(lst[,filtCol], lst[,1], sep=sepCha) %in% paste(lst[,1], lst[,filtCol], sep=sepCha)
if(any(chR2)) {
chRe <- if(!all(chR2)) lst[which(chR2),] else lst # data with any reverse mapping only
tmp <- apply(as.matrix(chRe[,1:2]), 1, function(x) paste(sort(x), sep=sepCha)) # pairs of sorted nodes
tmp <- paste(tmp[1,], tmp[2,], sep=sepCha)
names(tmp) <- rownames(chRe)
## check for consistent score with reverse pairs
if(reverseCheck && ncol(lst) >2) {
tmp2 <- by(as.matrix(chRe), tmp, function(x) length(unique(x[,3])) ==1)
if(any(!tmp2)) warning(fxNa,"Reverse value for ",sum(!tmp2)," pairs incoherent !! (",
pasteC(sub(sepCha,"& ", names(tmp2)[utils::head(which(!tmp2))])),")")
}
if(debug) {message(fxNa,".fiNe.2 check for consistent score with reverse pairs")}
## remove duplicates (ie remove 2nd occurance due to reverse pairs)
dupP <- duplicated(tmp, fromLast=FALSE)
if(any(dupP)) {lst <- lst[-1*as.integer(names(tmp)[which(dupP)]),]
if(!silent) message(fxNa,"Removing ",sum(dupP)," (reverse) redundant mappings")}
}
if(debug) {message(fxNa,".fiNe.3 remove duplicates")}
##
lstN <- c(as.character(lst[,1]), as.character(lst[,2]))
if(remOrphans) {
## need number of connections to decide on low-connected
chNo <- duplicated(lstN, fromLast=TRUE)
if(any(chNo)) {
chNo2 <- chNo | duplicated(lstN, fromLast=FALSE)
if(debug) {message(fxNa,".fiNe.4 number of connections to decide on low-connected")}
if(!all(chNo2)) { hiNo <- unique(lstN[which(chNo2)] )
## which pairs of connections to keep (any node connected to a hiNo ?)
chLi <- rowSums(matrix(lstN %in% hiNo, ncol=2)) >0
if(all(!chLi) & !silent) warning(fxNa,"NONE of the nodes has any further connections, argument 'remOrphans' removes everything")
lst <- lst[which(chLi),]
if(debug) {message(fxNa,".fiNe.5 which pairs of connections to keep")}
} }
}
##
rownames(lst) <- 1:nrow(lst)
lstN <- unique(c(as.character(lst[,1]), as.character(lst[,2])))
lst
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.