## Below is the Supporting information

(i) Supplementary figures

Fig. S1Results of Partial Least Squares regression between grassland aboveground productivity and daily unfilted and 15-day running mean filtered soil temperature at 15 cm depth.

Fig. S2Inter-annual variation in air temperature of the 97 national weather stations across the whole Qinghai-Tibetan Plateau during 1997-2011. Red dots mean that there was a significant warming trend during the past 15 years, while the size indicates the magnitude of the increase in air temperature. Grey dots represent stations for which no significant trends for air temperature were found.

Fig.S3Seasonal (a) and monthly (b) differences between soil temperatures at different depths and air temperatures during 1997-2011.

Fig.S4Mean daily and monthly standard deviation of air and soil temperatures at different depths during 1997-2011.

Fig.S5Results of Partial Least Squares regression between grassland aboveground productivity and daily air and soil temperature (at 15 cm depth) from previous September to August. See caption of Fig. 3 for a full explanation.

Fig.S6Monthly mean air and soil temperature at different depths as well as monthly precipitation during the growing season; inter-annual variation in precipitation during the growing season in the past 15 years (a); and daily mean precipitation, evaporation, wind speed and frozen soil depth in our study area (b). The preseason (March-April) period was marked in red dashed lines in this figure.

(ii) Codesfor reproducing the analyses

Code 1:Codes for reproducing the PLS analysis (Fig. 3) in the present study in R language.

#START

windowsFonts(

A=windowsFont("Times New Roman"),

B=windowsFont("Bookman Old Style"),

C=windowsFont("Comic Sans MS"),

D=windowsFont("Symbol")

)

require(chillR)

require(pls)

out_path<-"G:/"

runn_mean <- 15

split_month<-8

weather_data_frame<-read.csv("G:/weather.csv")

bio_data_frame<-read.csv("G:/aug.csv")

PLS_results_path<-paste(out_path,"PLS_chill_force",sep="")

use_Tmean=FALSE

crossvalidate = TRUE

leg1<-182:365

leg<-182:365

lc<-length(leg1)

weather_file <- weather_data_frame

weather_file$Tmax <- suppressWarnings(as.numeric(as.character(weather_file$Tmax)))

weather_file$Tmin <- suppressWarnings(as.numeric(as.character(weather_file$Tmin)))

suppressWarnings(weather_file[which(weather_file$Tmin > weather_file$Tmax),

c("Tmin", "Tmax")] <- NA)

bio_data <- bio_data_frame

runn_mean<-15

Tmin_gaps <- interpolate_gaps(weather_file$Tmin)

weather_file$Tmin <- Tmin_gaps[[1]]

weather_file[, "Tmin_interpolated"] <- 0

suppressWarnings(weather_file[Tmin_gaps[[2]], "Tmin_interpolated"] <- 1)

Tmax_gaps <- interpolate_gaps(weather_file$Tmax)

weather_file$Tmax <- Tmax_gaps[[1]]

weather_file[, "Tmax_interpolated"] <- 0

suppressWarnings(weather_file[Tmax_gaps[[2]], "Tmax_interpolated"] <- 1)

if (use_Tmean) {

Tmean_gaps <- interpolate_gaps(weather_file$Tmean)

weather_file$Tmean <- Tmean_gaps[[1]]

weather_file[, "Tmean_interpolated"] <- 0

weather_file[Tmean_gaps[[2]], "Tmean_interpolated"] <- 1

} else {

weather_file[, "Tmean"] <- (weather_file$Tmax + weather_file$Tmin)/2

}

weather_file[which(weather_file$Month <= split_month), "Season"] <- weather_file[which(weather_file$Month <=

split_month), "Year"]

weather_file[which(weather_file$Month > split_month), "Season"] <- weather_file[which(weather_file$Month >

split_month), "Year"] + 1

weather_file[, "Date"] <- weather_file$Month * 100 + weather_file$Day

weather_file[, "JDay"] <- strptime(paste(weather_file$Month,

"/", weather_file$Day, "/", weather_file$Year, sep = ""),

"%m/%d/%Y")$yday + 1

ww <- weather_file[, "Tmean"]

rr <- weather_file[, "Tmean"]

for (dd in 1:length(ww)) {

if (dd < ceiling(runn_mean/2)) {

rr[dd] <- mean(ww[1:(dd + floor(runn_mean/2))])

}

if ((dd >= ceiling(runn_mean/2)) & (dd <= length(ww) -

ceiling(runn_mean/2))) {

rr[dd] <- mean(ww[(dd - floor(runn_mean/2)):(dd +

floor(runn_mean/2))])

}

if (dd > (length(ww) - ceiling(runn_mean/2))) {

rr[dd] <- mean(ww[(dd - floor(runn_mean/2)):length(ww)])

}

}

