rorschach <- read.csv("Rorschach.csv")
print(rorschach)
## X Fear Anger Depression Love Ambition Security
## 1 Bat 33 10 18 1 2 6
## 2 Bear 0 0 2 0 0 0
## 3 Blood 10 5 2 1 0 0
## 4 Boots 0 1 2 0 0 0
## 5 Bridge 1 0 0 0 0 0
## 6 Butterfly 0 2 1 26 5 18
## 7 Cave 7 0 13 1 4 2
## 8 Clouds 2 9 30 4 1 6
## 9 Fire 5 9 1 2 1 1
## 10 Fur 0 3 4 5 5 21
## 11 Hair 0 1 1 2 0 0
## 12 Island 0 0 0 1 0 0
## 13 Mask 3 2 6 2 2 3
## 14 Mountains 2 1 4 1 18 2
## 15 Rocks 0 4 2 1 2 2
## 16 Smoke 1 6 1 0 1 0
# 1. PREPARE DATA
# ----------------
# assume X has columns: Card, Fear, Anger, Depression, Love, Ambition, Security
rownames(rorschach) <- rorschach$X
# species table: four primary emotions
rorsch_species <- rorschach[, c("Fear","Anger","Depression","Love")]
# drop any rows (cards) with all zeros
rorsch_species <- rorsch_species[rowSums(rorsch_species) > 0, ]
# environmental table: secondary variables
rorsch_env <- rorschach[rownames(rorsch_species), c("Ambition","Security")]
# 2. CORRESPONDENCE ANALYSIS
# --------------------------
# run CA
rorsch_ca <- cca(rorsch_species)
# basic plot
plot(rorsch_ca, type = "n", xlim = c(-2, 2), ylim = c(-2, 2))
# add site labels
text(rorsch_ca, display = "sites", labels = rownames(rorsch_species), cex = 0.8)
# add points
points(rorsch_ca, pch = 21, col = "red", bg = "yellow", cex = 1.2)
# add species labels
text(rorsch_ca, display = "species", col = "blue", cex = 0.8)
# fit env vars
fit_ca <- envfit(rorsch_ca, rorsch_env, permutations = 999)
plot(fit_ca, col = "black", lwd = 3)

fit_ca # shows which vectors are significant
##
## ***VECTORS
##
## CA1 CA2 r2 Pr(>r)
## Ambition 0.94241 -0.33446 0.0853 0.627
## Security 0.99855 -0.05376 0.5889 0.070 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Permutation: free
## Number of permutations: 999
# 3. DETRENDED CORRESPONDENCE ANALYSIS
# ------------------------------------
rorsch_dca <- decorana(rorsch_species)
plot(rorsch_dca, type = "n")
text(rorsch_dca, display = "sites", labels = rownames(rorsch_species), cex = 0.8)
points(rorsch_dca, pch = 21, col = "red", bg = "yellow", cex = 0.8)
text(rorsch_dca, display = "species", col = "blue", cex = 0.8)

# optional: tweak number of segments
rorsch_dca2 <- decorana(rorsch_species, mk = 5)
plot(rorsch_dca2, type = "n")
text(rorsch_dca2, display = "sites", labels = rownames(rorsch_species), cex = 0.8)
points(rorsch_dca2, pch = 21, col = "red", bg = "yellow", cex = 0.8)
text(rorsch_dca2, display = "species", col = "blue", cex = 0.8)

# 4. NON-METRIC MDS (Euclidean distance)
# --------------------------------------
# find a 2-D solution
rorsch_mds2 <- metaMDS(rorsch_species, k = 2, distance = "euclidean")
## Wisconsin double standardization
## Run 0 stress 0.1051141
## Run 1 stress 0.1051141
## ... New best solution
## ... Procrustes: rmse 2.828322e-06 max resid 4.821115e-06
## ... Similar to previous best
## Run 2 stress 0.08455158
## ... New best solution
## ... Procrustes: rmse 0.1841046 max resid 0.5189631
## Run 3 stress 0.1593132
## Run 4 stress 0.1051141
## Run 5 stress 0.08455158
## ... Procrustes: rmse 5.64791e-06 max resid 1.573309e-05
## ... Similar to previous best
## Run 6 stress 0.1051141
## Run 7 stress 0.1176256
## Run 8 stress 0.1176256
## Run 9 stress 0.08455158
## ... Procrustes: rmse 1.070532e-05 max resid 2.753626e-05
## ... Similar to previous best
## Run 10 stress 0.1176256
## Run 11 stress 0.08455159
## ... Procrustes: rmse 4.944646e-05 max resid 0.0001366444
## ... Similar to previous best
## Run 12 stress 0.08455158
## ... Procrustes: rmse 6.579794e-06 max resid 1.785269e-05
## ... Similar to previous best
## Run 13 stress 0.1051141
## Run 14 stress 0.1176256
## Run 15 stress 0.08455159
## ... Procrustes: rmse 2.02057e-05 max resid 5.416518e-05
## ... Similar to previous best
## Run 16 stress 0.1176256
## Run 17 stress 0.1051141
## Run 18 stress 0.1852348
## Run 19 stress 0.08455158
## ... Procrustes: rmse 6.146712e-06 max resid 1.700302e-05
## ... Similar to previous best
## Run 20 stress 0.1051141
## *** Best solution repeated 6 times
# quick base plot
plot(rorsch_mds2, type = "t", cex = 1.1)

