What is ordisurf() doing…?
Want to share your content on Rbloggers? click here if you have a blog, or here if you don't.
I’m writing this post for two reasons: i) someone searched on Google for the term ‘what is ordisurf doing’ and ended up on my blog, and ii) because I have been on the receiving end of reviewers comments on a paper I coauthored where they didn’t know what ordisurf()
was doing either! It is hardly surprising that people who don’t know R or haven’t studied the code or the examples in the vegan documentation do not realise what ordisurf()
is trying to do as there isn’t a paper in the scientific literature explaining the method. Whilst a solution to that part of the problem will have to wait until Jari, Dave Roberts and I get our acts together and write one, this post might be useful in the interim.
Before direct gradient analysis or canonical ordination was invented/used in ecology, the standard approach to analysing multivariate ecological data was to ordinate them using PCA or CA, for example, and then relate the separate, important axes of that ordination with a set of environmental variables. A multiple regression was often used to relate the two, with ordination axis score taken as the response variable and the set of environmental variables as the predictors. This is problematic for methods like nMDS that don’t have axes, where we should consider the k dimensions of the solution as a whole rather than as independent “axes” of variation, which is where ordisurf()
comes in.
So we have something tangible to work with in the ensuing discussion, lets fit a simple PCA to the classic Dutch Dune Meadows data set, available in vegan, and display the resulting biplot
For these data the main continuous, quantitative variable is A1
, the thickness of the soil A1 horizon. The envfit()
can be used to project a biplot arrow for this variable into the ordination
The result of the vector fitting is shown below, indicating borderline significance for the A1 horizon
As this is an unconstrained ordination, there is no reason at all to assume that the values of the A1 horizon vary in a linear fashion across the biplot. Instead, it might be better to fit a smooth response surface of A1 values over the limits of the biplot. For that we use ordisurf()
.
Combining all the various plotting elements thus far we get this figure
The fitted surface is far from linear! The object returned by ordisurf()
is an augments object of class “gam”
from the mgcv package, so we can use methods from that package to interrogate the result
Here we also see that there is little evidence to reject the null hypothesis. So what is ordisurf()
actually doing? It is doing nothing more than fitting the following model using the gam()
function
Line 1 loads the mgcv package. In line 2 we extract the site scores on PCA axes 1 and 2 using symmetric scaling (scaling = 3
) and convert to a data frame. Then we columnbind the soil A1 horizon thickness data into object dat
, which we can pass as the data
object in the call to gam()
. The final line of code (line 4) fits the response surface model using a model formula and a 2D smooth on the PCA axis 1 and 2 sites scores. We restrict the complexity of this smooth using k = 10
as there are only 14 unique values for A1
and the default were starting with a smooth with more degrees of freedom than unique data points.
It should now be clear that we fit a model to predict the soil A1 horizon thickness using a 2D smooth of the PCA site scores on axes 1 and 2 as the predictor variable. This is backwards to how we might conventionally think of the problem of relating explanatory variables to ordination axes, but it is logical if you think of the model as saying “given the main pattern in the species composition described by ordination axes, how well does this pattern explain variation in response variable at the sites.”
In newer versions of vegan (>= 1.179) we now provide access to more of the functionality provided by Simon Wood’s mgcv package for fitting GAMs:

you can alter the penalty used in the GCV routine that selects the degree of smoothness in the fitted smooth function (the response surface) via argument
penalty
. A penalty of 1.4 degrees of freedom per knot is often suggested if greater penalty on complex smooths is desired (penalty = 1.4
); 
ordisurf()
now accepts themethod
argument ofgam()
. Simon’s latest advice to me was that doing the smoothness selection via Marginal (Maximum) Likelihood (ML) or Restricted Maximum Likelihood (REML) gave the most reliable pvalues on the smooth functions. To use this form of model fitting instead of GCV, supplymethod = “ML”
ormethod = “REML”
in theordisurf()
call; 
By default,
gam()
can penalize smooths back to linear functions/surfaces but no further. An additional penalty term can be added to the smoothness selection procedure so that smooths can be penalised all the way back to zero degrees of freedom, effectively removing those terms from the model. This is a formal means of model selection. To turn this feature on, addselect = TRUE
to theordisurf()
call.
As a final illustration, we compare the response surface fitted earlier with one fitted using ML smoothness selection and the extra penalty term
We get a similar pattern to before
but the surface is a lot less complex using approximately 4.5 degrees of freedom compared with approximately 8.7 in dune.sf
. This doesn’t alter our interpretation of the significance of the relationship between the plant composition and A1 horizon thickness, however.
It remains to be seen whether we can trust the pvalues that mgcv provides for predictor data derived from an ordination. Preliminary simulations that Jari Oksanen and I have made suggest the pvalues have the right Type I error rate when we use randomly generated data with no relationship to the ordination axes. However, we have only just started this work and those are the sorts of results that are best presented for peer review and not relegated to a blog post. I hope that goes some way to explaining what on Earth it is that ordisurf()
does…
Rbloggers.com offers daily email updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/datascience job.
Want to share your content on Rbloggers? click here if you have a blog, or here if you don't.