weather_file[, "runn"] <- rr

VIP <- function(object) {

if (object$method != "oscorespls")

stop("Only implemented for orthogonal scores algorithm. Refit with 'method = \"oscorespls\"'")

if (nrow(object$Yloadings) > 1)

stop("Only implemented for single-response models")

SS <- c(object$Yloadings)^2 * colSums(object$scores^2)

Wnorm2 <- colSums(object$loading.weights^2)

SSW <- sweep(object$loading.weights^2, 2, SS/Wnorm2,"*")

sqrt(nrow(SSW) * apply(SSW, 1, cumsum)/cumsum(SS))

}

pls_ncomp <- function(indep, dep, threshold = 30) {

dat <- data.frame(dep)

dat$runn <- indep

if (length(dep) > 15) {

suppressWarnings(pls_out <- plsr(dep ~ runn, data = dat,

ncomp = 10, validation = "CV"))

suppressWarnings(pls_cv <- crossval(pls_out, segments = 10))

res <- data.frame(ncomp = c(1:10), explvar = explvar(pls_out),

cumul = NA)

res$cumul[1] <- res$explvar[1]

for (i in 2:nrow(res)) {

res$cumul[i] <- res$cumul[i - 1] + res$explvar[i]

}

ncomp <- which(res$cumul > threshold)[1]

if (is.na(ncomp))

ncomp <- 10

} else ncomp <- 2

return(ncomp)

}

seasons <- unique(weather_file$Season)

for (yy in seasons) {

yearweather <- weather_file[which(weather_file$Season ==

yy), ]

weathervector <- c(yearweather$runn[1:365])

if (yy == seasons[1])

year_res <- weathervector

else year_res <- rbind(year_res, weathervector)

if (nrow(yearweather) == 365) {

labdates <- yearweather$Date

labJdates <- yearweather$JDay

}

}

colnames(year_res) <- c(paste("runn_", 1:365, sep = ""))

year_res <- cbind(Season = seasons, year_res)

data_set <- year_res

full_seasons <- which(!is.na(rowMeans(data_set)))

data_set <- data_set[full_seasons, ]

newseasons <- data_set[, "Season"]

suppressWarnings(bio_data <- bio_data[which(bio_data[, "Year"] %in%

newseasons), ])

suppressWarnings(bio_data <- bio_data[which(!is.na(as.numeric(as.character(bio_data$pheno)))),

])

suppressWarnings(bio <- as.numeric(as.character(bio_data$pheno)))

indep <- as.matrix(data_set[which(data_set[, "Season"] %in%

bio_data$Year), ])

indep <- indep[, 2:ncol(indep)]

if (crossvalidate) {

ncomp <- pls_ncomp(indep = indep, dep = bio)

}else ncomp = crossvalidate

sdindep <- apply(indep, 2, sd)

sdindep[which(sdindep == 0)] <- 1

PLS_output <- plsr(bio ~ indep[,leg1], ncomp, validation = "none",

method = "oscorespls", scale = sdindep[leg1])

out <- data.frame()

out[1:lc, "Date"] <- labdates[leg1]

out[1:lc, "JDay"] <- labJdates[leg1]

out[1:lc, "Coeff"] <- coef(PLS_output)

out[1:lc, "VIP"] <- VIP(PLS_output)[ncomp, ]

colnames(out) <- c("Date", "JDay", "Coefficient", "VIP")

if (is.na(out[1, "VIP"])) {

out[, "VIP"] <- 0

out[, "coef"] <- 0

nothing <- TRUE

}else {

nothing <- FALSE

}

color_bar_maker <- function(columns_yn, columns_quant, threshold,

col1, col2, col3) {

color_bars <- c(rep(NA, length(columns_yn)))

color_bars[which(columns_yn >= threshold & columns_quant < 0)] <- col1

color_bars[which(columns_yn >= threshold & columns_quant >=0)] <- col2

color_bars[which(!columns_yn >= threshold)] <- col3

return(color_bars)

}

strptime(paste("01/", split_month + 1, "/2001", sep = ""),

format = "%d/%m/%Y") - 86400

leg <- strptime(strptime(paste("01/", split_month + 1, "/2001",

sep = ""), format = "%d/%m/%Y") - 86400 + leg * 86400, "%Y-%m-%d")

tick_marks <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == "01"]

tick_labels <- as.Date(tick_marks, origin = "1999-1-2")

