Nothing
jacobianAtXY <- function(
### Numerical approximation of the Jacobian at a point.
fDeriv ##<< derivative function \code{function(x,y,...)}
,x=NULL ##<< numeric scalar x coordinate
,y=NULL ##<< numeric scalar y corrdinate
,h=.000001 ##<< step to approximate derivative
){
if (is.null(x) | is.null(y)) {
x0 <- locator(n=1);
x <- x0$x;
y <- x0$y;
}
foo <- fDeriv(x,y);
foox <- fDeriv(x+h,y);
fooy <- fDeriv(x,y+h);
A <- (foox[1] - foo[1])/h;
B <- (fooy[1] - foo[1])/h;
C <- (foox[2] - foo[2])/h;
D <- (fooy[2] - foo[2])/h;
##value<< numeric matrix (2x2) of numerical approximation of Jacobian
return(matrix( c(A,B,C,D ), 2,2, byrow=T))
}
evalDerivGrid <- function(
### evaluating derivative function at grid
fDeriv ##<< derivative function \code{function(x,y,...)}
,xlims ##<< numeric vector (2): range of the x values
,ylims ##<< numeric vector (2): range of the y values
,resol=11 ##<< scalar integer: number of points in x and y range
,isJitter=FALSE
### set to TRUE to jitter vector starting positions to avoid overplotting
### (however calculating contours does not work then anymore)
,... ##<< further arguments to \code{fun}, such as \code{parms}
,useSnowfall=FALSE ##<< set to TRUE to use parallel execution using snowfall
){
xGrid <- seq(xlims[1],xlims[2], length=resol)
yGrid <- seq(ylims[1],ylims[2], length=resol)
x <- matrix(xGrid, byrow=T, resol,resol);
y <- matrix(yGrid, byrow=F, resol, resol);
if( isTRUE(isJitter) ){
# jitter
xspace <- abs(diff(xlims))/(resol*5)
yspace <- abs(diff(ylims))/(resol*5)
npts <- resol*resol;
x <- x + matrix(runif(npts, -xspace, xspace),resol,resol)
y <- y + matrix(runif(npts, -yspace, yspace),resol,resol)
}
xy <- abind::abind(x,y,rev.along=0)
#z <- apply( xy, c(1,2), function(X){ fun(0, X, ...)[[1]] })
zv1 <- fDeriv( x[1], y[1] ) # in order to get proper variable names
zv <- if( isTRUE(useSnowfall)){
ncpu = sfCpus()
nChunks <- length(c(x)) %/% ncpu
iChunk <- 1+(seq_along(c(x))-1) %/% nChunks
fRemote <- function(iCpu,iChunk, fDeriv, xv, yv, ...){
ii <- which(iChunk==iCpu)
matrix( fDeriv(xv[ii], yv[ii]), ncol=2 )
}
res <- sfLapply( x=1:ncpu, fun=fRemote, iChunk=iChunk, fDeriv=fDeriv, xv=c(x), yv=c(y), ...)
abind::abind( res, along=1)
}else fDeriv( c(x), c(y) )
z <- array( zv, dim=c(resol,resol,2) )
dimnames(z) <- list( x=NULL, y=NULL, names(zv1))
##value<< list with entries
list(
z=z ##<< numeric matrix vector (resol x resol,2): calculated flow at each of the grid (labels before before jittering)
,xy=xy ##<< numeric matrix (resol,resol,2): x and y values of the grid
)
}
phaseArrowsArray <- function(
### plotting phase space vectors
z ##<< numeric matrix (dimx,dimy,2): calculated flow at a grid, see
,xy ##<< numeric matrix (dimx,dimy,2): (x,y) of each gridpoint
,add=F ##<< set to TRUE to add arrows to an existing plot
,arrowHeads=0.4 ##<< size of the arrow heads (in inches), set to 0 for no heads, 0.04 gives nice results
,arrowLength=0.5 ##<< length of the vectors, set to 0 to scale vectors with magnitude of flow
,col=rev(heat.colors(150))[-(1:50)] ##<< color scale
,logLength=FALSE ##<< set to TRUE to calculate colors or length for log of the flow strength
,dimnames ##<< character vector(2): labels of the x and y axis
){
if( length(dimnames)==0 )
dimnames = if( length(rownames(z)) ) rownames(z) else c("dx","dy")
xlims <- range( xy[,,1])
ylims <- range( xy[,,2])
resol <- nrow(xy)
z1 <- z[,,1]
z2 <- z[,,2]
lens <- sqrt(z1^2 + z2^2)
lens2 <- if( arrowLength==0){
maxx <- max(abs(z1))
maxy <- max(abs(z2))
dt2 <- min( abs(diff(xlims))/maxx, abs(diff(ylims))/maxy)/resol
lens2 <- (lens/max(lens) +0.1)/(dt2)
}else{
dt <- min( abs(diff(xlims)), abs(diff(ylims)))/resol
lens2 <- lens / dt / arrowLength
}
nCol <- length(col)
colVal <- if(nCol==1 ) col else {
lens3 <- if(isTRUE(logLength)) log(lens) else lens
col[ round( .twRescale( abs(lens3), to=c(1, nCol) ) ) ]
}
if (add==F) {
plot(1,xlim=xlims, ylim=ylims, type='n', xlab=dimnames[1], ylab=dimnames[2] )
}
arrows(c(xy[,,1]), c(xy[,,2]), c(xy[,,1]+z1/lens2), c(xy[,,2]+z2/lens2), length=arrowHeads, col=colVal)
##value<< invisible numeric matrix (2,resol,resol): calculated flow at each of the grid points before jittering
invisible(NULL)
}
phaseArrows <- function(
### plotting phase space vectors
fDeriv ##<< derivative function \code{function(x,y,...)}
,xlims=c(-3,3) ##<< numeric vector (2): range of the x values
,ylims=xlims ##<< numeric vector (2): range of the y values
,resol=20 ##<< scalar integer: number of points in x and y range
,isJitter=FALSE
### set to TRUE to jitter vector starting positions to avoid overplotting
### (however calculating contours does not work then anymore)
,add=F ##<< set to TRUE to add arrows to an existing plot
,arrowHeads=0.04 ##<< size of the arrow heads (in inches), set t0 0 for heads, 0.04 gives nice results
,arrowLength=0.5 ##<< length of the vectors, set to 0 to scale vectors with magnitude of flow
,col=rev(heat.colors(150))[-(1:50)] ##<< color scale
,logLength=FALSE ##<< set to TRUE to calculate colors or length for log of the flow strength
,dimnames=NULL ##<< character vector(2): labels of the x and y axis, to overwrite defaults
,... ##<< further arguments to \code{fun}, such as \code{parms}
){
res <- evalDerivGrid(fDeriv=fDeriv, xlims=xlims, ylims=ylims, resol=resol, isJitter=isJitter,...)
phaseArrowsArray(z=res$z, xy=res$xy, add=add, arrowHeads=arrowHeads, arrowLength=arrowLength, col=col, logLength=logLength, dimnames=dimnames)
##value<< result of \code{\link{evalDerivGrid}}: a list with entries \itemize{
## \item z: numeric matrix vector (resol x resol,2): calculated flow at each of the grid (labels before before jittering)
## \item xy: numeric matrix (resol,resol,2): x and y values of the grid
## }
invisible(res)
}
attr( phaseArrows,"ex") <- function(){
fDeriv <- predatorprey(lambda=3, epsilon=2, delta=3, eta=2)
#
# set up a plotting window
# windows(width = 4.6, height = 3.2, pointsize = 10); par( las = 1, mar = c(2, 3.3, 0, 0) + 0.3, tck = 0.02, mgp = c(1.1, 0.2, 0))
#
# default: strength is colored, no arrow heads, same length
tmp <- phaseArrows( fDeriv, c(-2,5),c(-2,5) );
#phaseContours(tmp$z, tmp$xy, add=TRUE)
phaseNullclines(tmp$z, tmp$xy, add=TRUE)
drawTrajectories( fDeriv, tEnd=3, x0=list(x=1,y=2) ) # initial starting point by script
#drawTrajectories( fDeriv, tEnd=3, x0=locator(2,"p") ) # set the starting point in the graph: need to click several times
#
# add arrow heads and use colors for log scale, scale vector length
phaseArrows( fDeriv, c(-2,5),c(-2,5), logLength=TRUE, arrowHeads=0.04, arrowLength=0 );
#
# for background, sometimes a decent color is useful
tmp <- phaseArrows( fDeriv, c(-2,5),c(-2,5), col="grey" );
#
# may use parallel calculation of flow field and trajectories
if( FALSE ){ # do not run on R CMC check
require(snowfall)
tmp <- phaseArrows( fDeriv, c(-2,5),c(-2,5), useSnowfall=TRUE ); # using parallel calculation
drawTrajectories( fDeriv, tEnd=3, x0=list(x=1,y=c(2:5)), fLapply=sfLapply ) # initial starting point by script
}
}
phaseContours <- function(
### draw contour lines for the y and x component of the derivative
z ##<< result component of \code{\link{evalDerivGrid}}
,xy ##<< result component of \code{\link{evalDerivGrid}}
,add=F ##<< set to TRUE to add arrows to an existing plot
,colors=c('red', 'blue') ##<< colors of the contourlines for x and y direction of the derivative
, ... ##<< further arguments to \code{\link{contour}}, such as \code{levels}
) {
z1 <- z[,,1]
z2 <- z[,,2]
x <- xy[,,1]
y <- xy[,,2]
contour(x[1,],y[,1],t(z1), add=add, col=colors[1], ...); # why t? but it works maybe stacked on y instead on x
contour(x[1,],y[,1],t(z2), add=T, col=colors[2],...);
}
phaseNullclines <- function(
### draw nullclines, estimated by contour line at level 0
... ##<< arguments to \code{\link{phaseContours}}
){
phaseContours(..., levels=c(0))
}
drawTrajectories <- function(
### evaluate and draw trajectories in the phase plane
fDeriv ##<< derivative function \code{function(x,y,...)}
, tEnd=1 ##<< numeric scalar: end time
, tCut=60 ##<< numeric scalar: number of points of the trajectory
, ... ##<< further arguments to \code{fDeriv}
, tStart=0 ##<< start time
, x0=list( ##<< list of starting positions, such as returned by \code{\link{locator}(2,"p")}, with entries
##describe<<
x=c(1) ##<< numeric vector of x positions
,y=c(1) ##<< numeric vector of y positions
##end<<
)
, color = "black" ##<< colour of the trajectory
, arrowHeads=0.06 ##<< size of the arrow heads (in inches), set t0 0 to avoid
, qArrow = 0.1 ##<< quantile of the timepoints at which an arrow is drawn
, fLapply=lapply ##<< apply function (use \code{sfLapply} for parallel calculation of trajectories)
, fOde=deSolve::lsoda ##<< function to solve the forward problem
) {
##seealso<< \code{\link{phaseArrows}}, \code{\link{pplane}}
#print(paste("Click", loc.num, "initial values"))
#x0 <- locator(loc.num, "p")
func <- function(time, y, parms){
deriv <- parms$fDeriv( y[1], y[2], ... )
list( deriv )
}
#i <- 1
# make vectors the correct length
nTr <- max(sapply( x0, length ))
x <- numeric(nTr); x[] <- x0[[1]]
y <- numeric(nTr); y[] <- x0[[2]]
c(fOde, fDeriv) # evaluate in current context
traj <- fLapply( 1:nTr, function(i){
y <-c(x=x[i], y=y[i])
out <- as.data.frame(fOde(func=func, y=y, parms=list(fDeriv=fDeriv), times = seq(tStart, tEnd, length = tCut)))
})
sapply( traj, function(out){
lines(out$x, out$y, col = color)
iArrow <- round(qArrow*nrow(out))
outn <- out[iArrow+c(0,1),][,-1]
arrows( outn[1,1], outn[1,2], outn[2,1], outn[2,2], length=arrowHeads, col=color )
})
##value<< invisible list of \code{\link{lsoda}} output for each trajectory
return(invisible(traj))
}
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.