# more control with ordiplot
# build the empty ordiplot
fig <- ordiplot(rorsch_mds2, type = "none", cex = 1.1)
# add the species labels
text(fig, "species", col = "red", cex = 1.1)
# add the site labels
text(fig, "sites", col = "blue", cex = 0.8)
# overlay envfit
fit_nmds <- envfit(rorsch_mds2, rorsch_env, permutations = 999)
plot(fit_nmds, col = "black", lwd = 3)

fit_nmds
##
## ***VECTORS
##
## NMDS1 NMDS2 r2 Pr(>r)
## Ambition 0.23899 -0.97102 0.0148 0.849
## Security 0.99775 -0.06699 0.1025 0.460
## Permutation: free
## Number of permutations: 999
# 5. SURFACE FITTING WITH SPLINES
# -------------------------------
fig <- ordiplot(rorsch_mds2, type = "none", cex = 1.1, main = "NMDS – Rorschach Data")
text(fig, "species", col = "red", cex = 0.7)
text(fig, "sites", col = "black", cex = 0.7)
# draw env vectors
plot(fit_nmds)
# add spline surfaces
ordisurf(rorsch_mds2, rorsch_env$Ambition, add = TRUE)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## y ~ s(x1, x2, k = 10, bs = "tp", fx = FALSE)
##
## Estimated degrees of freedom:
## 0 total = 1
##
## REML score: 45.13682
ordisurf(rorsch_mds2, rorsch_env$Security, add = TRUE, col = "green4")

##
## Family: gaussian
## Link function: identity
##
## Formula:
## y ~ s(x1, x2, k = 10, bs = "tp", fx = FALSE)
##
## Estimated degrees of freedom:
## 1.69 total = 2.69
##
## REML score: 50.51879
# 6. THREE-DIMENSIONAL NMDS (Euclidean)
# -------------------------------------
# compute 3D NMDS
rorsch_mds3 <- metaMDS(rorsch_species, k = 3, distance = "euclidean")
## Wisconsin double standardization
## Run 0 stress 0
## Run 1 stress 9.482384e-05
## ... Procrustes: rmse 0.008857267 max resid 0.01753358
## Run 2 stress 9.720553e-05
## ... Procrustes: rmse 0.01142188 max resid 0.03005223
## Run 3 stress 9.955727e-05
## ... Procrustes: rmse 0.0133849 max resid 0.03637471
## Run 4 stress 9.514302e-05
## ... Procrustes: rmse 0.01233941 max resid 0.0263258
## Run 5 stress 9.80779e-05
## ... Procrustes: rmse 0.01346913 max resid 0.03685275
## Run 6 stress 9.975342e-05
## ... Procrustes: rmse 0.009873619 max resid 0.02235394
## Run 7 stress 8.945628e-05
## ... Procrustes: rmse 0.01012406 max resid 0.01982804
## Run 8 stress 9.758098e-05
## ... Procrustes: rmse 0.01295526 max resid 0.03132428
## Run 9 stress 0.07304579
## Run 10 stress 0.0003645748
## ... Procrustes: rmse 0.01471358 max resid 0.0403137
## Run 11 stress 0.0003947278
## ... Procrustes: rmse 0.01478234 max resid 0.04167848
## Run 12 stress 9.85796e-05
## ... Procrustes: rmse 0.009441807 max resid 0.0213194
## Run 13 stress 0.0002221011
## ... Procrustes: rmse 0.01363597 max resid 0.03860673
## Run 14 stress 9.368478e-05
## ... Procrustes: rmse 0.009233189 max resid 0.02065845
## Run 15 stress 9.977209e-05
## ... Procrustes: rmse 0.01163461 max resid 0.03046311
## Run 16 stress 9.572783e-05
## ... Procrustes: rmse 0.009561074 max resid 0.02294383
## Run 17 stress 0.07304633
## Run 18 stress 0.07304593
## Run 19 stress 9.796775e-05
## ... Procrustes: rmse 0.01238378 max resid 0.03475706
## Run 20 stress 0.000353623
## ... Procrustes: rmse 0.01440625 max resid 0.03960154
## *** Best solution was not repeated -- monoMDS stopping criteria:
## 4: no. of iterations >= maxit
## 13: stress < smin
## 3: stress ratio > sratmax
## Warning in metaMDS(rorsch_species, k = 3, distance = "euclidean"): stress is
## (nearly) zero: you may have insufficient data
# fit environmental vectors for dimensions 1–3
fit_mds3 <- envfit(rorsch_mds3, rorsch_env, permutations = 999, choices = 1:3)
# 3D ordination plot with arrows
pl3 <- ordiplot3d(rorsch_mds3, envfit = fit_mds3, pch = 19, main = "3D NMDS (Euclidean)")
points(pl3, "points", pch = 16, col = "red", cex = 0.7)
text(pl3, "arrows", col = "blue", pos = 3)
# add species labels in 3D
sp3 <- scores(rorsch_mds3, choices = 1:3, display = "species")
text(pl3$xyz.convert(sp3), rownames(sp3), cex = 0.7, xpd = TRUE)