tick_labels <- as.POSIXlt(tick_labels)$mon

tick_labels <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec")[tick_labels + 1]

mean_clim <- colMeans(indep[,leg1], na.rm = TRUE)

dev_clim <- apply(indep[,leg1], 2, sd, na.rm = TRUE)

tick_label_pos <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == "15"]

bmp(paste(PLS_results_path, ".bmp", sep = ""), width = 1000, height = 1000, pointsize = 10)

par(mfcol = c(2, 1))

par(mar = c(6.1, 9.8, 6.1, 2.1))

par(mgp = c(4, 1.5, 0))

color_bars <- color_bar_maker(out[1:lc, "VIP"], out[1:lc, "VIP"], threshold = 0.8,

col1 = "DARK BLUE", col2 = "DARK BLUE",

col3 = "DARK GREY")

plot(leg, out[1:lc, "VIP"], main = "VIP", xlab = NA, ylab = NA,

xaxs = "i", xaxt = "n", yaxs = "i", cex.lab = 4, cex.axis = 4,

cex.main = 5, type = "h", col = color_bars, lwd = 6,family="A")

tick_marks <- grconvertX(tick_marks, from = "user", to = "user")

X_coords <- grconvertX(leg, from = "user", to = "user")

ticks_labels <- grconvertX(tick_label_pos, from = "user", to = "user")

axis(1, lwd.ticks = 3, at = tick_marks, labels = FALSE, cex.axis = 4, padj = 1)

axis(2, lwd.ticks = 3, labels = FALSE)

box(which = "plot", lwd = 3)

axis(1, lwd.ticks = 0, at = ticks_labels, labels = tick_labels, cex.axis = 4, padj = 1,family="A")

mtext(side = 2, text = "VIP", line = 6, cex = 4,family="A")

if (nothing) {

text(x = (max(X_coords) - min(X_coords))/2 + min(X_coords),

y = 0.5, adj = 0.5, labels = ("No yield produced in any model run"),

cex = 2)

}

tick_marks2 <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == "01"]

tick_marks2<-tick_marks2[2:6]

ticks_labels2 <- grconvertX(tick_marks2, from = "user",to = "user")

abline(v=ticks_labels2,lwd=2,lty="dashed",col="DARK GREY")

color_bars <- color_bar_maker(out[1:lc, "VIP"], out[1:lc, "Coefficient"],

threshold = 0.8, col1 = "RED", col2 = "DARK GREEN", col3 = "DARK GREY")

plot(leg, out[1:lc, "Coefficient"], main = "Model coefficients",

ylab = NA, xlab = NA, xaxs = "i", xaxt = "n", yaxs = "i",

cex.lab = 4, cex.axis = 4, cex.main = 5, type = "h",

col = color_bars, lwd = 6,family="A")

axis(1, lwd.ticks = 3, at = tick_marks, labels = FALSE, cex.axis = 4, padj = 1)

axis(2, lwd.ticks = 3, labels = FALSE)

box(which = "plot", lwd = 3)

axis(1, lwd.ticks = 0, at = ticks_labels, labels = tick_labels, cex.axis = 4, padj = 1,family="A")

mtext(side = 2, text = "Model coefficients", line = 6, cex = 4,family="A")

if (nothing) {

text(x = (max(X_coords) - min(X_coords))/2 + min(X_coords),

y = 0.5, adj = 0.5, labels = ("No yield produced in any model run"),

cex = 2)

}

tick_marks2 <- leg[sapply(strsplit(as.character(leg), "-"),"[", 3) == "01"]

tick_marks2<-tick_marks2[2:6]

ticks_labels2 <- grconvertX(tick_marks2, from = "user",to = "user")

abline(v=ticks_labels2,lwd=2,lty="dashed",col="DARK GREY")

dev.off()

p<-predict(PLS_output)

ll<-length(bio)

df<-data.frame(obs=bio,pred=p[(ll*(ncomp-1)+1):(ll*ncomp)])

rmse <- function(obs, pred) sqrt(mean((obs-pred)^2))

rmse<-rmse(df$obs,df$pred)

write.csv(rmse,"G:/rmse.csv",row.names = FALSE)

write.csv(out, paste("G:/", "VIP_MC.csv", sep = ""), row.names = FALSE)

# END

Code 2: Codes for the analysis and drawing of daily and monthly temperature in Fig. 2.

#Taking Soil layer 20cm as an example

#START

windowsFonts(

A=windowsFont("Times New Roman"),

B=windowsFont("Bookman Old Style"),

C=windowsFont("Comic Sans MS"),

D=windowsFont("Symbol")

)

require(chillR)

