Skip to contents

calcPoly calls on the spatial package to fit rectangular spatial polynomial surface models by least-squares, or GLS. These methods allow the user to test whether data have spatial trends in morphospace. Outputs are a polynomial trend surface, and ANOVA table for the model fit. multiPoly applies calcPoly to a fnc_df with outputs for each trait. For more extensive documentation for model fitting see the spatial package.

Usage

calcPoly(fnc, npoly = 3, fnc.name = NULL, 
         gls.covmod = list(covmod = expcov, d = 0.7, alpha = 0, se = 1), 
         pad = 1.2, resample = 100, range = NULL, verbose = FALSE)
                     
multiPoly(fnc_df, npoly = 3, ...)

Arguments

fnc

an XYZ dataframe or matrix of a spatially distributed trait.

fnc_df

a functional dataframe from as_fnc_df with colnames corresponding to X,Y and trait names.

npoly

singular numeric. Degree of polynomial to fit ragning from 1-4. For multiPoly this can also be a vector with length equal to the numer of traits in order to specify the degree of polynomial to apply to each trait.

gls.covmod

Optional list of arguments to pass to surf.gls if fitting by generalized least-squares is desired. Defaults to NULL, and fitting is performed by least-squares. See surf.gls and expcov documentation for a full list of arguments and usage.

fnc.name

Optional speficiation of the trait name. Defaults to NULL, and will use column names instead.

pad

Degree by which to extrapolate input data. Defaults to 1.2.

resample

Resampling density. Corresponds to the number of points calculated along both X and Y axes. Defaults to 100. If no resampling is desired, set reample = NULL

range

Optional. Manually set X and Y ranges. Input is a 2x2 matrix with rows corresponding to X and Y ranges respectively.

verbose

Optional. Logical. If TRUE, will print ANOVA tables.

...

Arguments to pass onto calcPoly when using multiPoly

Details

Fits polynomial trend surfaces using the `spatial` package. First, an npoly polynomial trend surface is fit by least squares using surf.ls or generalized least-squares by surf.gls. GLS is fit by one of three covariance functions, exponential (expcov), gaussian (gaucov) or spherical (sphercov) and requires additional parameters to be passed as a list through gls.covmod (see examples). For a full description of arguments and usage see surf.gls and expcov documentation.

The surface is then evaluated using trmat within limits set by input data, or manually using range.

Value

An object of class poly_surf, or multi_surf with the following components:

fnc.name

name of trait

poly

Polynomial trend fit output from surf.ls

surface

Evaluated trend surface output from trmat

grid

Expanded surface in long XZY dataframe format

peak

Coordinates and height of the peak of the surface

References

Dickson, B.V. and Pierce, S.E. (2019), Functional performance of turtle humerus shape across an ecological adaptive landscape. Evolution, 73: 1265-1277. https://doi.org/10.1111/evo.13747

Author

Blake V. Dickson

See also

Examples

require(spatial)
#> Loading required package: spatial

data("warps")
warps_fnc <- as_fnc_df(warps)

# Make single trait dataframe 
hydro_fnc <- data.frame(warps_fnc[ ,1:2], warps_fnc[ ,"hydro"])