# compare stress of 2D vs 3D
stressplot(rorsch_mds2, main = "Stressplot 2D")

stressplot(rorsch_mds3, main = "Stressplot 3D")

# 7. NMDS USING BRAY–CURTIS DISTANCE
# ----------------------------------
# default Bray–Curtis NMDS in 2 dimensions
rorsch_mds_bc <- metaMDS(rorsch_species, k = 2)
## Wisconsin double standardization
## Run 0 stress 0.1116559
## Run 1 stress 0.1570399
## Run 2 stress 0.1116559
## ... New best solution
## ... Procrustes: rmse 8.102761e-06 max resid 1.909446e-05
## ... Similar to previous best
## Run 3 stress 0.1111066
## ... New best solution
## ... Procrustes: rmse 0.01974439 max resid 0.06116106
## Run 4 stress 0.06688559
## ... New best solution
## ... Procrustes: rmse 0.1911017 max resid 0.5480701
## Run 5 stress 0.06688561
## ... Procrustes: rmse 0.0002634186 max resid 0.0006529957
## ... Similar to previous best
## Run 6 stress 0.06688553
## ... New best solution
## ... Procrustes: rmse 0.0001126197 max resid 0.0002927313
## ... Similar to previous best
## Run 7 stress 0.15704
## Run 8 stress 0.06688554
## ... Procrustes: rmse 2.592285e-05 max resid 6.879284e-05
## ... Similar to previous best
## Run 9 stress 0.06688555
## ... Procrustes: rmse 5.104569e-05 max resid 0.0001352803
## ... Similar to previous best
## Run 10 stress 0.1111066
## Run 11 stress 0.1111066
## Run 12 stress 0.2068189
## Run 13 stress 0.1372835
## Run 14 stress 0.15704
## Run 15 stress 0.06688559
## ... Procrustes: rmse 0.0001013386 max resid 0.0002659198
## ... Similar to previous best
## Run 16 stress 0.1111066
## Run 17 stress 0.1372835
## Run 18 stress 0.1116559
## Run 19 stress 0.06688555
## ... Procrustes: rmse 6.76235e-05 max resid 0.0001858452
## ... Similar to previous best
## Run 20 stress 0.1116559
## *** Best solution repeated 5 times
# quick scree of stress across dims 1–4
stress_vals <- sapply(1:4, function(d)
metaMDS(rorsch_species, k = d, distance = "bray")$stress
)
## Wisconsin double standardization
## Run 0 stress 0.2039544
## Run 1 stress 0.2021874
## ... New best solution
## ... Procrustes: rmse 0.01756611 max resid 0.05089031
## Run 2 stress 0.2513238
## Run 3 stress 0.3125744
## Run 4 stress 0.3289399
## Run 5 stress 0.5349923
## Run 6 stress 0.330129
## Run 7 stress 0.2030572
## Run 8 stress 0.5159673
## Run 9 stress 0.2018833
## ... New best solution
## ... Procrustes: rmse 0.01046816 max resid 0.02768177
## Run 10 stress 0.3029342
## Run 11 stress 0.3387221
## Run 12 stress 0.3029171
## Run 13 stress 0.3121038
## Run 14 stress 0.3216512
## Run 15 stress 0.3207417
## Run 16 stress 0.2513238
## Run 17 stress 0.3920812
## Run 18 stress 0.2543006
## Run 19 stress 0.3982969
## Run 20 stress 0.378103
## *** Best solution was not repeated -- monoMDS stopping criteria:
## 1: stress ratio > sratmax
## 19: scale factor of the gradient < sfgrmin
## Wisconsin double standardization
## Run 0 stress 0.1116559
## Run 1 stress 0.06688553
## ... New best solution
## ... Procrustes: rmse 0.1887123 max resid 0.547947
## Run 2 stress 0.1111066
## Run 3 stress 0.06688557
## ... Procrustes: rmse 8.931332e-05 max resid 0.0002338569
## ... Similar to previous best
## Run 4 stress 0.06688563
## ... Procrustes: rmse 0.0001451382 max resid 0.0003548361
## ... Similar to previous best
## Run 5 stress 0.0668856
## ... Procrustes: rmse 0.0001157369 max resid 0.0003130171
## ... Similar to previous best
## Run 6 stress 0.06688564
## ... Procrustes: rmse 0.0001768978 max resid 0.0004626383
## ... Similar to previous best
## Run 7 stress 0.06688557
## ... Procrustes: rmse 6.39868e-05 max resid 0.0001770611
## ... Similar to previous best
## Run 8 stress 0.06688556
## ... Procrustes: rmse 6.816399e-05 max resid 0.0001659013
## ... Similar to previous best
## Run 9 stress 0.1570399
## Run 10 stress 0.06688554
## ... Procrustes: rmse 3.126223e-05 max resid 8.290704e-05
## ... Similar to previous best
## Run 11 stress 0.06688555
## ... Procrustes: rmse 5.755777e-05 max resid 0.0001559243
## ... Similar to previous best
## Run 12 stress 0.06688555
## ... Procrustes: rmse 2.199084e-05 max resid 5.566325e-05
## ... Similar to previous best
## Run 13 stress 0.1394338
## Run 14 stress 0.06688554
## ... Procrustes: rmse 1.989108e-05 max resid 5.419757e-05
## ... Similar to previous best
## Run 15 stress 0.06688565
## ... Procrustes: rmse 0.0001441273 max resid 0.0003739288
## ... Similar to previous best
## Run 16 stress 0.1111066
## Run 17 stress 0.1111066
## Run 18 stress 0.06688555
## ... Procrustes: rmse 7.684716e-05 max resid 0.000204921
## ... Similar to previous best
## Run 19 stress 0.1116559
## Run 20 stress 0.06688553
## ... Procrustes: rmse 3.727463e-05 max resid 9.932557e-05
## ... Similar to previous best
## *** Best solution repeated 13 times
## Wisconsin double standardization
## Run 0 stress 0.02868572
## Run 1 stress 0.02868656
## ... Procrustes: rmse 0.0004083708 max resid 0.001188444
## ... Similar to previous best
## Run 2 stress 0.02873228
## ... Procrustes: rmse 0.004220213 max resid 0.01285496
## Run 3 stress 0.02872498
## ... Procrustes: rmse 0.003677402 max resid 0.01118975
## Run 4 stress 0.02866305
## ... New best solution
## ... Procrustes: rmse 0.006842169 max resid 0.02092068
## Run 5 stress 0.02877989
## ... Procrustes: rmse 0.01401928 max resid 0.04301267
## Run 6 stress 0.02873238
## ... Procrustes: rmse 0.01106778 max resid 0.03389779
## Run 7 stress 0.02865938
## ... New best solution
## ... Procrustes: rmse 0.00131359 max resid 0.004013101
## ... Similar to previous best
## Run 8 stress 0.028702
## ... Procrustes: rmse 0.007406573 max resid 0.02266563
## Run 9 stress 0.02869406
## ... Procrustes: rmse 0.006667264 max resid 0.0203044
## Run 10 stress 0.02866153
## ... Procrustes: rmse 0.001861082 max resid 0.00569946
## ... Similar to previous best
## Run 11 stress 0.02867817
## ... Procrustes: rmse 0.004942178 max resid 0.01513631
## Run 12 stress 0.02870996
## ... Procrustes: rmse 0.00808319 max resid 0.02473073
## Run 13 stress 0.02867066
## ... Procrustes: rmse 0.003838365 max resid 0.01175131
## Run 14 stress 0.02866031
## ... Procrustes: rmse 0.000531133 max resid 0.001628663
## ... Similar to previous best
## Run 15 stress 0.02865973
## ... Procrustes: rmse 0.0002690586 max resid 0.0008197836
## ... Similar to previous best
## Run 16 stress 0.02871989
## ... Procrustes: rmse 0.008861811 max resid 0.02711497
## Run 17 stress 0.02867525
## ... Procrustes: rmse 0.004552367 max resid 0.01393937
## Run 18 stress 0.02876407
## ... Procrustes: rmse 0.01124805 max resid 0.03444532
## Run 19 stress 0.02865942
## ... Procrustes: rmse 0.000680353 max resid 0.00186622
## ... Similar to previous best
## Run 20 stress 0.02866039
## ... Procrustes: rmse 0.0005975065 max resid 0.001817526
## ... Similar to previous best
## *** Best solution repeated 6 times
## Wisconsin double standardization
## Run 0 stress 0.01261575
## Run 1 stress 0.01905545
## Run 2 stress 0.0127123
## ... Procrustes: rmse 0.01289386 max resid 0.04102407
## Run 3 stress 0.01190344
## ... New best solution
## ... Procrustes: rmse 0.06503753 max resid 0.2028914
## Run 4 stress 0.01112145
## ... New best solution
## ... Procrustes: rmse 0.02700836 max resid 0.07069003
## Run 5 stress 0.01903925
## Run 6 stress 0.01271357
## Run 7 stress 0.01120128
## ... Procrustes: rmse 0.004608802 max resid 0.01119371
## Run 8 stress 0.0190282
## Run 9 stress 0.01276499
## Run 10 stress 0.01121247
## ... Procrustes: rmse 0.007575308 max resid 0.02098673
## Run 11 stress 0.01904605
## Run 12 stress 0.01261145
## Run 13 stress 0.01108631
## ... New best solution
## ... Procrustes: rmse 0.005151215 max resid 0.01314577
## Run 14 stress 0.01904811
## Run 15 stress 0.01903931
## Run 16 stress 0.01328132
## Run 17 stress 0.01108844
## ... Procrustes: rmse 0.0007368829 max resid 0.002104249
## ... Similar to previous best
## Run 18 stress 0.01164383
## Run 19 stress 0.01263937
## Run 20 stress 0.01264341
## *** Best solution repeated 1 times
plot(1:4, stress_vals, type = "b", lwd = 2,
xlab = "Dimensions", ylab = "Stress",
main = "Stress vs Dimensions (Bray–Curtis)")