out_path<-"G:/"

runn_mean <- 15

split_month<-8

weather_data_frame<-read.csv("G:/weather.csv")

bio_data_frame<-read.csv("G:/aug.csv")

PLS_results_path<-paste(out_path,"climate_index",sep="")

use_Tmean = FALSE

main_lable<-"Soil layer 20cm"

soil_air<-read.csv("G:/soil_air.csv")

#soil_air<-soil_air[,1:4]

#soil_air<-soil_air[,c(1:3,5)]

soil_air<-soil_air[,c(1:3,6)] #Soil layer 20cm

colnames(soil_air)<-c("Year","Month","Day","Td")

require(pls)

weather_file <- weather_data_frame

weather_file$Tmax <- suppressWarnings(as.numeric(as.character(weather_file$Tmax)))

weather_file$Tmin <- suppressWarnings(as.numeric(as.character(weather_file$Tmin)))

suppressWarnings(weather_file[which(weather_file$Tminweather_file$Tmax),

c("Tmin", "Tmax")] <- NA)

bio_data <- bio_data_frame

runn_mean<-15

Tmin_gaps <- interpolate_gaps(weather_file$Tmin)

weather_file$Tmin <- Tmin_gaps[[1]]

weather_file[, "Tmin_interpolated"] <- 0

suppressWarnings(weather_file[Tmin_gaps[[2]], "Tmin_interpolated"] <- 1)

Tmax_gaps <- interpolate_gaps(weather_file$Tmax)

weather_file$Tmax <- Tmax_gaps[[1]]

weather_file[, "Tmax_interpolated"] <- 0

suppressWarnings(weather_file[Tmax_gaps[[2]], "Tmax_interpolated"] <- 1)

if (use_Tmean) {

Tmean_gaps <- interpolate_gaps(weather_file$Tmean)

weather_file$Tmean <- Tmean_gaps[[1]]

weather_file[, "Tmean_interpolated"] <- 0

weather_file[Tmean_gaps[[2]], "Tmean_interpolated"] <- 1

} else {

weather_file[, "Tmean"] <- (weather_file$Tmax + weather_file$Tmin)/2

}

weather_file[which(weather_file$Month <= split_month), "Season"] <- weather_file[which(weather_file$Month <=

split_month), "Year"]

weather_file[which(weather_file$Monthsplit_month), "Season"] <- weather_file[which(weather_file$Month

split_month), "Year"] + 1

weather_file[, "Date"] <- weather_file$Month * 100 + weather_file$Day

weather_file[, "JDay"] <- strptime(paste(weather_file$Month,

"/", weather_file$Day, "/",weather_file$Year, sep = ""), "%m/%d/%Y")$yday + 1

ww <- weather_file[, "Tmean"]

rr <- weather_file[, "Tmean"]

for (dd in 1:length(ww)) {

if (dd < ceiling(runn_mean/2)) {

rr[dd] <- mean(ww[1:(dd + floor(runn_mean/2))])

}

if ((dd >= ceiling(runn_mean/2)) & (dd <= length(ww) -

ceiling(runn_mean/2))) {

rr[dd] <- mean(ww[(dd - floor(runn_mean/2)):(dd +

floor(runn_mean/2))])

}

if (dd > (length(ww) - ceiling(runn_mean/2))) {

rr[dd] <- mean(ww[(dd - floor(runn_mean/2)):length(ww)])

}

}

weather_file[, "runn"] <- rr

seasons <- unique(weather_file$Season)

for (yy in seasons) {

yearweather <- weather_file[which(weather_file$Season ==

yy), ]

weathervector <- c(yearweather$runn[1:365])

if (yy == seasons[1])

year_res <- weathervector

elseyear_res <- rbind(year_res, weathervector)

if (nrow(yearweather) == 365) {

labdates <- yearweather$Date

labJdates <- yearweather$JDay

}

}

colnames(year_res) <- c(paste("runn_", 1:365, sep = ""))

year_res <- cbind(Season = seasons, year_res)

data_set <- year_res

full_seasons <- which(!is.na(rowMeans(data_set)))

data_set <- data_set[full_seasons, ]

newseasons <- data_set[, "Season"]

suppressWarnings(bio_data <- bio_data[which(bio_data[, "Year"] %in%

newseasons), ])

suppressWarnings(bio_data <- bio_data[which(!is.na(as.numeric(as.character(bio_data$pheno)))),

])

suppressWarnings(bio <- as.numeric(as.character(bio_data$pheno)))

indep <- as.matrix(data_set[which(data_set[, "Season"] %in% bio_data$Year), ])

