2020-07-19 / Blog 2

Temperature contour plots showing variation in depth and time

When you are monitoring soil temperature at various locations in a plot or an in experimental setup over time, you either end up having too many figures in a publication or important information goes missing when you plot snapshots of soil temperature profile. While struggling with fitting all the data I have in a strictly 6-page conference proceeding, I came up with an idea of illustrating the change in time and depth of soil temperature in the same plot, without compromising any data.

The idea starts with a simple contour plot. Temperature contour plots have a potential to convey a great deal of information you would like to give to the reader. A 2D temperature profile can be plotted very easily. While keeping the 2D structure, extending the profile by using the x-axis as time gives you a chance to show both the time- and depth- dependent variation.

We will use air temperature and soil temperature data from the same lysimeter setup presented in the Blog Post #1. Data used in this script can be accessed via NGIF API and from the following data set:

Yildiz, A. and Stirling, R.A. 2020. PLEXUS Lysimeter - Soil Temperature Data v1. Newcastle University. doi: 10.25405/data.ncl.12613880.

Firstly, we define the start and end of the time frame, then generate a POSIXct vector using seq() function in 15-min time steps:

startdate <- as.POSIXct("2019-05-03 00:00:00",tz="UTC")

enddate <- as.POSIXct("2019-07-03 00:00:00",tz="UTC")

time_steps <- seq(startdate,enddate,60*15)

Then, we check the range of the air temperature and soil temperature values measured, simply using summary() function. We see that air temperature varied between 2.5 °C and 25.7 °C, whereas the range of soil temperatures measured is 2.9 °C and 23.4°C. We define a sequential vector to obtain the steps of temperature between 2°C and 26°C so that we can display all the temperatures measured.

temp_steps <- seq(2,26,1)

We used findInterval() function in the Blog Post #1 to find which time step does each data point belong to. This time we will use the same function to define which temperature step each measurement belongs to. Next thing to do is to use the heat.colors(n) palette to get the hex colour codes. Here n will be the number of the colours we want to extract. We have 25 temperature steps, therefore we will substitute n with length(temp_steps). We have one issue to solve here. The first colour in heat.colors(n) palette is red, whereas our first temperature step, temp_steps[1] , is 2°C-3°C. But, we should be having a bright red for our last temperature step, temp_steps[25]. Therefore, we will substract all temperature steps from 26 to assign the first colour in the palette to the last temperature step and vice versa. Finally, we combine findInterval() and heat.colors() to assign a hex colour code for each measurement. The final code will be as follows:


This piece of code will assign a hex colour code for each measurement in the second column of soiltemp dataset, and can be used to create any contour plot. We can repeat the same for the other columns in the dataset. In order to visualise the contour plot showing the variation in depth and time, we will first plot an empty area that extends in x-axis from our startdate until enddate. y-axis will range between 0 to the depth of our soil column, i.e. 950 mm for the lysimeter setup. We will extract the depths from the column names of the soiltemp dataset.

depth <- as.numeric(substr(colnames(soiltemp[2:14]),start=2,stop=4))

Then generate a for loop to plot rectangles with a width of the measurement interval of the soil temperature, and a height to be adjusted based on the plot height. The colour of the rectangle will be chosen using the combined findInterval() and heat.colors() code. So, the for loop will look like this:

for(j in 1:length(depth))

{ for(i in 1:nrow(soiltemp)){






The plot will then look like this:

The scripts used in this post can be found here: Blog Scripts @ Github