polysurf <- calcPoly(hydro_fnc)
summary(polysurf)
#> - warps_fnc....hydro.. 
#> npoly:  3 
#> peak:  
#>           x           y           z 
#> -0.07422549 -0.04639033  1.00000000 
#> 
#> Analysis of Variance Table
#>  Model: (function (np, covmod, x, y, z, nx = 1000, ...) {    if (np > 6)         stop("'np' exceeds 6")    if (is.data.frame(x)) {        if (any(is.na(match(c("x", "y", "z"), names(x)))))             stop("'x' does not have columns 'x', 'y' and 'z'")        if (missing(y))             y <- x$y        if (missing(z))             z <- x$z        x <- x$x    }    rx <- range(x)    ry <- range(y)    .C(VR_frset, as.double(rx[1L]), as.double(rx[2L]), as.double(ry[1L]),         as.double(ry[2L]))    covmod <- covmod    arguments <- list(...)    if (length(arguments)) {        onames <- names(formals(covmod))        pm <- pmatch(names(arguments), onames, nomatch = 0L)        if (any(pm == 0L))             warning("some of '...' do not match")        names(arguments[pm > 0L]) <- onames[pm]        oargs <- formals(covmod)        oargs[pm] <- arguments[pm > 0L]        formals(covmod) <- oargs    }    mm <- 1.5 * sqrt((rx[2L] - rx[1L])^2 + (ry[2L] - ry[1L])^2)    alph <- c(mm/nx, covmod(seq(0, mm, mm/nx)))    .C(VR_alset, as.double(alph), as.integer(length(alph)))    n <- length(x)    npar <- ((np + 1) * (np + 2))/2    f <- .spfmat(x, y, np)    Z <- .C(VR_gls, as.double(x), as.double(y), as.double(z),         as.integer(n), as.integer(np), as.integer(npar), as.double(f),         l = double((n * (n + 1))/2), r = double((npar * (npar +             1))/2), beta = double(npar), wz = double(n), yy = double(n),         W = double(n), ifail = 0L, l1f = double(n * npar))    if (Z$ifail > 0L)         stop("rank failure in Choleski decomposition")    if (nx > 1000L)         alph <- alph[1L]    res <- list(x = x, y = y, z = z, np = np, f = f, alph = alph,         l = Z$l, r = Z$r, beta = Z$beta, wz = Z$wz, yy = Z$yy,         W = Z$W, l1f = Z$l1f, rx = rx, ry = ry, covmod = covmod,         call = match.call())    class(res) <- c("trgls", "trls")    res})(np = 3, covmod = function (r, d, alpha = 0, se = 1) {    se^2 * (alpha * (r < d/10000) + (1 - alpha) * exp(-r/d))}, x = c(`1` = -0.189222674092978, `2` = -0.189222674092978, `3` = -0.189222674092978, `4` = -0.189222674092978, `5` = -0.133845239206066, `6` = -0.133845239206066, `7` = -0.133845239206066, `8` = -0.133845239206066, `9` = -0.0784678043191536, `10` = -0.0784678043191536, `11` = -0.0784678043191536, `12` = -0.0784678043191536, `13` = -0.0230903694322413, `14` = -0.0230903694322413, `15` = -0.0230903694322413, `16` = -0.0230903694322413, `17` = 0.032287065454671, `18` = 0.032287065454671, `19` = 0.032287065454671, `20` = 0.032287065454671, `21` = 0.0876645003415833, `22` = 0.0876645003415833, `23` = 0.0876645003415833, `24` = 0.0876645003415833), y = c(`1` = -0.0516138896365427, `2` = -0.00363138024603597, `3` = 0.0443511291444708, `4` = 0.0923336385349775, `5` = -0.0516138896365427, `6` = -0.00363138024603597, `7` = 0.0443511291444708, `8` = 0.0923336385349775, `9` = -0.0516138896365427, `10` = -0.00363138024603597, `11` = 0.0443511291444708, `12` = 0.0923336385349775, `13` = -0.0516138896365427, `14` = -0.00363138024603597, `15` = 0.0443511291444708, `16` = 0.0923336385349775, `17` = -0.0516138896365427, `18` = -0.00363138024603597, `19` = 0.0443511291444708, `20` = 0.0923336385349775, `21` = -0.0516138896365427, `22` = -0.00363138024603597, `23` = 0.0443511291444708, `24` = 0.0923336385349775), z = c(`1` = 0.763499188437312, `2` = 0.627384654347192, `3` = 0.486816967049923, `4` = 0.174142264485349, `5` = 0.857732301856784, `6` = 0.752332848053817, `7` = 0.492353717916519, `8` = 0.276414894820345, `9` = 1, `10` = 0.845494217913583, `11` = 0.642508934612232, `12` = 0.38984057122137, `13` = 0.995858044607531, `14` = 0.821012732300195, `15` = 0.471898305561689, `16` = 0.243166139196157, `17` = 0.879545728740752, `18` = 0.701083365008891, `19` = 0.349124619048563, `20` = 0.0758538303088942, `21` = 0.511206057156924, `22` = 0.661975028175644, `23` = 0.281357500482196, `24` = 0), d = 0.7, alpha = 0, se = 1)
#>                Sum Sq Df     Mean Sq  F value     Pr(>F)
#> Regression 1.80378676  9 0.200420751 31.79593 8.4249e-08
#> Deviation  0.08824683 14 0.006303345                    
#> Total      1.89203360 23                                
#> Multiple R-Squared: 0.9534,	Adjusted R-squared: 0.9234 
#> AIC: (df = 10) -114.5361
#> Fitted:
#>     Min      1Q  Median      3Q     Max 
#> 0.02863 0.30283 0.55810 0.80552 0.99446 
#> Residuals:
#>      Min       1Q   Median       3Q      Max 
#> -0.10958 -0.04286 -0.02556  0.01876  0.11254 
#> 
plot(polysurf)

# Fit using gls

polysurf <- calcPoly(hydro_fnc, gls.covmod = list(covmod = expcov, d = 0.7, alpha = 0, se = 1))
if (FALSE) {
summary(polysurf)
}
plot(polysurf)


# Calculate multiple polynomial surfaces

multi_poly <- multiPoly(warps_fnc)
#> polynomials:
#> hydro curve  mech   fea 
#>     3     3     3     3 
if (FALSE) {
summary(multi_poly)
}
plot(multi_poly)


# Set manual range

polysurf <- calcPoly(hydro_fnc, range = rbind(range(warps_fnc$x) * 1.2,
                                              range(warps_fnc$y) * 1.4))
                                              
polysurf <- calcPoly(hydro_fnc, range = rbind(c(-0.2, 0.12),
                                              c(-0.06, 0.1)) )
if (FALSE) {
summary(polysurf)
}                                              
# 
# Adjust polynomial degree

multiPoly(warps_fnc, npoly = 2)
#> polynomials:
#> hydro curve  mech   fea 
#>     2     2     2     2 
#> A multi_poly object
#> - functional characteristics:
#> 	hydro, curve, mech, fea

# Specify multiple degrees

multi_poly <- multiPoly(warps_fnc, npoly = c(2,3,4,3))
#> polynomials:
#> [1] 2 3 4 3

if (FALSE) {
summary(polysurf)
}
plot(polysurf)