indep <- indep[, 2:ncol(indep)]

sdindep <- apply(indep, 2, sd)

sdindep[which(sdindep == 0)] <- 1

lc <- 365

leg <- 1:365

strptime(paste("01/", split_month + 1, "/2001", sep = ""), format = "%d/%m/%Y") - 86400

leg <- strptime(strptime(paste("01/", split_month + 1, "/2001",

sep = ""), format = "%d/%m/%Y") - 86400 + leg * 86400, "%Y-%m-%d")

tick_marks <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == "01"]

tick_labels <- as.Date(tick_marks, origin = "1999-1-2")

tick_labels <- as.POSIXlt(tick_labels)$mon

tick_labels <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun",

"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")[tick_labels + 1]

mean_clim <- colMeans(indep, na.rm = TRUE)

dev_clim <- apply(indep, 2, sd, na.rm = TRUE)

write.csv(mean_clim,"G:/mean_clim.csv",row.names=FALSE)

mean_clim2<-read.csv("G:/mean_clim.csv")

mean_clim_for_Jday<-data.frame("mean"=rep(NA,365),"Date"=rep(NA,365),"Date2"=rep(NA,365))

mean_clim_for_Jday[,"mean"]<-mean_clim2[1:365,1]

mean_clim_for_Jday[,"Date"]<-leg[1:365]$yday+1

mean_clim_for_Jday[1:122,"Date2"]<-mean_clim_for_Jday[1:122,"Date"]-243

mean_clim_for_Jday[123:365,"Date2"]<-mean_clim_for_Jday[123:365,"Date"]+122

mean_clim_for_Jday<-mean_clim_for_Jday[which(mean_clim_for_Jday$Date2 %in% c(182:212)),]

located_date<-mean_clim_for_Jday[min(which(mean_clim_for_Jday$mean>0)),"Date"]-59

bmp(paste(PLS_results_path, ".bmp", sep = ""), width = 2000, height = 2000, pointsize = 20)

par(mfcol = c(3, 1))

par(mar = c(6.1, 9.8, 6.1, 2.1))

par(mgp = c(4, 1.5, 0))

tick_label_pos <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == "15"]

plot(leg, mean_clim[1:lc], main = main_lable, ylab = NA,

xlab = NA, xaxs = "i", yaxs = "i", xaxt = "n", cex.lab = 4,

cex.axis = 4, cex.main = 5, type = "l", lwd = 3, col = "BLACK",

ylim = c(–-15,20),family="A")

tick_marks <- grconvertX(tick_marks, from = "user", to = "user")

X_coords <- grconvertX(leg, from = "user", to = "user")

ticks_labels <- grconvertX(tick_label_pos, from = "user", to = "user")

arrows(X_coords, mean_clim[1:lc] + dev_clim[1:lc], X_coords,

mean_clim[1:lc] - dev_clim[1:lc], angle = 90, code = 3,

lwd = 6, length = 0, col = "DARK GREY")

lines(leg, mean_clim[1:lc], lwd = 3)

axis(1, lwd.ticks = 3, at = tick_marks, labels = FALSE, cex.axis = 4,padj = 1,family="A")

axis(2, lwd.ticks = 3, labels = FALSE)

box(which = "plot", lwd = 3)

axis(1, lwd.ticks = 0, at = ticks_labels, labels = tick_labels, cex.axis = 4, padj = 1,family="A")

mtext(side = 2, text = expression("Mean temperature ("^"o" * "C)"), line = 5, cex = 3,family="A")

abline(h=0,lwd=4,lty="dashed",col="DARK GREY")

located_date2<-as.character(located_date)

tick_marks2 <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == located_date2]

tick_marks3<-tick_marks2[7]

ticks_labels3 <- grconvertX(tick_marks3, from = "user",to = "user")

abline(v=ticks_labels3,lwd=4,lty="dashed",col="DARK GREY")

mtext(paste(located_date," Mar",sep=""), line=-5, side=1,at =(ticks_labels3),

cex = 2.3,family="A")

monthly_data<-weather_file[which(weather_file$Season %in% bio_data$Year),]

month_mean<-data.frame()

tempo<-data.frame()

for (i in 1:12){

monthly<-monthly_data[which(monthly_data$Month==i),]

year<-unique(monthly$Year)

q=1

for (y in year){

month_yr<-monthly[which(monthly$Year==y),]

tempo[q,1]<-mean(month_yr$Tmean)

q=q+1}

month_mean[i,1]<-i

month_mean[i,2]<-mean(tempo[,1])

month_mean[i,3]<-sd(tempo[,1])

}

