Nothing
# Algorithm to detect boundaries, based on Monmonier's algorithm
# Extended to any connection network
# Thibaut Jombart 2006-2008 (t.jombart@imperial.ac.uk)
#####################
# function monmonier
#####################
monmonier <- function(xy, dist, cn, threshold=NULL, bd.length=NULL, nrun=1,
skip.local.diff=rep(0,nrun), scanthres=is.null(threshold), allowLoop=TRUE){
if(!inherits(cn,"nb")) stop('cn is not a nb object')
if(is.data.frame(xy)) xy <- as.matrix(xy)
if(!is.matrix(xy)) stop('xy must be a matrix')
if(!inherits(dist,"dist")) stop('Argument \'dist\' must be a distance matrix of class dist')
if(nrow(xy) != nrow(as.matrix(dist))) stop('Number of sites and number of observations differ')
## set to TRUE to debug
## DEBUG <- FALSE
## if(DEBUG) {
## plot.nb(cn, xy, col="grey", points=FALSE)
## if(exists("x1")) {
## x1 <<- x1
## s.value(xy,x1,add.p=TRUE)
## }
## text(xy,lab=1:nrow(xy),font=2,col="darkgreen")
## }
## PRECISION of the xy coordinates (in digits)
## used when coordinates are inputed in C code.
PRECISION=12
## conversion of the connection network
cn.nb <- cn
cn <- nb2neig(cn)
## binary matrix of neighbourhood
M <- neig2mat(cn)
## distance matrix
D <- as.matrix(dist)
## matrix of distances among neighbours
D <- M*D
## set/check the threshold value of the distances among neighbours
## default: the median of all distances among neighbours
if(is.null(threshold) || threshold<0) {Dlim <- summary(unique(D[D>0]))[5]} else {Dlim <- threshold}
## handle 'bd.length' / must prevail over threshold.
if(!is.null(bd.length)) {
if(bd.length < 1) bd.length <- 1
Dlim <- 0
scanthres <- FALSE
} else {
bd.length <- nrow(xy)^2
}
if(scanthres){
plot(sort(unique(D)[unique(D) > 0],decreasing=TRUE),main="Local distances plot",type="l",xlab="rank",ylab="Sorted local distances")
abline(h=Dlim,lty=2)
mtext("Dashed line indicates present threshold")
cat("Indicate the threshold (\'d\' for default): ")
temp <- as.character(readLines(con = getOption('adegenet.testcon'), n = 1))
if(toupper(temp)!="D") { Dlim <- as.numeric(temp) }
}
#### OLD VERSION ####
## ## build a data.frame of coords of neighbours, with columns x1 y1 x2 y2
## listCpl <- neig.util.GtoL(neig2mat(cn))
## allSeg <- cbind(xy[,1][listCpl[,1]] , xy[,2][listCpl[,1]] , xy[,1][listCpl[,2]] , xy[,2][listCpl[,2]])
## colnames(allSeg) <- c('xP','yP','xQ','yQ')
#### END OLD VERSION ####
## Compute once and for all a matrix matSegVal with columns A, B and val
## A: index of one vertex
## B: index if another vertex, connected (beighbour) to B
## val: distance between A and B
## This table is such that "val" is sorted in decreasing order.
matSegVal <- which(D>0,arr.ind=TRUE)
matSegVal.names <- apply(matSegVal,1,function(vec) paste(sort(vec),collapse="-"))
rownames(matSegVal) <- matSegVal.names # used to get unique segments (cause D is symmetric)
matSegVal <- matSegVal[unique(rownames(matSegVal)),]
temp <- apply(matSegVal,1,function(vec) D[vec[1],vec[2]])
matSegVal <- cbind(matSegVal,temp) # matSegVal has its 3 colums
idx <- order(matSegVal[,3], decreasing=TRUE)
matSegVal <- matSegVal[idx,]
## allSeg is a matrix giving the coordinates of all edges (in row), x1 y1 x2 y2.
allSeg <- cbind(xy[matSegVal[,1],] , xy[matSegVal[,2],])
rownames(allSeg) <- rownames(matSegVal)
colnames(allSeg) <- c("x1","y1","x2","y2")
## auxiliary function used to remove a segment from matSegVal (A,B: indices of vertices of the removed edge)
rmFromMatSegVal <- function(A,B){
AB.name <- paste(sort(c(A,B)), collapse="-")
toRemove <- match(AB.name, rownames(matSegVal))
matSegVal <<- matSegVal[-toRemove,]
}
## Given a rank 'rang', getNext retrieves the two corresponding neighbours (A and B),
## their middle (M), and the corresponding value.
## A is the index of the vertex, xA and yA are its coordinates
getNext <- function(rang){
## ## ## OLD VERSION ## ## ##
## val <- unique(sort(D,decreasing=TRUE))[rang]
## A <- which(round(D,10)==round(val,10),TRUE)[1,1] # beware: == used on doubles
## B <- which(round(D,10)==round(val,10),TRUE)[1,2] # beware: == used on doubles
## xA <- xy[A,1]
## yA <- xy[A,2]
## xB <- xy[B,1]
## yB <- xy[B,2]
## xM <- (xA + xB)/2
## yM <- (yA + yB)/2
## ## ## END OLD VERSION ## ## ##
#### Must take into account that the some local distances occur for different segments
#### Create a table with columns A, B and val
temp <- matSegVal[rang,]
A <- temp[1]
B <- temp[2]
val <- temp[3]
xA <- xy[A,1]
yA <- xy[A,2]
xB <- xy[B,1]
yB <- xy[B,2]
xM <- mean(c(xA,xB))
yM <- mean(c(yA,yB))
return( list(A=c(A,xA,yA), B=c(B,xB,yB), M=c(xM,yM), val=val) )
}
## checkNext returns TRUE if it is ok to draw the segment MN, i.e. if MN does not cross another edge,
## and FALSE otherwise
## - M and N define the segment of interest
## M = c(xM,yM) ; N=c(xN,yN)
## -segMat is the matrix of all known edges
## A,B,C,D are not coordinates, but indices of vertices
## -AB is the edge whose middle is M ; given to avoid checking MN vs AB
## -CD is the edge whose middle is N ; given to avoid checking MN vs CD
## - toRemove: a vector of characters naming other edges in segMat to be removed before checking
checkNext <- function(M,N,A,B,C,D,segMat=allSeg,toRemove=NULL,curDir=NULL){
## orientation of the segment MN
xmin <- min(M[1],N[1])
xmax <- max(M[1],N[1])
ymin <- min(M[2],N[2])
ymax <- max(M[2],N[2])
### From here segment that would be difficult to check for crossing are removed
### If MN is the segment of interest, with M middle of AB and N middle of CD,
subsetSeg <- segMat
## The segment that was just drawn before is removed from the checks for crossing (messy code 2)
if(!is.null(curDir)){
prevSeg <- grep(paste("dir",curDir,sep=""),rownames(subsetSeg))
if(length(prevSeg)>0){ # this is not the 1st seg. in this dir
prevSeg <- prevSeg[length(prevSeg)]
subsetSeg <- segMat[-prevSeg,,drop=FALSE]
} else { # this is the 1st seg. in this direction -> rm 1st seg of other dir
otherDir <- ifelse(curDir==1L, 2, 1)
prevSeg <- grep(paste("dir",otherDir,"-1-2",sep=""),rownames(subsetSeg))
if(length(prevSeg)>0) { subsetSeg <- segMat[-prevSeg,,drop=FALSE] }
}
}
## AB and CD are now taken out (doubtful code 2 returned by the C procedure CheckAllSeg)
AB.name <- paste(sort(c(A,B)),collapse="-")
AB.idx <- match(AB.name, rownames(subsetSeg))
CD.name <- paste(sort(c(C,D)),collapse="-")
CD.idx <- match(CD.name, rownames(subsetSeg))
subsetSeg <- subsetSeg[-c(AB.idx,CD.idx),,drop=FALSE]
## subsetSeg is a matrix, each of its rows being a segment: xP,yP,xQ,yQ
## edges out of the square of diagonal MN cannot be crossed, so they are removed from
## the checks for crossing
subsetSeg <- subsetSeg[!(subsetSeg[,1] < xmin & subsetSeg[,3] < xmin),,drop=FALSE]
subsetSeg <- subsetSeg[!(subsetSeg[,1] > xmax & subsetSeg[,3] > xmax),,drop=FALSE]
subsetSeg <- subsetSeg[!(subsetSeg[,2] < ymin & subsetSeg[,4] < ymin),,drop=FALSE]
subsetSeg <- subsetSeg[!(subsetSeg[,2] > ymax & subsetSeg[,4] > ymax),,drop=FALSE]
## handle toRemove here
if(!is.null(toRemove)){
idx <- match(toRemove, rownames(subsetSeg))
idx <- idx[!is.na(idx)]
if(length(idx)>0) { subsetSeg <- subsetSeg[-idx,,drop=FALSE] }
}
## temp is used for the output of CheckAllSeg
## initialized at 10, which is never returned by CheckAllSeg
temp <- as.integer(10)
## call to CheckAllSeg
## =======================
## output code for CheckAllSeg:
## - 0: no intersection
## - 1: all kind of intersection, including the codes from SegSeg function
## (a C function inside monmonier-utils.C):
## - 3 : The segments collinearly overlap, sharing at least a point.
## - 2 : An endpoint (vertex) of one segment is on the other segment,
## but segments aren't collinear.
## - 1 : The segments intersect properly (i.e. not case 2 or 3)
## =======================
##
## restore the matrix type if there is only one segment to check for crossing in subsetSeg
## round down coordinates in subsetSeg
subsetSeg <- round(subsetSeg, digits=PRECISION)
if(nrow(subsetSeg)>0) {
temp <- .C("CheckAllSeg",as.integer(nrow(subsetSeg)),as.integer(ncol(subsetSeg)),
as.double(as.matrix(subsetSeg)), as.double(M), as.double(N), temp,PACKAGE="adegenet")[[6]]
} else {temp <- 0}
## for debugging
## if(DEBUG) {
## if(temp==1) cat("\n can't go there (code",temp,")") else cat("\n new segment ok (code",temp,")")
## }
## if a code 1 or 3 is returned, CheckAllSeg returns FALSE
## else it returns TRUE
## additional control used (code 10, CheckAllSeg failed)
if(temp==10) stop("CheckAllSeg failure (returned value=10, i.e. unchanged, not computed). Please report the bug.")
if(temp==1 | temp==2 | temp==3) return(FALSE) else return(TRUE)
} # end of checkNext
## result object is created
## this is a list with one component per run (a run = a boundary)
result <-list()
for(run in 1:nrun){
result[[run]] <- list(dir1=list(),dir2=list())
}
#### MAIN FUNCTION HERE
#### a for loop is used to handle several runs
## each boundary seeks one starting point, and then expands both sides (dir1 / dir2)
for(run in 1:nrun){
## handle skip.local.diff here
## the corresponding values of distance are set definitely to -1
## if(skip.local.diff[run] >0)
## for(i in 1:skip.local.diff[run]){
## temp <- getNext(1)
## ## D[temp$A[1],temp$B[1] ] <- -1
## ## D[temp$B[1],temp$A[1] ] <- -1
## rmFromMatSegVal(temp$A[1],temp$B[1])
## }
## starting point: find the highest distance among neighbours
## then expand
currentDir1 <- getNext(1 + skip.local.diff[run])
currentDir2 <- currentDir1
current.bd.length <- 1
if(currentDir1$val<=Dlim) stop(paste('Algorithm reached the threshold value at the first step of run',run))
result[[run]]$dir1[[1]] <- currentDir1 # first point dir1
result[[run]]$dir2[[1]] <- currentDir2 # first point dir2 (same as dir1)
## D[result[[run]]$dir1[[1]]$A[1],result[[run]]$dir1[[1]]$B[1]] <- -1 # update D matrix
## D[result[[run]]$dir1[[1]]$B[1],result[[run]]$dir1[[1]]$A[1]] <- -1 # update D matrix
rmFromMatSegVal(result[[run]]$dir1[[1]]$A[1], result[[run]]$dir1[[1]]$B[1]) # update matSegVal
## dir1 => i1: result index; s1: index for the rank of the distance between neighbours (decreasing order)
## dir2 => i2: result index; s2: index for the rank of the distance between neighbours (decreasing order)
i1 <- 1
s1 <- 1
i2 <- 1
s2 <- 2
n <- nrow(D)
## logical handling the expansion of a boundary
keepExpanding <- ((current.bd.length < bd.length)
&& ((currentDir1$val>Dlim)|(currentDir2$val>Dlim))
&& (s1 < nrow(matSegVal) | s2 < nrow(matSegVal)) )
#### This while loop has the following behavior:
## as long as the keepExpanding is true, we try to expand the boundary by
## 1) finding the highest next distance among neighbours
## 2) test if we can draw the corresponding segment
## 3) - if we can, store the result, increment i1 or i2, reset s1 and s2, erase the edge
## 3) - if we can't, take the next distance among neighbours (incrementing s1 and s2)
## 4) get back to 1)
while(keepExpanding){
hasExpanded <- FALSE # used to test if it is relevant to check for looping
## if(DEBUG){
## points(currentDir1$M[1],currentDir1$M[2],col="white",pch=20)
## points(currentDir2$M[1],currentDir2$M[2],col="white",pch=20)
## }
if(s1 <= nrow(matSegVal)) { currentDir1 <- getNext(s1) }
if(s2 <= nrow(matSegVal)) { currentDir2 <- getNext(s2) }
## if(DEBUG){
## cat("\n\n ## dir1: trying edge",currentDir1$A[1],"-",currentDir1$B[1])
## points(currentDir1$M[1],currentDir1$M[2],col="blue",pch=20)
## readline("\npress enter")
## }
## first direction (dir1)
if( currentDir1$val > Dlim && s1 <= nrow(matSegVal)) {
if(checkNext(result[[run]]$dir1[[length(result[[run]]$dir1)]]$M,
currentDir1$M,
result[[run]]$dir1[[length(result[[run]]$dir1)]]$A[1],
result[[run]]$dir1[[length(result[[run]]$dir1)]]$B[1],
currentDir1$A[1],
currentDir1$B[1], curDir=as.integer(1))) {
i1 <- i1+1
result[[run]]$dir1[[i1]] <- currentDir1
## update the matrix of diff. between neighbours
## D[result[[run]]$dir1[[i1]]$A[1],result[[run]]$dir1[[i1]]$B[1]] <- -1
## D[result[[run]]$dir1[[i1]]$B[1],result[[run]]$dir1[[i1]]$A[1]] <- -1
rmFromMatSegVal(result[[run]]$dir1[[i1]]$A[1],result[[run]]$dir1[[i1]]$B[1] ) # update matSegVal
s1 <- 1
## update existing segments
allSeg <- rbind(allSeg,c(result[[run]]$dir1[[i1-1]]$M,result[[run]]$dir1[[i1]]$M) )
rownames(allSeg) <- c(rownames(allSeg)[-nrow(allSeg)] , paste("dir1",i1-1,i1,sep="-"))
## add 1 to the boundary length
current.bd.length <- current.bd.length + 1
hasExpanded <- TRUE
## if(DEBUG) {
## arrows(result[[run]]$dir1[[i1-1]]$M[1], result[[run]]$dir1[[i1-1]]$M[2],
## result[[run]]$dir1[[i1]]$M[1], result[[run]]$dir1[[i1]]$M[2],col="blue")
## }
} else{ s1 <- s1+1 }
} # end "if( currentDir1$val>Dlim)"
## if(DEBUG){
## cat("\n\n ## dir2: trying edge",currentDir2$A[1],"-",currentDir2$B[1])
## points(currentDir2$M[1],currentDir2$M[2],col="red",pch=20)
## readline("\npress enter")
## }
## second direction (dir2)
if( currentDir2$val > Dlim && s2 <= nrow(matSegVal)) {
if(checkNext(result[[run]]$dir2[[length(result[[run]]$dir2)]]$M,
currentDir2$M,
result[[run]]$dir2[[length(result[[run]]$dir2)]]$A[1],
result[[run]]$dir2[[length(result[[run]]$dir2)]]$B[1],
currentDir2$A[1],
currentDir2$B[1], curDir=as.integer(2))) {
i2 <- i2+1
result[[run]]$dir2[[i2]] <- currentDir2
## update the matrix of diff. between neighbours
## D[result[[run]]$dir2[[i2]]$A[1],result[[run]]$dir2[[i2]]$B[1]] <- -1
## D[result[[run]]$dir2[[i2]]$B[1],result[[run]]$dir2[[i2]]$A[1]] <- -1
rmFromMatSegVal(result[[run]]$dir2[[i2]]$A[1],result[[run]]$dir2[[i2]]$B[1])
s2 <- 1
## update existing segments
allSeg <- rbind(allSeg,c(result[[run]]$dir2[[i2-1]]$M,result[[run]]$dir2[[i2]]$M) )
rownames(allSeg) <- c(rownames(allSeg)[-nrow(allSeg)] , paste("dir2",i2-1,i2,sep="-"))
## add 1 to the boundary length
current.bd.length <- current.bd.length + 1
hasExpanded <- TRUE
## if(DEBUG){
## arrows(result[[run]]$dir2[[i2-1]]$M[1], result[[run]]$dir2[[i2-1]]$M[2],
## result[[run]]$dir2[[i2]]$M[1], result[[run]]$dir2[[i2]]$M[2],col="red",cex=2)
## }
} else{ s2 <- s2+1 }
} # end "if( currentDir2$val>Dlim)"
## update the logical for the while loop
keepExpanding <- ((current.bd.length < bd.length)
&& ((currentDir1$val>Dlim)|(currentDir2$val>Dlim))
&& (s1 <= nrow(matSegVal) | s2 <= nrow(matSegVal)) )
## handle the looping of a boundary
if(hasExpanded && (current.bd.length>3) && allowLoop){
## check if the two ends of the boundary can be joined
## remove segments ending each direction (to avoid messy code 2 in checkNext)
terminalEdges <- c(paste("dir1",i1-1,i1,sep="-"),
paste("dir2",i2-1,i2,sep="-"))
canLoop <- checkNext(result[[run]]$dir1[[length(result[[run]]$dir1)]]$M,
result[[run]]$dir2[[length(result[[run]]$dir2)]]$M,
result[[run]]$dir1[[length(result[[run]]$dir1)]]$A[1],
result[[run]]$dir1[[length(result[[run]]$dir1)]]$B[1],
result[[run]]$dir2[[length(result[[run]]$dir2)]]$A[1],
result[[run]]$dir2[[length(result[[run]]$dir2)]]$B[1],
toRemove=terminalEdges
)
if(canLoop) {
## add the last, closing segment
result[[run]]$dir1[[length(result[[run]]$dir1)+1]] <- result[[run]]$dir2[[length(result[[run]]$dir2)]]
## stop expanding
keepExpanding <- FALSE
## update existing segments
allSeg <- rbind(allSeg,c(result[[run]]$dir1[[length(result[[run]]$dir1)]]$M,
result[[run]]$dir2[[length(result[[run]]$dir2)]]$M) )
} # end looping of the boundary
}
## output for debugging
## if(DEBUG) {
## cat("\n","s1:",s1,"s2:",s2,"i1:",i1,"i2:",i2,"D1:",
## currentDir1$val,"D2:",currentDir2$val,"Dlim:",Dlim,
## "nrow(matSegVal)",nrow(matSegVal),"\n")
## cat("\n","D1:",currentDir1$val,"D2:",currentDir2$val,"Dlim:",Dlim,
## "cur.bd.le:", current.bd.length,"max length:", bd.length,"\n",
## "s1:",s1,"s2:",s2,"maxS:",nrow(matSegVal))
## }
} # end of one given run
} # end for all run
# build the final output
# this is a list of class monmonier
# each element correspond to a run, i.e. to a potential boundary
# the output also contains the number of runs ($nrun) and the matched call ($call).
output=list()
for(run in 1:nrun){
runname <- paste('run',run,sep='')
output[[runname]] <- list(dir1=list(),dir2=list())
# dir 1 #
output[[runname]]$dir1$path <- matrix(-1, ncol=2,nrow=length(result[[run]]$dir1))
colnames(output[[runname]]$dir1$path) <- c('x','y')
rownames(output[[runname]]$dir1$path) <- paste('Point',1:nrow(output[[run]]$dir1$path),sep='_')
for(i in 1:length(result[[run]]$dir1)) {
output[[runname]]$dir1$path[i,] <- result[[run]]$dir1[[i]]$M
output[[runname]]$dir1$values[i] <- result[[run]]$dir1[[i]]$val
}
# dir 2 #
output[[runname]]$dir2$path <- matrix(-1, ncol=2,nrow=length(result[[run]]$dir2))
colnames(output[[runname]]$dir2$path) <- c('x','y')
rownames(output[[runname]]$dir2$path) <- paste('Point',1:nrow(output[[run]]$dir2$path),sep='_')
for(i in 1:length(result[[run]]$dir2)) {
output[[runname]]$dir2$path[i,] <- result[[run]]$dir2[[i]]$M
output[[runname]]$dir2$values[i] <- result[[run]]$dir2[[i]]$val
}
}
output$nrun <- nrun
output$threshold <- Dlim
output$xy <- xy
output$cn <- cn.nb
output$call <- match.call()
class(output) <- 'monmonier'
return(output)
}
##########################
# function plot.monmonier
##########################
#' @method plot monmonier
#' @export
plot.monmonier <- function(x, variable=NULL,displayed.runs=1:x$nrun,
add.arrows=TRUE, col='blue',lty=1,bwd=4, clegend=1,csize=0.7,
method = c('squaresize','greylevel'),sub='',csub=1,possub='topleft',
cneig=1,pixmap=NULL,contour=NULL,area=NULL,add.plot=FALSE,...){
if (!inherits(x, "monmonier")) stop("Use only with 'monmonier' objects")
if(!is.null(variable) & !is.numeric(variable)) stop('If provided, variable must be numeric.\n')
xy <- x$xy
cpoint <- 0
if(cneig>0) {neig <- nb2neig(x$cn)} else {neig <- NULL}
if(is.null(variable)){
variable <- rep(1,nrow(xy))
csize <- 0
cpoint <- 1
clegend <- 0
}
s.value(xy,variable,grid=FALSE,include.origin=FALSE,addaxes=FALSE,neig=neig,
cneig=cneig,clegend=clegend,csize=csize,cpoint=cpoint,pch=20,pixmap=pixmap,
method=method,sub=sub,csub=csub,possub=possub,add.plot=add.plot)
opar <- par(no.readonly=TRUE)
on.exit(par(mar=opar$mar))
par(mar=c(0,0,0,0))
for(run in displayed.runs){
obj <- x[[run]]
if(length(col)!=x$nrun) col <- rep(col,x$nrun)
if(length(lty)!=x$nrun) lty <- rep(lty,x$nrun)
if(length(obj$dir1$values) == 0) stop(paste('Monmonier object of run', run, 'is empty (no point in the path)\n'))
if(length(obj$dir1$values) == 1 && length(obj$dir2$values) == 1) {
points(obj$dir1$path[1],obj$dir1$path[2],pch=20,col=col[run],...)
} else{
## handle boundary width
## the largest part corresponds to the highest distance among neighbours
val.1 <- obj$dir1$values
val.2 <- obj$dir2$values
n1 <- length(val.1)
n2 <- length(val.2)
cex.bwd.1 <- ( val.1[1:(n1-1)] + val.1[2:n1] )/2
cex.bwd.2 <- ( val.2[1:(n2-1)] + val.2[2:n2] )/2
cex.bwd.max <- max(c(cex.bwd.1,cex.bwd.2), na.rm=TRUE)
cex.bwd.1 <- cex.bwd.1/max(cex.bwd.max)
cex.bwd.2 <- cex.bwd.2/max(cex.bwd.max)
## amplify the differences
## cex.bwd.1 <- cex.bwd.1^1.5
## cex.bwd.2 <- cex.bwd.2^1.5
if(add.arrows) {
if(n1>1) arrows(obj$dir1$path[1:(nrow(obj$dir1$path)-1),1],
obj$dir1$path[1:(nrow(obj$dir1$path)-1),2],
obj$dir1$path[2:nrow(obj$dir1$path),1],
obj$dir1$path[2:nrow(obj$dir1$path),2],
lwd=bwd*cex.bwd.1,angle=20,length=0.2,col=col[run],lty=lty[run],...)
if(n2>1) arrows(obj$dir2$path[1:(nrow(obj$dir2$path)-1),1],
obj$dir2$path[1:(nrow(obj$dir2$path)-1),2],
obj$dir2$path[2:nrow(obj$dir2$path),1],
obj$dir2$path[2:nrow(obj$dir2$path),2],
lwd=bwd*cex.bwd.2,angle=20,length=0.2,col=col[run],lty=lty[run],...)
} else {
if(n1>1) segments(obj$dir1$path[1:(nrow(obj$dir1$path)-1),1],
obj$dir1$path[1:(nrow(obj$dir1$path)-1),2],
obj$dir1$path[2:nrow(obj$dir1$path),1],
obj$dir1$path[2:nrow(obj$dir1$path),2],
lwd=bwd*cex.bwd.1,col=col[run],lty=lty[run],...)
if(n2>1)segments(obj$dir2$path[1:(nrow(obj$dir2$path)-1),1],
obj$dir2$path[1:(nrow(obj$dir2$path)-1),2],
obj$dir2$path[2:nrow(obj$dir2$path),1],
obj$dir2$path[2:nrow(obj$dir2$path),2],
lwd=bwd*cex.bwd.2,col=col[run],lty=lty[run],...)
}
} # end else
} # end for
} # end function
#####################
# print function
#####################
#' @method print monmonier
#' @export
#'
print.monmonier <- function(x, ...){
cat("\t\n###########################################################")
cat("\t\n# List of paths of maximum differences between neighbours #")
cat("\t\n# Using a Monmonier based algorithm #")
cat("\t\n###########################################################\n")
cat('\n$call:')
print(x$call)
cat('\n # Object content #')
cat("\nClass: ", class(x))
cat('\n$nrun (number of successive runs): ', x$nrun)
if(x$nrun==1)
cat('\n$run1: run of the algorithm')
else if(x$nrun==2)
cat('\n$run1, $run2: runs of the algorithm')
else cat('\n$run1 ... $run',x$nrun, ': runs of the algorithm',sep='')
cat('\n$threshold (minimum difference between neighbours): ', x$threshold)
cat("\n$xy: spatial coordinates")
cat("\n$cn: connection network")
cat('\n\n # Runs content #')
for(i in 1:x$nrun){
cat('\n# Run',i)
# dir 1 #
cat('\n# First direction')
cat('\nClass: ', class(x$run1$dir1))
cat('\n$path:\n')
print(head(x[[i]]$dir1$path,n=3))
if(nrow(x[[i]]$dir1$path) >3) cat('...\n')
cat('\n$values:\n',head(x[[i]]$dir1$values,n=3))
if(length(x[[i]]$dir1$values)>3) cat(' ...')
# dir 2 #
cat('\n# Second direction')
cat('\nClass: ', class(x$run1$dir2))
cat('\n$path:\n')
print(head(x[[i]]$dir2$path,n=3))
if(nrow(x[[i]]$dir2$path) >3) cat('...\n')
cat('\n$values:\n',head(x[[i]]$dir2$values,n=3))
if(length(x[[i]]$dir2$values)>3) cat(' ...')
cat('\n')
lenTheo <- x$nrun + 5
if(length(names(x))> lenTheo) {
cat('Other elements: \n')
cat(names(x)[(lenTheo+1) : length(x)])
}
cat('\n')
}
}
##############################
# function optimize.monmonier
##############################
optimize.monmonier <- function(xy,dist,cn,ntry=10, bd.length=NULL, return.best=TRUE,
display.graph=TRUE,threshold=NULL,scanthres=is.null(threshold),allowLoop=TRUE){
## move X to the arguments if we want to optimize an already created object
X <- NULL
#if( any(is.null(xy), is.null(dist), is.null(cn)) & is.null(X) ) stop("Please provide either xy, dist and cn or a monmonier object (X)")
## if X is a monmonier object...
if(inherits(X,what="monmonier")){
obj <- as.list(X$call)
xy <- obj$xy
dist <- obj$dist
cn <- obj$cn
}
cn.nb <- cn
cn <- nb2neig(cn)
M <- neig2mat(cn)
D <- as.matrix(dist)
D <- M*D
if(is.null(threshold) || (threshold<0)) {Dlim <- summary(unique(D[D>0]))[5]} else {Dlim <- threshold}
if(scanthres){
plot(sort(unique(D)[unique(D) > 0],decreasing=TRUE),main="Local distances plot", type="l", xlab="rank",ylab="Sorted local distances")
abline(h=Dlim,lty=2)
mtext("Dashed line indicates present threshold")
cat("Indicate the threshold (\'d\' for default): ")
temp <- as.character(readLines(con = getOption('adegenet.testcon'), n = 1))
if(toupper(temp)!="D") { Dlim <- as.numeric(temp) }
}
## start the series if computations
cat(paste("Boundaries computed (required: ",ntry,")\n",sep=""))
## for loop
bdr.values <- -1 # used so that the first boundary is automatically the best
for(i in 0:(ntry-1)){
temp <- monmonier(xy, dist, cn.nb,skip.local.diff=i,scanthres=FALSE,
threshold=Dlim, bd.length=bd.length, allowLoop=allowLoop)
current.bdr.value <- sum(c(temp$run1$dir1$values, temp$run1$dir2$values))
if(all(current.bdr.value > bdr.values)) {
bdr.best <- temp
bdr.skip <- i
}
bdr.values <- c(bdr.values , current.bdr.value)
cat(paste(1+i," ")) # print progression in live
}
## remove the first value (-1) in bdr.value
bdr.values <- bdr.values[-1]
## graphical display
if(display.graph) barplot(bdr.values,xlab="Local differences skipped",ylab="Sum of all local differences",names.arg=0:(ntry-1))
## return the best value of skip.local.diff, or the corresponding object
if(!return.best) {
return(bdr.skip)
} else {
cat(paste("\nOptimal number of skipped local differences: ",bdr.skip,"\n"))
prevcall <- as.list(match.call())
newcall <- bquote( monmonier(xy=.(prevcall$xy), dist=.(prevcall$dist), cn=.(prevcall$cn),
threshold=.(bdr.best$threshold), bd.length=.(bd.length),
nrun=1, skip.local.diff=.(as.numeric(bdr.skip)), scanthres=FALSE, allowLoop=.(allowLoop)) )
## assign the appropriate call to the result
bdr.best$call <- newcall
## exp <- bquote( monmonier(xy=.(prevcall$xy),dist=.(prevcall$dist),cn=.(prevcall$cn),skip=.(bdr.skip),
## ,scan=FALSE,thres=.(Dlim),bd.length=.(bd.length),allowLoop=.(allowLoop)) )
return(bdr.best)
}
}
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.