# ordination plot
# 1) make a blank ordination plot
plot(rorsch_mds_bc, type = "n", main = "NMDS (Bray–Curtis)")
# 2) extract coordinates
site_scores <- scores(rorsch_mds_bc, display = "sites")
species_scores <- scores(rorsch_mds_bc, display = "species")
# 3) add points
points(site_scores, pch = 21, bg = "yellow", cex = 1)
points(species_scores, pch = 19, cex = 1)
# 4) add labels
text(site_scores, labels = rownames(site_scores), col = "blue", cex = 0.8, pos = 3)
text(species_scores, labels = rownames(species_scores), col = "red", cex = 1.1, pos = 3)
# 5) overlay envfit
fit_bc <- envfit(rorsch_mds_bc, rorsch_env, permutations = 999)
plot(fit_bc, col = "black", lwd = 3)

# 8. SPLINE SURFACES ON BRAY–CURTIS ORDINATION
# --------------------------------------------
fig_bc2 <- ordiplot(rorsch_mds_bc, type = "none",
main = "NMDS (Bray–Curtis) with Splines")
text(fig_bc2, "species", col = "red", cex = 0.8)
text(fig_bc2, "sites", col = "black", cex = 0.8)
plot(fit_bc)
# add ordisurf contours
ordisurf(rorsch_mds_bc, rorsch_env$Ambition, add = TRUE)
##
## Family: gaussian
## Link function: identity
##
## Formula:
## y ~ s(x1, x2, k = 10, bs = "tp", fx = FALSE)
##
## Estimated degrees of freedom:
## 0.0001 total = 1
##
## REML score: 45.13681
ordisurf(rorsch_mds_bc, rorsch_env$Security, add = TRUE, col = "green4")

##
## Family: gaussian
## Link function: identity
##
## Formula:
## y ~ s(x1, x2, k = 10, bs = "tp", fx = FALSE)
##
## Estimated degrees of freedom:
## 1.42 total = 2.42
##
## REML score: 50.57659