colnames(month_mean)<-c("Month","Values","Sd")

up<-month_mean$Values[c(9:12,1:8)]+month_mean$Sd[c(9:12,1:8)]

down<-month_mean$Values[c(9:12,1:8)]-month_mean$Sd[c(9:12,1:8)]

lines(x=rep(tick_label_pos[1],2),y=c(down[1],up[1]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[2],2),y=c(down[2],up[2]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[3],2),y=c(down[3],up[3]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[4],2),y=c(down[4],up[4]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[5],2),y=c(down[5],up[5]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[6],2),y=c(down[6],up[6]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[7],2),y=c(down[7],up[7]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[8],2),y=c(down[8],up[8]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[9],2),y=c(down[9],up[9]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[10],2),y=c(down[10],up[10]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[11],2),y=c(down[11],up[11]),lwd=8,col="DARK GREEN")

lines(x=rep(tick_label_pos[12],2),y=c(down[12],up[12]),lwd=8,col="DARK GREEN")

points(tick_label_pos, month_mean$Values[c(9:12,1:8)],col = "RED",cex=2.5,pch=19)

soil_air[which(soil_air$Month <= split_month), "Season"] <- soil_air[which(soil_air$Month <=

split_month), "Year"]

soil_air[which(soil_air$Monthsplit_month), "Season"] <- soil_air[which(soil_air$Month

split_month), "Year"] + 1

soil_air<-soil_air[which(soil_air$Season %in% bio_data$Year),]

soil_air_mean<-data.frame()

tempo2<-data.frame()

for (i in 1:12){

soil<-soil_air[which(soil_air$Month==i),]

year<-unique(soil$Year)

q=1

for (y in year){

soil_yr<-soil[which(soil$Year==y),]

tempo2[q,1]<-mean(soil_yr$Td)

q=q+1}

soil_air_mean[i,1]<-i

soil_air_mean[i,2]<-mean(tempo2[,1])

soil_air_mean[i,3]<-sd(tempo2[,1])

}

colnames(soil_air_mean)<-c("Month","Values","Sd")

tick_label_pos3 <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == "15"]

up2<-soil_air_mean$Values[c(9:12,1:8)]+soil_air_mean$Sd[c(9:12,1:8)]

down2<-soil_air_mean$Values[c(9:12,1:8)]-soil_air_mean$Sd[c(9:12,1:8)]

lines(x=rep(tick_label_pos3[1],2),y=c(down2[1],up2[1]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[2],2),y=c(down2[2],up2[2]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[3],2),y=c(down2[3],up2[3]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[4],2),y=c(down2[4],up2[4]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[5],2),y=c(down2[5],up2[5]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[6],2),y=c(down2[6],up2[6]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[7],2),y=c(down2[7],up2[7]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[8],2),y=c(down2[8],up2[8]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[9],2),y=c(down2[9],up2[9]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[10],2),y=c(down2[10],up2[10]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[11],2),y=c(down2[11],up2[11]),lwd=8,col="DARK GREY")

lines(x=rep(tick_label_pos3[12],2),y=c(down2[12],up2[12]),lwd=8,col="DARK GREY")

points(tick_label_pos3, soil_air_mean$Values[c(9:12,1:8)],col = rgb(0,0.5,1),cex=2.5,pch=19)

gl<-round(mean(soil_air_mean$Values),digits=2)

tick_marks4 <- leg[sapply(strsplit(as.character(leg), "-"), "[", 3) == "01"]

tick_marks4<-tick_marks4[11]

ticks_labels4 <- grconvertX(tick_marks4, from = "user",to = "user")

mtext(paste("Annual mean (Soil-Air)= ",gl,sep=""), line=-19, side=1,at =(ticks_labels4),

cex = 2.3,family="A")

dev.off()

write.csv(month_mean,"G:/month_mean.csv",row.names=FALSE)

write.csv(soil_air_mean,"G:/soil_air_mean.csv",row.names=FALSE)

# END

Code 3: Codes for the Kriging interpolation in Fig. 4.

#Taking Soil layer 20cm as an example

#START

windowsFonts(

A=windowsFont("Times New Roman"),

B=windowsFont("Bookman Old Style"),

C=windowsFont("Comic Sans MS"),

D=windowsFont("Symbol")

)

library(chillR)

library(fields)

weather<-read.csv("G:/weather.csv")

weather<-fix_weather(weather)

file_path<-"G:/"

weather_data_frame = weather$weather

split_month = 8

pheno = read.csv("G:/aug.csv")

use_Tmean = FALSE

Start_JDay_chill = 65

End_JDay_chill = 118

