Lab 2b. Environmental Distance
This material must be reviewed by BCB743 students in Week 1 of Quantitative Ecology.
- Example xyz data –
Euclidean_distance_demo_data_xyz.csv - Example env data –
Euclidean_distance_demo_data_env.csv - The seaweed environmental data (Smit et al. 2017) –
SeaweedEnv.RData - The seaweed coastal sections (sites) –
SeaweedSites.csv - The Doubs River environmental data –
DoubsEnv.csv
“It’s not that I’m so smart, it’s just that I stay with problems longer.”
— Albert Einstein
Set up the Analysis Environment
Revisiting Euclidean Distance
The toy data have arbitrary columns to demonstrate the Euclidean distance calculation:
\[ d(a,b) = \sqrt{(a_x - b_x)^2 + (a_y - b_y)^2 + (a_z - b_z)^2} \]
The distance is found between every pair of sites named a to g whose locations are marked by the ‘coordinates’ \(x\), \(y\), and \(z\)—i.e. this is an example of 3-dimensional data (a space or volume, as opposed to 2D data situated on a \(x\), \(y\) place). We might also call each coordinate a ‘variable’ (sometimes called a ‘dimension’) and hence we have multivariate or multidimensional data.
Let’s load the dataset and find the size of the dataframe:
[1] 7 4
There are seven rows and four columns.
The data look like:
The first column contains the site names and it must be excluded from subsequent calculations. The remaining three columns will be used below.
Calculate the Euclidean distance using vegan’s vegdist() function and view the lower triangle with the diagonal:
1 2 3 4 5 6 7
1 0.0000
2 4.5826 0.0000
3 5.4772 1.7321 0.0000
4 7.3485 5.7446 7.3485 0.0000
5 5.7446 4.6904 6.4031 1.7321 0.0000
6 4.8990 5.3852 4.6904 10.6771 9.2195 0.0000
7 5.3852 5.6569 5.9161 9.4340 7.8740 4.5826 0.0000
Convert to a dataframe and view it:
1 2 3 4 5 6 7
1 0.0000 4.5826 5.4772 7.3485 5.7446 4.8990 5.3852
2 4.5826 0.0000 1.7321 5.7446 4.6904 5.3852 5.6569
3 5.4772 1.7321 0.0000 7.3485 6.4031 4.6904 5.9161
4 7.3485 5.7446 7.3485 0.0000 1.7321 10.6771 9.4340
5 5.7446 4.6904 6.4031 1.7321 0.0000 9.2195 7.8740
6 4.8990 5.3852 4.6904 10.6771 9.2195 0.0000 4.5826
7 5.3852 5.6569 5.9161 9.4340 7.8740 4.5826 0.0000
Distance matrices have the same properties as dissimilarity matrices, i.e.:
The distance matrix is square (number rows = number columns).
The diagonal is filled with 0.
The matrix is symmetrical—it is comprised of symmetrical upper and lower triangles.
In terms of the meaning of the cell values, their interpretation is also analogous with that of the species dissimilarities. A value of 0 means the properties of the sites (or sections, plots, transects, quadrats, etc.) in terms of their environmental conditions are identical (this is always the case the the diagonal). The larger the number (which may be >1) the more different sites are in terms of their environmental conditions.
Since each column, \(x\), \(y\), and \(z\), is a variable, we can substitute them for actual variables or properties of the environment within which species are present. Let’s load such data (again fictitious):
site temperature depth light
1 a 4 1 3
2 b 5 5 5
These are the same data as in Euclidean_distance_demo_data_xyz.csv but I simply renamed the columns to names of the variables temperature, depth, and light intensity. I won’t repeat the analysis here as the output remains the same.
Now apply vegdist() as before. The resultant distances are called ‘environmental distances’.
Let us now use some real data.
A Look at the Seaweed Environmental Data
These data accompany the analysis of the South African seaweed flora (Smit et al. 2017).
[1] 58 18
We see that the data have 58 rows and 18 columns… the same number of rows as the seaweed.csv data. What is in the first five rows?
febMean febMax febMed febX95 febRange
1 13.0012 18.7204 12.6600 16.8097 6.0703
2 13.3795 18.6190 13.1839 17.0724 5.8893
3 13.3616 17.8646 13.2319 16.6111 5.4314
4 13.2897 17.1207 13.1028 16.1214 5.0490
5 12.8113 16.3783 12.4003 15.5324 4.9779
And the last five rows?
annRange febSD augSD annChl augChl febChl
53 4.3707 1.0423 0.7735 4.3420 4.3923 4.6902
54 4.3358 1.1556 0.9104 1.6469 2.2654 1.6930
55 4.4104 1.1988 0.8427 0.2325 0.6001 0.5422
56 4.6089 1.1909 0.6631 0.1321 0.4766 0.3464
57 4.9693 1.1429 0.4994 0.1339 0.5845 0.3185
58 5.5743 1.0000 0.3494 0.1486 0.7363 0.4165
So, each of the rows corresponds to a site (i.e. each of the coastal sections), and the columns each contains an environmental variable. The names of the environmental variables are:
[1] "febMean" "febMax" "febMed" "febX95" "febRange" "augMean"
[7] "augMin" "augMed" "augX5" "augRange" "annMean" "annSD"
[13] "annRange" "febSD" "augSD" "annChl" "augChl" "febChl"
As we have seen, there are 18 variables (or dimensions). These data are truly multidimensional in a way that far exceeds our brains’ limited ability to spatially visualise. For mathematicians these data define an 18-dimensional space, but all we can do is visualise 3-dimensions.
We select only some of the thermal variables; the rest are collinear with some of the ones I import:
Let us make a quick graph of annMean as a function of distance along the coast (Figure 1).
z-Scores
Here we need to do something new that was not necessary with the toy data. We calculate z-scores, and the process is called ‘standardisation’. Standardisation is necessary when the variables are measured in different units—e.g. the unit for temperature is °C whereas Ch-a is measured in mg Chl-a/m3.
febMean febRange febSD augMean augRange
1 -1.4915 -0.0443 -0.2713 -1.3765 -0.4735
2 -1.4014 -0.1432 -0.1084 -1.4339 -0.0700
3 -1.4057 -0.3932 -0.1720 -1.5269 0.0248
4 -1.4228 -0.6020 -0.3121 -1.5797 -0.0508
5 -1.5368 -0.6408 -0.4096 -1.5464 -0.0983
For comparison with the previous plot showing the raw data, let us now plot the standardised annMean data (Figure 2).
Euclidean Distance
1 2 3 4 5 6 7 8 9 10
1 0.0000 0.7040 1.0006 1.1132 0.9902 0.9124 0.7849 0.7957 2.7901 2.0327
2 0.7040 0.0000 0.3769 0.6126 0.6553 0.7726 0.6291 0.5565 2.2733 1.7509
3 1.0006 0.3769 0.0000 0.2818 0.4729 0.7594 0.7164 0.7939 2.2692 1.8055
4 1.1132 0.6126 0.2818 0.0000 0.3662 0.7566 0.7911 0.9708 2.4523 1.9019
5 0.9902 0.6553 0.4729 0.3662 0.0000 0.4094 0.5261 0.9860 2.4847 2.1376
6 0.9124 0.7726 0.7594 0.7566 0.4094 0.0000 0.2862 1.0129 2.4449 2.3483
7 0.7849 0.6291 0.7164 0.7911 0.5261 0.2862 0.0000 0.7678 2.3035 2.1656
8 0.7957 0.5565 0.7939 0.9708 0.9860 1.0129 0.7678 0.0000 2.2251 1.5609
9 2.7901 2.2733 2.2692 2.4523 2.4847 2.4449 2.3035 2.2251 0.0000 2.8476
10 2.0327 1.7509 1.8055 1.9019 2.1376 2.3483 2.1656 1.5609 2.8476 0.0000
We already know how to read this matrix. Let’s plot it as a function of the coastal section’s number (Figure 3).
(To be reviewed by BCB743 student but not for marks)
Use the Doubs River environmental data for this exercise.
Total: 14 marks for BDC334 students. Marks are assigned only to the components listed below and under Question 8.
-
(/ 2) Standardise these data using R and display a portion of the resultant standardised data file.
- Mark allocation: 1 mark for the correct code; 1 mark for the correct portion of output.
- (/ no marks) Discuss why standardisation was necessary for these data. Use the content of the actual ‘raw’ data file in your discussion.
-
(/ 2) Using R, calculate the Euclidean distances for these data and display a portion of the resultant distance matrix.
- Mark allocation: 1 mark for the correct code; 1 mark for the correct portion of output.
-
(/ 6) Discuss the ecological conclusions you are able to draw from these Euclidean distances. Provide two graphs to substantiate your answer.
- Mark allocation: 2 marks for the code for two graphs (1 per graph); 2 marks for two correct, publication-quality graphs (1 per graph), including full axis labels, units where applicable and readable presentation; 2 marks for correct explanations (1 per explanation), for example a gradient and a local perturbation.
These answers use all 30 Doubs River sites and all 11 environmental variables. Lab 1 used only the odd-numbered sites for its distance and correlation matrices. Do not carry that selection into this exercise.
1. Standardise the Doubs data
Marking: 2 marks — 1 for the code and 1 for the correct portion of output.
Read the site numbers as row names. They identify the samples and must not become an extra environmental variable. The dfs column is different: it records distance from the river’s source and is retained here to match the 11-variable analysis in Lab 1.
# Read the downloaded DoubsEnv.csv in your working directory with:
# doubs <- read.csv("DoubsEnv.csv", row.names = 1)
# This course website uses the same file at its repository location:
doubs <- read.csv(here::here("data", "BCB743", "DoubsEnv.csv"),
row.names = 1
)
# Subtract each column's mean and divide by its sample SD.
doubs_z <- scale(doubs)
knitr::kable(doubs_z[1:5, 1:6], digits = 3, row.names = TRUE)| dfs | alt | slo | flo | pH | har | |
|---|---|---|---|---|---|---|
| 1 | -1.350 | 1.667 | 5.141 | -1.180 | -0.864 | -2.437 |
| 2 | -1.336 | 1.660 | -0.057 | -1.171 | -0.288 | -2.733 |
| 3 | -1.279 | 1.594 | 0.023 | -1.127 | 1.439 | -2.022 |
| 4 | -1.219 | 1.373 | -0.034 | -1.087 | -0.288 | -0.836 |
| 5 | -1.197 | 1.354 | -0.138 | -1.081 | 0.288 | -0.125 |
Only a portion is displayed; doubs_z contains all 30 rows and 11 columns. Each column should now have a mean of zero and a sample SD of one, allowing for tiny numerical rounding errors:
dfs alt slo flo pH har pho nit amm oxy bod
mean 0 0 0 0 0 0 0 0 0 0 0
SD 1 1 1 1 1 1 1 1 1 1 1
vegan::decostand(doubs, method = "standardize") gives the same standardisation. Keep the full precision for subsequent calculations; round only what you display.
2. Why standardisation matters here
No marks are assigned to this question.
Look at the actual scales in the file. Altitude ranges from 172 to 934, whereas pH ranges from 7.7 to 8.6 and ammonium from 0 to 1.8. Squaring the raw differences would let a variable with large numerical values, such as altitude, dominate the distance. That would reflect its scale of measurement rather than an explicit ecological decision about its importance. Even changing altitude from metres to kilometres would change the raw distances.
Standardisation expresses each difference relative to the variation in that variable across these 30 sites. A difference of one standard deviation then makes the same contribution whichever variable it comes from. It does not make the variables biologically equally important, remove outliers, or remove correlations. Several correlated nutrient variables can still give extra weight to a shared water-quality gradient.
3. Calculate and inspect environmental distances
Marking: 2 marks — 1 for the code and 1 for the correct portion of output.
| 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|
| 1 | 0.000 | 5.319 | 5.686 | 5.498 | 6.293 |
| 2 | 5.319 | 0.000 | 1.924 | 1.976 | 3.142 |
| 3 | 5.686 | 1.924 | 0.000 | 2.201 | 2.669 |
| 4 | 5.498 | 1.976 | 2.201 | 0.000 | 2.173 |
| 5 | 6.293 | 3.142 | 2.669 | 2.173 | 0.000 |
The complete matrix is 30 × 30. Its diagonal is zero and its two triangles mirror one another. Sites 2 and 3 have a distance of about 1.924; Sites 1 and 5 have a distance of about 6.293. The second pair is more different in the selected, standardised environmental variables. These are not kilometres, percentages or probabilities, and a value greater than one is perfectly possible.
4. Describe the pattern, then consider its causes
Marking: 6 marks — 2 for the code for two graphs, 2 for two correct, publication-quality graphs, and 2 for correct explanations. Each graph can earn 1 code mark, 1 presentation/output mark and 1 explanation mark.
A distance tells us how different two sites are overall. To explain that difference, return to the variables that went into it. Plotting them against distance from the source also respects the unequal spacing of the sampling sites. The two examples below show a broad altitude gradient and a local oxygen decline. Other suitable graphs and well-supported explanations are acceptable.
Explanation 1: Altitude decreases downstream, showing a broad longitudinal gradient. Sites far apart along that gradient can have large environmental distances partly because they differ in altitude. This is a description of river position and topography; it does not establish that altitude caused every other environmental change.
ggplot(doubs, aes(dfs, oxy)) +
annotate("rect",
xmin = doubs$dfs[23], xmax = doubs$dfs[25],
ymin = -Inf, ymax = Inf, fill = "goldenrod", alpha = 0.15
) +
geom_line(colour = "indianred", linewidth = 0.7) +
geom_point(size = 2) +
labs(
x = "Distance from source (km)",
y = expression("Dissolved oxygen (mg " * L^{
-1
} * ")")
) +
theme_linedraw(base_size = 12)Explanation 2: The oxygen decline around Sites 23–25, followed by higher concentrations downstream, is consistent with a local perturbation superimposed on the river gradient. Increased microbial oxygen consumption after organic inputs is one possible explanation. The high biological oxygen demand at these sites supports investigating that explanation, but oxygen supply and reaeration must also be measured.
The wider dataset helps us interpret these two graphs:
- There is a broad downstream gradient. Altitude decreases and flow generally increases. Accumulating drainage and tributary inputs could help explain increasing flow. Neighbouring sites often have similar environments, but being neighbours does not guarantee similarity.
- Sites 23–25 show a marked water-quality change. Phosphate, ammonium and biological oxygen demand are high, while oxygen is low. Sites 1 and 25 are the most different pair in this matrix, with a distance of about 12.145. Site 1 also has an unusually steep slope, which contributes to this difference. Sites 11 and 13 are much more similar, with a distance of about 0.968.
- Some water-quality variables move back towards earlier values below Site 25. Oxygen rises while ammonium and biological oxygen demand fall. Dilution, reaeration, uptake and processing of organic material are possible explanations to investigate. The measurements do not establish which process was responsible.
Organic inputs followed by microbial respiration offer one explanation for the combination of high oxygen demand and low dissolved oxygen. However, a distance matrix cannot identify a discharge source, establish causation or demonstrate a change in fish composition. Those conclusions require additional measurements. Also remember that dfs itself is in this distance calculation: part of the spatial pattern is included by construction. Task 8 shows how to check the result without it.
We will explore distance and dissimilarity matrices in more detail in later sections.
Pairwise Correlations
It is easy to calculate pairwise correlation matrices for the above data:
febMean febRange febSD augMean augRange augSD annMean annRange annSD
febMean 1.00 -0.27 -0.28 0.90 -0.10 -0.16 0.98 0.74 0.41
febRange -0.27 1.00 0.79 -0.32 0.14 0.14 -0.29 -0.08 0.48
febSD -0.28 0.79 1.00 -0.16 0.35 0.46 -0.26 -0.33 0.31
augMean 0.90 -0.32 -0.16 1.00 -0.01 -0.05 0.96 0.37 0.13
augRange -0.10 0.14 0.35 -0.01 1.00 0.91 -0.10 -0.20 0.06
augSD -0.16 0.14 0.46 -0.05 0.91 1.00 -0.17 -0.27 0.08
annMean 0.98 -0.29 -0.26 0.96 -0.10 -0.17 1.00 0.60 0.29
annRange 0.74 -0.08 -0.33 0.37 -0.20 -0.27 0.60 1.00 0.68
annSD 0.41 0.48 0.31 0.13 0.06 0.08 0.29 0.68 1.00
(To be reviewed by BCB743 student but not for marks)
- (/ no marks) Explain in a short (1/3 page paragraph) what is meant by ‘environmental distance’.
- (/ no marks) Describe to your grandmother how to interpret the above correlation matrix, and also mention what the major conclusions are that can be drawn from studying the matrix. Add a mechanistic explanation to demonstrate to her what your thought processes are for reaching your conclusion.
-
(/ no marks) Explain why the same general trend is seen in the raw or standardised environmental data for
annMean(Figure 1 and 2) and that of environmental distance (Figure 3).
No marks are assigned to Questions 5–7.
5. What is environmental distance?
Environmental distance describes how different two sites are in a specified set of environmental measurements. Imagine describing each site by its altitude, flow, oxygen and other measured conditions. For each variable, take the difference between the two sites. Euclidean distance squares these differences, adds them and takes the square root. We standardise the Doubs variables first so that different units and numerical scales do not determine their contributions. Zero means the sites have identical values for the variables included; larger values mean greater overall difference. Two geographically distant sites can therefore have a small environmental distance, while two nearby sites can have a large one. The result depends on which variables we select and how we scale them. It summarises the measured environment; it is not a complete measure of habitat quality, species composition or ecological importance.
6. Read the coastal correlation matrix
This question refers to the nine seaweed thermal variables in env1_cor immediately above, not to the Doubs distance matrix.
Think of each entry as asking whether two measurements tend to move together across the 58 coastal sections. A number close to +1 means sections with high values of one usually have high values of the other. A number close to −1 means high values of one usually accompany low values of the other. A value close to zero means little linear association; it does not rule out a curved relationship. The diagonal is all ones because each measurement is being compared with itself. The repeated triangle contains the same information twice.
Here are some examples from this matrix:
| Comparison | Pearson’s r | What it shows |
|---|---|---|
| February mean and annual mean | 0.98 | Sections that are warm in February also tend to be warm over the year. |
| August mean and annual mean | 0.96 | Much of that ordering persists in August. |
| February mean and August mean | 0.90 | Warm and cool sections retain a broad seasonal consistency. |
| August range and August SD | 0.91 | The two measures of within-month variability tend to increase together. |
| February range and February SD | 0.79 | The same broad association occurs in February. |
| Annual mean and August range | −0.10 | Mean warmth tells us little about August’s range in a simple linear comparison. |
Differences in the source and mixing of coastal water could maintain relatively cool and warm sections across seasons. Changes in water movement or episodic upwelling could also produce temperature fluctuations within a month. To test those explanations, we would need temperature time series together with information about water movement and upwelling. The matrix alone does not show which mechanism operates. There is also a simpler reason for some correlations: annual and monthly means share underlying temperature observations, while range and SD both describe variation. They are not independent lines of evidence.
7. Why do the three coastal plots look broadly similar?
The raw and standardised annMean plots have exactly the same shape. Standardisation subtracts one constant and divides by another positive constant. It changes the vertical scale but preserves the ordering, peaks and troughs.
The environmental-distance plot asks a different question. Its column 1 gives the distance of every section from Section 1, using all nine standardised thermal variables:
\[ d(1,j) = \sqrt{\sum_{k=1}^{9}(z_{1k}-z_{jk})^2}. \]
Section 1 is a cool western reference section. Mean annual temperature rises broadly towards the east, and the February and August means change with it. Many eastern sections therefore differ from Section 1 in several variables at once, increasing their environmental distance. This explains the broad resemblance. The curves need not match: temperature range and variability also contribute, and environmental distance has no sign. Choosing another reference section would change the distance curve without changing the annMean curve. Do not interpret Figure 3 as distance from each section’s immediate neighbour, or as a geographic distance.
Euclidean Distance of Geographical Data
When we calculate Euclidean distances between geographic lat/lon coordinate, the relationship between sections will be the same (but scaled) as actual geographic distances.
Latitude Longitude
1 -28.98450 16.72429
2 -29.38053 16.94238
3 -29.83253 17.08194
4 -30.26426 17.25928
5 -30.67874 17.47638
6 -31.08580 17.72167
Calculate geographic distances (in meters) between coordinate pairs (Figure 6).
1 2 3 4 5
1 0.00 48752.45 100201.82 151021.75 201380.00
2 48752.45 0.00 51894.01 102638.03 152849.90
3 100201.82 51894.01 0.00 50822.71 101197.22
4 151021.75 102638.03 50822.71 0.00 50457.53
5 201380.00 152849.90 101197.22 50457.53 0.00
1 2 3 4 5
1 0.0000 0.4521 0.9204 1.3871 1.8537
2 0.4521 0.0000 0.4731 0.9388 1.4037
3 0.9204 0.4731 0.0000 0.4667 0.9336
4 1.3871 0.9388 0.4667 0.0000 0.4679
5 1.8537 1.4037 0.9336 0.4679 0.0000
(To be reviewed by BCB743 student but not for marks)
-
(/ 4) Do a full analysis of the Doubs River environmental data using Euclidean distances and correlations. Demonstrate graphically any clear spatial patterns that you might find, and offer a full suite of mechanistic explanations for the patterns you see. It is sufficient to submit a fully annotated R script (not a MS Word or Excel file).
- Mark allocation: 1 mark for the Euclidean distance code; 1 mark for the correct visualisation of Euclidean distance; 1 mark for the correlations code; 1 mark for the correct pairwise correlations.
8. Put the Doubs analysis together
Marking: 4 marks — 1 for the Euclidean distance code, 1 for its correct visualisation, 1 for the correlations code, and 1 for the correct pairwise correlations. No additional marks are assigned to the interpretation or sensitivity check below.
A complete answer combines the calculations with an explanation of what the figures show. The plots for Task 4 are part of that evidence. First inspect the full distance table, then its visualisation. Scroll within the table to see all 30 site columns. Values are rounded for display; the calculations retain full precision.
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 0.000 | 5.319 | 5.686 | 5.498 | 6.293 | 5.391 | 5.584 | 6.740 | 6.584 | 5.380 | 6.483 | 6.289 | 6.699 | 7.139 | 7.707 | 6.650 | 7.113 | 7.035 | 7.053 | 7.231 | 7.197 | 7.288 | 9.833 | 8.885 | 12.145 | 8.585 | 8.210 | 8.911 | 8.900 | 9.249 |
| 2 | 5.319 | 0.000 | 1.924 | 1.976 | 3.142 | 1.669 | 3.003 | 3.978 | 3.542 | 3.537 | 4.177 | 3.676 | 4.316 | 4.729 | 5.187 | 4.061 | 4.594 | 4.490 | 4.419 | 4.761 | 4.738 | 4.819 | 8.024 | 6.767 | 10.637 | 6.487 | 5.978 | 6.791 | 7.132 | 7.309 |
| 3 | 5.686 | 1.924 | 0.000 | 2.201 | 2.669 | 2.430 | 2.515 | 3.438 | 3.380 | 4.203 | 3.690 | 3.803 | 3.828 | 3.755 | 3.751 | 3.925 | 4.398 | 4.348 | 4.073 | 4.665 | 4.825 | 4.430 | 7.635 | 6.497 | 10.541 | 6.422 | 5.633 | 6.130 | 7.155 | 6.772 |
| 4 | 5.498 | 1.976 | 2.201 | 0.000 | 2.173 | 1.437 | 1.213 | 2.939 | 2.406 | 2.481 | 2.632 | 2.263 | 2.708 | 3.334 | 4.276 | 2.812 | 3.444 | 3.328 | 3.402 | 3.805 | 3.821 | 3.826 | 7.514 | 6.071 | 10.275 | 5.751 | 5.215 | 5.903 | 6.047 | 6.282 |
| 5 | 6.293 | 3.142 | 2.669 | 2.173 | 0.000 | 2.190 | 1.955 | 0.990 | 1.018 | 2.960 | 2.829 | 3.081 | 3.160 | 3.317 | 4.187 | 2.929 | 3.195 | 3.281 | 3.347 | 3.756 | 3.660 | 3.434 | 6.038 | 4.625 | 8.939 | 4.774 | 4.426 | 5.176 | 5.811 | 5.730 |
| 6 | 5.391 | 1.669 | 2.430 | 1.437 | 2.190 | 0.000 | 2.252 | 2.864 | 2.435 | 2.237 | 3.295 | 2.634 | 3.442 | 4.018 | 4.993 | 3.171 | 3.645 | 3.634 | 3.694 | 4.039 | 3.805 | 3.963 | 7.115 | 5.710 | 9.873 | 5.460 | 5.181 | 6.156 | 6.119 | 6.515 |
| 7 | 5.584 | 3.003 | 2.515 | 1.213 | 1.955 | 2.252 | 0.000 | 2.515 | 2.236 | 2.700 | 2.092 | 2.253 | 2.143 | 2.647 | 3.712 | 2.656 | 3.224 | 3.160 | 3.228 | 3.711 | 3.796 | 3.550 | 7.239 | 5.804 | 10.138 | 5.598 | 4.968 | 5.490 | 5.795 | 5.825 |
| 8 | 6.740 | 3.978 | 3.438 | 2.939 | 0.990 | 2.864 | 2.515 | 0.000 | 1.078 | 3.207 | 3.096 | 3.424 | 3.399 | 3.508 | 4.456 | 3.151 | 3.312 | 3.496 | 3.605 | 3.973 | 3.714 | 3.421 | 5.843 | 4.269 | 8.842 | 4.571 | 4.306 | 5.104 | 5.679 | 5.568 |
| 9 | 6.584 | 3.542 | 3.380 | 2.406 | 1.018 | 2.435 | 2.236 | 1.078 | 0.000 | 2.531 | 2.643 | 2.825 | 3.025 | 3.371 | 4.461 | 2.480 | 2.750 | 2.836 | 3.062 | 3.325 | 3.038 | 3.003 | 5.915 | 4.195 | 8.732 | 4.187 | 3.937 | 4.818 | 5.163 | 5.293 |
| 10 | 5.380 | 3.537 | 4.203 | 2.481 | 2.960 | 2.237 | 2.700 | 3.207 | 2.531 | 0.000 | 2.843 | 2.016 | 3.052 | 4.012 | 5.520 | 2.500 | 2.906 | 2.910 | 3.327 | 3.316 | 2.846 | 3.425 | 6.786 | 5.101 | 9.379 | 4.599 | 4.536 | 5.640 | 4.814 | 5.780 |
| 11 | 6.483 | 4.177 | 3.690 | 2.632 | 2.829 | 3.295 | 2.092 | 3.096 | 2.643 | 2.843 | 0.000 | 1.602 | 0.968 | 1.347 | 3.036 | 1.193 | 1.561 | 1.479 | 1.538 | 2.049 | 2.382 | 2.061 | 6.228 | 4.721 | 9.115 | 4.243 | 3.446 | 3.806 | 4.261 | 4.248 |
| 12 | 6.289 | 3.676 | 3.803 | 2.263 | 3.081 | 2.634 | 2.253 | 3.424 | 2.825 | 2.016 | 1.602 | 0.000 | 1.374 | 2.498 | 4.097 | 1.613 | 2.069 | 1.952 | 2.195 | 2.499 | 2.381 | 2.535 | 6.753 | 5.139 | 9.595 | 4.564 | 4.043 | 4.823 | 4.232 | 4.828 |
| 13 | 6.699 | 4.316 | 3.828 | 2.708 | 3.160 | 3.442 | 2.143 | 3.399 | 3.025 | 3.052 | 0.968 | 1.374 | 0.000 | 1.337 | 3.041 | 1.724 | 2.096 | 1.974 | 2.015 | 2.564 | 2.753 | 2.336 | 6.697 | 5.162 | 9.679 | 4.724 | 3.904 | 4.285 | 4.308 | 4.332 |
| 14 | 7.139 | 4.729 | 3.755 | 3.334 | 3.317 | 4.018 | 2.647 | 3.508 | 3.371 | 4.012 | 1.347 | 2.498 | 1.337 | 0.000 | 1.958 | 2.178 | 2.321 | 2.296 | 1.986 | 2.726 | 3.170 | 2.359 | 6.325 | 5.018 | 9.407 | 4.736 | 3.700 | 3.701 | 4.735 | 4.137 |
| 15 | 7.707 | 5.187 | 3.751 | 4.276 | 4.187 | 4.993 | 3.712 | 4.456 | 4.461 | 5.520 | 3.036 | 4.097 | 3.041 | 1.958 | 0.000 | 3.628 | 3.810 | 3.694 | 3.152 | 3.954 | 4.464 | 3.427 | 6.963 | 5.895 | 10.032 | 5.743 | 4.456 | 4.076 | 5.961 | 4.680 |
| 16 | 6.650 | 4.061 | 3.925 | 2.812 | 2.929 | 3.171 | 2.656 | 3.151 | 2.480 | 2.500 | 1.193 | 1.613 | 1.724 | 2.178 | 3.628 | 0.000 | 0.913 | 0.791 | 1.089 | 1.279 | 1.384 | 1.492 | 5.911 | 4.209 | 8.712 | 3.587 | 2.839 | 3.532 | 3.901 | 4.142 |
| 17 | 7.113 | 4.594 | 4.398 | 3.444 | 3.195 | 3.645 | 3.224 | 3.312 | 2.750 | 2.906 | 1.561 | 2.069 | 2.096 | 2.321 | 3.810 | 0.913 | 0.000 | 0.640 | 1.018 | 0.867 | 1.192 | 1.336 | 5.283 | 3.629 | 8.083 | 3.036 | 2.299 | 3.013 | 3.465 | 3.710 |
| 18 | 7.035 | 4.490 | 4.348 | 3.328 | 3.281 | 3.634 | 3.160 | 3.496 | 2.836 | 2.910 | 1.479 | 1.952 | 1.974 | 2.296 | 3.694 | 0.791 | 0.640 | 0.000 | 0.737 | 0.780 | 1.187 | 1.334 | 5.442 | 3.819 | 8.168 | 3.118 | 2.386 | 3.049 | 3.408 | 3.637 |
| 19 | 7.053 | 4.419 | 4.073 | 3.402 | 3.347 | 3.694 | 3.228 | 3.605 | 3.062 | 3.327 | 1.538 | 2.195 | 2.015 | 1.986 | 3.152 | 1.089 | 1.018 | 0.737 | 0.000 | 1.007 | 1.526 | 1.184 | 5.412 | 3.912 | 8.247 | 3.264 | 2.314 | 2.826 | 3.703 | 3.550 |
| 20 | 7.231 | 4.761 | 4.665 | 3.805 | 3.756 | 4.039 | 3.711 | 3.973 | 3.325 | 3.316 | 2.049 | 2.499 | 2.564 | 2.726 | 3.954 | 1.279 | 0.867 | 0.780 | 1.007 | 0.000 | 1.214 | 1.541 | 5.352 | 3.815 | 7.962 | 3.047 | 2.164 | 2.767 | 3.450 | 3.669 |
| 21 | 7.197 | 4.738 | 4.825 | 3.821 | 3.660 | 3.805 | 3.796 | 3.714 | 3.038 | 2.846 | 2.382 | 2.381 | 2.753 | 3.170 | 4.464 | 1.384 | 1.192 | 1.187 | 1.526 | 1.214 | 0.000 | 1.256 | 5.432 | 3.495 | 8.124 | 2.598 | 2.006 | 3.171 | 2.980 | 3.542 |
| 22 | 7.288 | 4.819 | 4.430 | 3.826 | 3.434 | 3.963 | 3.550 | 3.421 | 3.003 | 3.425 | 2.061 | 2.535 | 2.336 | 2.359 | 3.427 | 1.492 | 1.336 | 1.334 | 1.184 | 1.541 | 1.256 | 0.000 | 5.319 | 3.449 | 8.319 | 2.864 | 1.751 | 2.632 | 3.249 | 2.983 |
| 23 | 9.833 | 8.024 | 7.635 | 7.514 | 6.038 | 7.115 | 7.239 | 5.843 | 5.915 | 6.786 | 6.228 | 6.753 | 6.697 | 6.325 | 6.963 | 5.911 | 5.283 | 5.442 | 5.412 | 5.352 | 5.432 | 5.319 | 0.000 | 2.494 | 3.563 | 3.542 | 4.329 | 4.718 | 5.990 | 5.640 |
| 24 | 8.885 | 6.767 | 6.497 | 6.071 | 4.625 | 5.710 | 5.804 | 4.269 | 4.195 | 5.101 | 4.721 | 5.139 | 5.162 | 5.018 | 5.895 | 4.209 | 3.629 | 3.819 | 3.912 | 3.815 | 3.495 | 3.449 | 2.494 | 0.000 | 5.419 | 1.587 | 2.479 | 3.465 | 4.174 | 4.040 |
| 25 | 12.145 | 10.637 | 10.541 | 10.275 | 8.939 | 9.873 | 10.138 | 8.842 | 8.732 | 9.379 | 9.115 | 9.595 | 9.679 | 9.407 | 10.032 | 8.712 | 8.083 | 8.168 | 8.247 | 7.962 | 8.124 | 8.319 | 3.563 | 5.419 | 0.000 | 6.006 | 7.063 | 7.259 | 8.259 | 8.233 |
| 26 | 8.585 | 6.487 | 6.422 | 5.751 | 4.774 | 5.460 | 5.598 | 4.571 | 4.187 | 4.599 | 4.243 | 4.564 | 4.724 | 4.736 | 5.743 | 3.587 | 3.036 | 3.118 | 3.264 | 3.047 | 2.598 | 2.864 | 3.542 | 1.587 | 6.006 | 0.000 | 1.736 | 2.952 | 3.085 | 3.351 |
| 27 | 8.210 | 5.978 | 5.633 | 5.215 | 4.426 | 5.181 | 4.968 | 4.306 | 3.937 | 4.536 | 3.446 | 4.043 | 3.904 | 3.700 | 4.456 | 2.839 | 2.299 | 2.386 | 2.314 | 2.164 | 2.006 | 1.751 | 4.329 | 2.479 | 7.063 | 1.736 | 0.000 | 1.637 | 3.007 | 2.491 |
| 28 | 8.911 | 6.791 | 6.130 | 5.903 | 5.176 | 6.156 | 5.490 | 5.104 | 4.818 | 5.640 | 3.806 | 4.823 | 4.285 | 3.701 | 4.076 | 3.532 | 3.013 | 3.049 | 2.826 | 2.767 | 3.171 | 2.632 | 4.718 | 3.465 | 7.259 | 2.952 | 1.637 | 0.000 | 3.729 | 2.451 |
| 29 | 8.900 | 7.132 | 7.155 | 6.047 | 5.811 | 6.119 | 5.795 | 5.679 | 5.163 | 4.814 | 4.261 | 4.232 | 4.308 | 4.735 | 5.961 | 3.901 | 3.465 | 3.408 | 3.703 | 3.450 | 2.980 | 3.249 | 5.990 | 4.174 | 8.259 | 3.085 | 3.007 | 3.729 | 0.000 | 2.356 |
| 30 | 9.249 | 7.309 | 6.772 | 6.282 | 5.730 | 6.515 | 5.825 | 5.568 | 5.293 | 5.780 | 4.248 | 4.828 | 4.332 | 4.137 | 4.680 | 4.142 | 3.710 | 3.637 | 3.550 | 3.669 | 3.542 | 2.983 | 5.640 | 4.040 | 8.233 | 3.351 | 2.491 | 2.451 | 2.356 | 0.000 |
lab2_pairs <- expand.grid(
site_a = seq_len(nrow(doubs)),
site_b = seq_len(nrow(doubs))
)
lab2_pairs$distance <- as.vector(doubs_D)
ggplot(lab2_pairs, aes(site_a, site_b, fill = distance)) +
geom_tile() +
coord_equal() +
scale_fill_viridis_c(name = "Distance") +
scale_x_continuous(breaks = c(1, 5, 10, 15, 20, 25, 30)) +
scale_y_continuous(breaks = c(1, 5, 10, 15, 20, 25, 30)) +
labs(x = "Site", y = "Site") +
theme_linedraw()Use correlations to examine relationships among variables, rather than differences among sites. These are Pearson correlations across all 30 sites; standardising each column leaves them unchanged.
| dfs | alt | slo | flo | pH | har | pho | nit | amm | oxy | bod | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| dfs | 1.00 | -0.94 | -0.38 | 0.95 | 0.01 | 0.70 | 0.48 | 0.75 | 0.41 | -0.51 | 0.39 |
| alt | -0.94 | 1.00 | 0.44 | -0.87 | -0.04 | -0.74 | -0.44 | -0.76 | -0.38 | 0.36 | -0.34 |
| slo | -0.38 | 0.44 | 1.00 | -0.34 | -0.22 | -0.53 | -0.19 | -0.31 | -0.17 | 0.31 | -0.18 |
| flo | 0.95 | -0.87 | -0.34 | 1.00 | 0.02 | 0.70 | 0.39 | 0.61 | 0.29 | -0.36 | 0.25 |
| pH | 0.01 | -0.04 | -0.22 | 0.02 | 1.00 | 0.09 | -0.08 | -0.05 | -0.12 | 0.18 | -0.15 |
| har | 0.70 | -0.74 | -0.53 | 0.70 | 0.09 | 1.00 | 0.36 | 0.51 | 0.29 | -0.38 | 0.34 |
| pho | 0.48 | -0.44 | -0.19 | 0.39 | -0.08 | 0.36 | 1.00 | 0.80 | 0.97 | -0.72 | 0.89 |
| nit | 0.75 | -0.76 | -0.31 | 0.61 | -0.05 | 0.51 | 0.80 | 1.00 | 0.80 | -0.63 | 0.64 |
| amm | 0.41 | -0.38 | -0.17 | 0.29 | -0.12 | 0.29 | 0.97 | 0.80 | 1.00 | -0.72 | 0.89 |
| oxy | -0.51 | 0.36 | 0.31 | -0.36 | 0.18 | -0.38 | -0.72 | -0.63 | -0.72 | 1.00 | -0.84 |
| bod | 0.39 | -0.34 | -0.18 | 0.25 | -0.15 | 0.34 | 0.89 | 0.64 | 0.89 | -0.84 | 1.00 |
lab2_panel_cor <- function(x, y, ...) {
old_usr <- par("usr")
on.exit(par(usr = old_usr))
par(usr = c(0, 1, 0, 1))
text(0.5, 0.5, sprintf("%.2f", cor(x, y)), cex = 0.9)
}
pairs(doubs,
upper.panel = lab2_panel_cor,
pch = 16, cex = 0.5, cex.labels = 0.9, gap = 0.4,
col = ifelse(seq_len(nrow(doubs)) %in% 23:25,
"indianred", "grey35"
)
)An ecological interpretation should connect three things: a measured pattern, a possible mechanism, and evidence that could test it.
| Measured pattern | Possible explanation | What else would help test it? |
|---|---|---|
Altitude falls and flow rises downstream; dfs–alt r = −0.94 and dfs–flo r = 0.95. |
The river descends through the catchment while drainage and tributaries add water. | Catchment area, tributary locations and repeated discharge measurements. |
| Phosphate and ammonium rise together (r = 0.97), especially at Sites 23–25. | Shared nutrient inputs could affect both. Their common downstream setting could also contribute. | Measurements above and below suspected inputs, including input concentrations and flows. |
| Biological oxygen demand is negatively associated with oxygen (r = −0.84). | Microbial processing of organic inputs can consume oxygen; the oxygen balance also depends on supply and reaeration. | Organic loading, temperature, oxygen through time, discharge and reaeration measurements. |
Hardness generally increases downstream (dfs–har r = 0.70). |
Changes in geology, groundwater or tributary inputs could change dissolved mineral concentrations. | Catchment geology and the chemistry of groundwater and tributaries. |
| Several water-quality indicators improve below Site 25. | Dilution, reaeration and biological or chemical processing could contribute. | Nutrient and oxygen budgets with repeated upstream, input and downstream sampling. |
These are explanations to test, not causes established by a correlation coefficient. Site 1’s steep slope and the high values at Sites 23–25 also warrant inspection in the raw plots. Pearson’s r can be strongly affected by unusual observations and shared downstream trends. The river sites are spatially connected, so they should not automatically be treated as 30 independent replicates of a process.
For a useful sensitivity check, repeat the environmental distances without dfs. We are then asking about differences in measured conditions without including longitudinal position as one of those conditions. Sites 11 and 13 remain similar (about 0.957), but every distance must be recalculated. Standardisation still uses all 30 sites.
with_dfs without_dfs
0.968 0.957
The annotated model R script recreates the full Doubs analysis, including the two labelled Q4 graphs, supplementary raw-variable plots, the distance table and figure, the correlation table and pairwise plot, and the check without dfs. Save it alongside DoubsEnv.csv and run it from that directory. The comments show how to keep observations separate from proposed mechanisms. Other well-supported explanations are acceptable; a list of correlation coefficients alone is not an ecological explanation.
The Lab 2b assignment on Environmental Distance is due at 08:00 on Monday, 14 September 2026.
Provide a neat and thoroughly annotated R file which can recreate all the graphs and all calculations. Written answers must be typed in the same file as comments.
Please label the R file as follows:
BDC334_<first_name>_<last_name>_Lab_2.R
(the < and > must be omitted as they are used in the example as field indicators only).
Upload your appropriately named R document to iKamva by the stated deadline. This requirement applies to both pre-assessed and self-assessed submissions. If this Lab is self-assessed, complete and upload the self-assessment to iKamva by 23:59 on the same day. See the Lab submission and self-assessment policy for the checking and penalty rules.
The marked components total 14 marks. Questions 2 and 5–7 remain learning exercises without marks. Figure presentation is assessed within Question 4; there is no separate formatting mark.
References
Reuse
Citation
@online{smit2026,
author = {Smit, A. J. and J. Smit, A.},
title = {Lab 2b. {Environmental} {Distance}},
date = {2026-08-19},
url = {https://tangledbank.netlify.app/BDC334/Lab-02b-env_dist.html},
langid = {en}
}
