Tests correlations between distance matrices (e.g. distance in species composition vs. environmental or geographical distance). Significance can be calculated by randomizations since the distance matrix is not a set of independent values.
library(vegan)
load("community.rda")
De=dist(soil.data$pH.KCl) ## calculates Euclidean distance beteen soil pH values
Dv=vegdist(log1p(vas.plants),method="euclidean") # vegetation distance
plot(De,Dv) # all pairwise combinations, for n sites n*(n-1)/2
mantel(De,Dv) # p value from randomizations
##
## Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel(xdis = De, ydis = Dv)
##
## Mantel statistic r: 0.2568
## Significance: 0.008
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.136 0.181 0.220 0.251
## Permutation: free
## Number of permutations: 999
library(sp) # for spatial analyses, real metric distance between lon-lat
Dxy=as.dist(spDists(as.matrix(xy[,1:2]),longlat=T))
# correllograms with space
m.c1=mantel.correlog(De,Dxy)
m.c2=mantel.correlog(Dv,Dxy)
plot(m.c1)
plot(m.c2)
# Correlation vs. distance. Empty symbols are not significant.
plot(mantel.correlog(Dv,De)) # Distance in soil pH vs vegetation
# We can use partial mantel tests to take account the third distance matrix
mantel.partial(De,Dv,Dxy)
##
## Partial Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel.partial(xdis = De, ydis = Dv, zdis = Dxy)
##
## Mantel statistic r: 0.2578
## Significance: 0.005
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.127 0.172 0.200 0.228
## Permutation: free
## Number of permutations: 999
Make a graph to explore how real distance between points differ from Euclidean distance calculated from raw latitude and longitude.
plot(Dxy, dist(xy[,-3]))
A useful method to see how much variation in species composition is described by some other variable groups. Can also calculate how much variation different variables describe jointly.
# Making a table space with squares and products. This can describe spatial pattern
space=xy[,-3]
space$x2=space$lon**2
space$y2=space$lat**2
space$xy=space$lon*space$lat
vp.o=varpart(vegdist(vas.plants,"bray"),soil.data$pH.KCl,soil.data[,2:4],space)
showvarparts(3)
plot(vp.o,bg=2:4,Xnames=c("pH","Nutrients","Space"))
Using data from DroughtNet, an international collaboration. Three years 6 permanent plots are recorded. Half of them are control, another half drought treament (rain shadow excludes ca 50% or rainfall)
temp=read.table("droughtnet.txt",stringsAsFactors = F) # long data format
# Plots 1,3,5 are drought treatment
temp[1:10,]
## plot taxa cover date
## 1 1 Achillea_millefolium 3 01-07-15
## 2 1 Anthoxanthum_odoratum 1 01-07-15
## 3 1 Avenula_pubescens 5 01-07-15
## 4 1 Briza_media 20 01-07-15
## 5 1 Campanula_patula 2 01-07-15
## 6 1 Cerastium_arvense 1 01-07-15
## 7 1 Dactylis_glomerata 5 01-07-15
## 8 1 Equisetum_arvense 1 01-07-15
## 9 1 Festuca_pratensis 1 01-07-15
## 10 1 Festuca_rubra 2 01-07-15
temp$year_plot=paste0(substring(temp$date,7,8),"-",temp$plot)
temp=as.data.frame.matrix(xtabs(cover~year_plot+taxa,data=temp))
ord=metaMDS(log1p(temp),"manhattan",2)
## Run 0 stress 0.210736
## Run 1 stress 0.2161235
## Run 2 stress 0.2458476
## Run 3 stress 0.2265871
## Run 4 stress 0.2189891
## Run 5 stress 0.2320847
## Run 6 stress 0.210736
## ... Procrustes: rmse 6.886996e-05 max resid 0.0002606918
## ... Similar to previous best
## Run 7 stress 0.2746193
## Run 8 stress 0.2106909
## ... New best solution
## ... Procrustes: rmse 0.02954776 max resid 0.1347751
## Run 9 stress 0.2400829
## Run 10 stress 0.2170666
## Run 11 stress 0.2106907
## ... New best solution
## ... Procrustes: rmse 0.0001966733 max resid 0.0008297866
## ... Similar to previous best
## Run 12 stress 0.2434451
## Run 13 stress 0.2170667
## Run 14 stress 0.2351685
## Run 15 stress 0.2562188
## Run 16 stress 0.210736
## ... Procrustes: rmse 0.02953941 max resid 0.1339546
## Run 17 stress 0.2545797
## Run 18 stress 0.2106907
## ... New best solution
## ... Procrustes: rmse 3.933951e-05 max resid 0.0001613128
## ... Similar to previous best
## Run 19 stress 0.210736
## ... Procrustes: rmse 0.02955329 max resid 0.1339921
## Run 20 stress 0.2332111
## *** Best solution repeated 1 times
plot(scores(ord)$sites,type="n")
points(ord,"sites",pch=16,col=c("red","blue"))
row.names(temp)
## [1] "15-1" "15-2" "15-3" "15-4" "15-5" "15-6" "16-1" "16-2" "16-3" "16-4"
## [11] "16-5" "16-6" "17-1" "17-2" "17-3" "17-4" "17-5" "17-6" "18-1" "18-2"
## [21] "18-3" "18-4" "18-5" "18-6" "19-1" "19-2" "19-3" "19-4" "19-5" "19-6"
for(i in 1:6) {
n=which(grepl(paste0("-",i),row.names(temp)))
for(j in 1:(length(n)-1)) {
arrows(scores(ord)$sites[n[j],1],scores(ord)$sites[n[j],2],
scores(ord)$sites[n[j+1],1],scores(ord)$sites[n[j+1],2],length=0.1,angle=20,
col=ifelse(i%%2==1,"red","blue"))}
# i%%2 is looking if i is odd or even
}
Dv=vegdist(log1p(temp),method="manhattan")
treatment=as.numeric(substring(row.names(temp),4,4))%%2==1
year=as.numeric(substring(row.names(temp),1,2))
space=as.numeric(substring(row.names(temp),4,4))
ev=envfit(ord,data.frame(drought=as.numeric(treatment),year,space))
ev
##
## ***VECTORS
##
## NMDS1 NMDS2 r2 Pr(>r)
## drought -0.43570 0.90009 0.0809 0.314
## year 0.99723 -0.07438 0.4217 0.002 **
## space -0.23126 -0.97289 0.5315 0.001 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Permutation: free
## Number of permutations: 999
plot(ord,type="n")
points(ord,"sites",pch=16,col="red")
plot(ev,col="green")
## Let's study more with distances!
De=dist(treatment) ## calculates treatment distance
Dt=dist(year) ## temporal distance
Dp=log1p(dist(space)) ## spatial distance (plots 1...6 in row)
plot(De,Dv) # all pairwise combinations, for n sites n*(n-1)/2
mantel(Dv,De) # p value from randomizations
##
## Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel(xdis = Dv, ydis = De)
##
## Mantel statistic r: 0.1696
## Significance: 0.002
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.0448 0.0581 0.0788 0.0975
## Permutation: free
## Number of permutations: 999
mantel(Dv,Dt) # p value from randomizations
##
## Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel(xdis = Dv, ydis = Dt)
##
## Mantel statistic r: 0.2629
## Significance: 0.001
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.0864 0.1165 0.1451 0.1653
## Permutation: free
## Number of permutations: 999
mantel(Dv,Dp) # p value from randomizations
##
## Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel(xdis = Dv, ydis = Dp)
##
## Mantel statistic r: 0.3485
## Significance: 0.001
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.0682 0.0898 0.1057 0.1227
## Permutation: free
## Number of permutations: 999
mantel.partial(Dv,De,Dp)
##
## Partial Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel.partial(xdis = Dv, ydis = De, zdis = Dp)
##
## Mantel statistic r: 0.1322
## Significance: 0.005
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.0449 0.0611 0.0849 0.1049
## Permutation: free
## Number of permutations: 999
mantel.partial(Dv,De,Dt)
##
## Partial Mantel statistic based on Pearson's product-moment correlation
##
## Call:
## mantel.partial(xdis = Dv, ydis = De, zdis = Dt)
##
## Mantel statistic r: 0.1892
## Significance: 0.001
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.0489 0.0670 0.0852 0.0945
## Permutation: free
## Number of permutations: 999
# Variance partitioning using distances
plot(varpart(Dv,De,Dp,Dt),bg=2:4,Xnames=c("Treatment","Space","Time"))
## Warning: collinearity detected in X1: mm = 30, m = 1
## Warning: collinearity detected in X2: mm = 30, m = 5
## Warning: collinearity detected in X3: mm = 30, m = 4
## Warning: collinearity detected in cbind(X1,X2): mm = 60, m = 5
## Warning: collinearity detected in cbind(X1,X3): mm = 60, m = 5
## Warning: collinearity detected in cbind(X2,X3): mm = 60, m = 9
## Warning: collinearity detected in cbind(X1,X2,X3): mm = 90, m = 9
## Constrained ordination cca
o.temp=cca(temp~treatment+year)
anova(o.temp,by="mar")
## Permutation test for cca under reduced model
## Marginal effects of terms
## Permutation: free
## Number of permutations: 999
##
## Model: cca(formula = temp ~ treatment + year)
## Df ChiSquare F Pr(>F)
## treatment 1 0.05855 2.1117 0.007 **
## year 1 0.08305 2.9951 0.001 ***
## Residual 27 0.74866
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Conditioning out (removing) the effect of space
o.temp=cca(temp~treatment+year+Condition(space))
anova(o.temp,by="mar")
## Permutation test for cca under reduced model
## Marginal effects of terms
## Permutation: free
## Number of permutations: 999
##
## Model: cca(formula = temp ~ treatment + year + Condition(space))
## Df ChiSquare F Pr(>F)
## treatment 1 0.07133 2.8329 0.001 ***
## year 1 0.08141 3.2333 0.001 ***
## Residual 26 0.65465
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
plot(o.temp)
# Analysis of variance based on dissimilarity, treatment, year and interactions,
adonis2(Dv~treatment*year*space)
## Permutation test for adonis under reduced model
## Terms added sequentially (first to last)
## Permutation: free
## Number of permutations: 999
##
## adonis2(formula = Dv ~ treatment * year * space)
## Df SumOfSqs R2 F Pr(>F)
## treatment 1 484.7 0.09801 4.7200 0.001 ***
## year 1 598.5 0.12100 5.8274 0.001 ***
## space 1 665.2 0.13449 6.4768 0.001 ***
## treatment:year 1 49.1 0.00992 0.4779 0.900
## treatment:space 1 683.4 0.13818 6.6548 0.001 ***
## year:space 1 55.3 0.01117 0.5382 0.862
## treatment:year:space 1 150.3 0.03040 1.4638 0.150
## Residual 22 2259.4 0.45682
## Total 29 4945.8 1.00000
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# same but randomizing within plot id ("space")
adonis2(Dv~treatment*year, strata=space)
## Permutation test for adonis under reduced model
## Terms added sequentially (first to last)
## Blocks: strata
## Permutation: free
## Number of permutations: 999
##
## adonis2(formula = Dv ~ treatment * year, strata = space)
## Df SumOfSqs R2 F Pr(>F)
## treatment 1 484.7 0.09801 3.3048 0.001 ***
## year 1 598.5 0.12100 4.0802 0.001 ***
## treatment:year 1 49.1 0.00992 0.3346 0.800
## Residual 26 3813.6 0.77106
## Total 29 4945.8 1.00000
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
R is a very powerful gis program.
library(maps) # global maps
map("world")
map("world",fill=T,col="grey",xlim=c(-25,40),ylim=c(35,70))
map("world",fill=T,col="grey",xlim=c(-25,40),ylim=c(35,70),border=F)
box()
## R reading mapinfo and shape (ArcInfo) files
library(rgdal)
maa=readOGR("eesti reljeef.tab")
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## Warning: OGR support is provided by the sf and terra packages among others
## OGR data source with driver: MapInfo File
## Source: "C:\Users\Carlos Perez Carmona\Dropbox\Courses\DataAnalysisCommunityEcology\2023-2024\Data\eesti reljeef.tab", layer: "eesti reljeef"
## with 17 features
## It has 2 fields
plot(maa)
## Warning in is.projected(p4str): Package sf not available
plot(maa,col="grey",border=F)
## Warning in is.projected(p4str): Package sf not available
plot(maa,col=terrain.colors(17)[rank(maa$ID)],border=F)
## Warning in is.projected(p4str): Package sf not available
box()
# latitude and longitude need to be transformed to x and y
coord=xy[,-3]
coordinates(coord)= c("lon","lat")
proj4string(coord) = CRS("+proj=longlat")
## Warning in CRS("+proj=longlat"): sf required for evolution_status==2L
coord=spTransform(coord,CRS(proj4string(maa)))
## Warning in CRS(proj4string(maa)): sf required for evolution_status==2L
## Warning in spTransform(coord, CRS(proj4string(maa))): NULL source CRS comment,
## falling back to PROJ string
## Warning in spTransform(coord, CRS(proj4string(maa))): NULL target CRS comment,
## falling back to PROJ string
## Warning in is.projected(p4str): Package sf not available
points(coord,cex=0.5)
# Another gis package for raster data
library(raster)
est=raster::getData("alt", country="EST", mask=T)
## Warning in raster::getData("alt", country = "EST", mask = T): getData will be removed in a future version of raster
## . Please use the geodata package instead
## Warning in sp::CRS(...): sf required for evolution_status==2L
## Warning in sp::CRS(...): sf required for evolution_status==2L
plot(est,col="green")
hist(est) # histogram of raster values
## Warning in .hist1(x, maxpixels = maxpixels, main = main, plot = plot, ...): 44%
## of the raster cells were used. 100000 values used.
plot(est>20) # Estonia land >20 m above the sea level
# Baltic countries
lat=raster::getData("alt", country="LVA", mask=T)
## Warning in raster::getData("alt", country = "LVA", mask = T): getData will be removed in a future version of raster
## . Please use the geodata package instead
lit=raster::getData("alt", country="LTU", mask=T)
## Warning in raster::getData("alt", country = "LTU", mask = T): getData will be removed in a future version of raster
## . Please use the geodata package instead
plot(merge(est,lat,lit),col=terrain.colors(286)) # merging all three countries
points(xy[,-3],cex=0.5) ## this raster map uses lat and lon
elev=raster::extract(est,xy[,-3]) # extracting values for our coordinates
elev
## [1] 66 65 77 78 51 55 91 33 56 42 40 47 50 106 100 42 99 109 46
## [20] 42 44 114 96 53 79 87 110 80 54 131
Raster package has also current climate data and future climate predictions. It is a powerful GIS software.