Start_JDay_heat = 123

End_JDay_heat = 243

outpath = file_path

file_name = "pheno_trend_plot"

plot_title = "20cm soil temperature"

ylabel = NA

xlabel = NA

legend_label = NA

image_type = "png"

colorscheme = "normal"

fonttype="serif"

weather_file <- weather_data_frame

weather_file$Tmax <- suppressWarnings(as.numeric(as.character(weather_file$Tmax)))

weather_file$Tmin <- suppressWarnings(as.numeric(as.character(weather_file$Tmin)))

suppressWarnings(weather_file[which(weather_file$Tminweather_file$Tmax),

c("Tmin", "Tmax")] <- NA)

Tmin_gaps <- interpolate_gaps(weather_file$Tmin)

weather_file$Tmin <- Tmin_gaps[[1]]

weather_file[, "Tmin_interpolated"] <- 0

suppressWarnings(weather_file[Tmin_gaps[[2]], "Tmin_interpolated"] <- 1)

Tmax_gaps <- interpolate_gaps(weather_file$Tmax)

weather_file$Tmax <- Tmax_gaps[[1]]

weather_file[, "Tmax_interpolated"] <- 0

suppressWarnings(weather_file[Tmax_gaps[[2]], "Tmax_interpolated"] <- 1)

if (use_Tmean) {

Tmean_gaps <- interpolate_gaps(weather_file$Tmean)

weather_file$Tmean <- Tmean_gaps[[1]]

weather_file[, "Tmean_interpolated"] <- 0

weather_file[Tmean_gaps[[2]], "Tmean_interpolated"] <- 1

} else {

weather_file[, "Tmean"] <- (weather_file$Tmax + weather_file$Tmin)/2

}

weather_file[which(weather_file$Month <= split_month), "Season"] <- weather_file[which(weather_file$Month <=

split_month), "Year"]

weather_file[which(weather_file$Monthsplit_month), "Season"] <- weather_file[which(weather_file$Month

split_month), "Year"] + 1

weather_file[, "Date"] <- weather_file$Month * 100 + weather_file$Day

weather_file[, "JDay"] <- strptime(paste(weather_file$Month,

"/", weather_file$Day, "/", weather_file$Year, sep = ""),

"%m/%d/%Y")$yday + 1

ww <- weather_file[, "Tmean"]

rr <- weather_file[, "Tmean"]

sea <- unique(weather_file$Season)

res <- data.frame(Season = sea, Chill_Tmean = NA, Heat_Tmean = NA, Year_Tmean = NA)

if (Start_JDay_chillEnd_JDay_chill)

chill_days <- c(Start_JDay_chill:366, 1:End_JDay_chill) else {

chill_days <- Start_JDay_chill:End_JDay_chill}

if (Start_JDay_heatEnd_JDay_heat)

heat_days <- c(Start_JDay_heat:366, 1:End_JDay_heat) else {

heat_days <- Start_JDay_heat:End_JDay_heat}

for (s in sea) {

res[which(res$Season == s), "Chill_Tmean"] <- mean(weather_file[which(weather_file$Season ==

s & weather_file$JDay %in% chill_days), "Tmean"])

res[which(res$Season == s), "Heat_Tmean"] <- mean(weather_file[which(weather_file$Season ==

s & weather_file$JDay %in% heat_days), "Tmean"])

res[which(res$Season == s), "Year_Tmean"] <- mean(weather_file[which(weather_file$Season ==

s), "Tmean"])

}

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

if (pheno[i, 1] %in% res$Season) {

pheno[i, "Chill_Tmean"] <- res[which(res$Season ==

pheno[i, 1]), "Chill_Tmean"]

pheno[i, "Heat_Tmean"] <- res[which(res$Season ==

pheno[i, 1]), "Heat_Tmean"]

pheno[i, "Year_Tmean"] <- res[which(res$Season ==

pheno[i, 1]), "Year_Tmean"]

}

}

Make_date <- function(Jday) {

leg <- strptime(strptime(paste(Jday, "/2001", sep = ""),

format = "%j/%Y"), "%Y-%m-%d")

comps <- strsplit(as.character(leg), "-")

JM <- c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",

"Aug", "Sep", "Oct", "Nov", "Dec")[as.numeric(comps[[1]][2])]

return(paste(comps[[1]][3], JM))

}

if (is.na(xlabel))

xlabel <- paste("Mean temperature during ",

Make_date(Start_JDay_chill), " - ", Make_date(End_JDay_chill), " (°C)", sep = "")

if (is.na(ylabel))

ylabel <- paste("Mean temperature during ",

Make_date(Start_JDay_heat), " - ", Make_date(End_JDay_heat), " (°C)", sep = "")

pheno[, 2] <- as.numeric(as.character(pheno[, 2]))

pheno <- pheno[which(!is.na(pheno[, "pheno"])), ]

pheno <- pheno[which(!is.na(pheno[, "Chill_Tmean"])), ]

pheno <- pheno[which(!is.na(pheno[, "Heat_Tmean"])), ]

pheno <- pheno[which(!is.na(pheno[, "Year_Tmean"])), ]

k <- Krig(x = as.matrix(pheno[, c("Chill_Tmean", "Heat_Tmean")]), Y = pheno$pheno)

legend_label<-expression("ANPP (g m"^"-2" * " yr"^"-1"*")")

if (image_type == "tiff")

tiff(paste(outpath, file_name, ".tif", sep = ""), width = 1400,

height = 1500) else {

png(paste(outpath, file_name, ".png", sep = ""), width = 1400,height = 1500)}

par(family = fonttype)

par(mai = c(2.5, 2.5, 1.5, 1),lwd=4)

if (colorscheme == "bw")

colors <- colorRampPalette(c("#F9F9F9", "#343434"))(255) else {

colors <- tim.colors(255)}

surface(k, add.legend=FALSE,col = colors, type = "C", xaxt = "n", yaxt = "n",

xlab=NA,ylab=NA, cex.lab =5, cex.axis = 5, labcex = 5, asp = 1,

legend.mar=10,axis.args = list(cex.axis = 4,lwd.ticks=4,family="A"))

mtext(text = plot_title, side = 3, cex = 6, line = 1.7)

points(pheno[, c("Chill_Tmean", "Heat_Tmean")], pch = 16,cex=2.5,col="DARK BLUE")

axis(1,lwd.ticks=4,cex.axis=5,padj=0.8)

axis(2,lwd.ticks=4,cex.axis=5,padj=-0.3)

mtext(text = xlabel, side = 1, cex = 5.5, line = 7.7)

mtext(text = ylabel, side = 2, cex = 5.5, line = 7)

dev.off()

pheno <- pheno[, which(!is.na(pheno[1, ]))]

write.csv(pheno, paste(outpath, file_name, ".csv", sep = ""), row.names = FALSE)

#END

Code 4: Codes for the linear regression analysis in Fig. 5.

#Taking Soil layer 20cm as an example

#START

windowsFonts(

A=windowsFont("Times New Roman"),

B=windowsFont("Bookman Old Style"),

C=windowsFont("Comic Sans MS"),

D=windowsFont("Symbol")

)

par(mfrow = c(2, 1))

data<-read.csv("C:/Users/Administrator/Desktop/data.csv")

library(ggplot2)

library(gcookbook)

hwp1<-ggplot(data[,c("Chill_Tmean","pheno")],aes(x=Chill_Tmean,y=pheno))+geom_point(colour="RED")

hwp1+xlab("Mean temp (6 Mar-28 Apr)")+ylab(expression("ANPP (g m"^"-2" * " yr"^"-1"*")"))+xlim(0.8,3.1)+

theme(axis.title.x=element_text(size=14,family="A",colour="WHITE"),axis.title.y=element_text(size=14,family="A"),

axis.text.x=element_text(size=12,family="A"),axis.text.y=element_text(size=12,family="A"))+guides(colour=FALSE)+

stat_smooth(method=lm,colour="RED")

ggsave("C:/Users/Administrator/Desktop/hwp1.png",width=5.4,height=5.4,unit="cm",dpi=1000)

hwp2<-ggplot(data[,c("Heat_Tmean","pheno")],aes(x=Heat_Tmean,y=pheno))+geom_point(colour="BLUE")

hwp2+xlab("Mean temp (3 May-31 Aug)")+ylab(expression("ANPP (g m"^"-2" * " yr"^"-1"*")"))+xlim(12.8,15.5)+

theme(axis.title.x=element_text(size=14,family="A",colour="WHITE"),axis.title.y=element_text(size=14,family="A"),

axis.text.x=element_text(size=12,family="A"),axis.text.y=element_text(size=12,family="A"))+guides(colour=FALSE)+

stat_smooth(method=lm,colour="BLUE")

ggsave("C:/Users/Administrator/Desktop/hwp2.png",width=5.4,height=5.4,unit="cm",dpi=1000)

#END

#Note: We only listed parts of all the codes used in the present study. If you like them #and want to know more, please contact us (E-mail: ), #and we are quite pleased to share what we have with you. Thanks again for your #reading of our long codes in R language, and best wishes to you.

1