if (grepl("monsoon_asia", getwd())) {
load(".RData")
else {
} setwd("monsoon_asia/")
load(".RData")
}
Agriculture in East Asian Monsoon Area
Diverse forms of agriculture in Southeast Asia
Introduction
Southeast Asia is one of the regions where a wide range of agricultural practices has been carried out. Despite the overwhelming influence of the market economy, the tireless efforts of smallholder farmers over more than 1,000 years have created remarkably diverse array of farming systems. For example, in rice farming, which has long been the foundation of food security, farmers have developed numerous rice varieties, adaptive techniques to cope with erratic rainfall, fluctuations in crop prices, and, at times, strategies to escape the control of dominant political powers (Scott 2010). These farming techniques are well adapted to their local ecosystems and socioeconomic conditions.
While these agricultural practices have evolved in response to micro-landscape, much like the Darwinian evolution of living organisms, agricultural scientists have sought to construct overarching frameworks to explain farmers’ behaviors. Needless to say, socioeconomic factors such as food productions, crop market price, demographic dynamics (Boserup 1965) strongly influence these behaviors, but natural conditions also play a significant role in shaping farming practices over the long run.
Abundant natural resources and highly variable natural conditions are often considered as the two main factors shaping agriculture in this region. However, these two are frequently at odds. Interestingly, there is a clear divide among researchers: some emphasize environmental instability, while others highlight resource abundance. Researchers focusing on mainland Southeast Asia, such as Thailand, Laos, Myanmar, Vietnam, and Cambodia, tend to stress how farmers adapt to unstable and unpredictable natural conditions, especially precipitation (Fukui and Fukui 1993, Kono et al. 2012). On the other hand, scholars studying maritime Southeast Asia often emphasize the area’s rich biomass and high primary productivity (Tanaka 2010).
In this short essay, I aim to examine whether the instability or the abundance of natural resources has been the primary factor shaping agricultural systems in the long run, or whether both factors have played complementary roles. I also outline the methodological steps taken to approach this research questions.
East Asian Monsoon Area
The East Asian Monsoon region is unique in terms of its rainfall patterns (Kira 2012). Unlike other tropical and subtropical areas, it lacks arid zones. As a result, vegetation transitions continuously along temperature gradients, contributing to exceptionally rich biodiversity. This region also plays a vital role in agricultural production, making it and ideal context for comparing temperate and tropical farming systems.
Rather than focusing on meteorological perspectives, I aim to approach this topic from an agricultural standpoint to gain deeper insights into farming practices that sustains a significant portion of population.
Method
Load data
Load Library
library(tidyverse)
library(rgeoboundaries)
library(sf)
library(ncdf4)
# library(raster) duplication. The terra works instead of this.
library(terra)
library(rlang)
library(utils)
library(R.utils)
library(leaflet)
library(leaflet.extras)
library(htmlwidgets)
library(tmap)
Administrative Boundary
Visit geoBoundaries. Also see (Moraga and Baker 2022).
Show administrative boundary
<- c("THA", "LAO", "MYS", "IDN", "KHM", "MMR", "VNM", "TLS", "SGP", "BRN", "PHL")
se_asia <- c("PRK", "KOR", "JPN", "CHN", "MNG", "TWN")
e_asia <- c(se_asia, e_asia) east_monsoon
National border of Lao PDR
<- gb_adm0("LAO")
laos # laos <- geoboundaries("LAO")
plot(st_geometry(laos), graticule = TRUE, axes = TRUE)
# plot(laos$geometry, graticule = TRUE, axes = TRUE)
Provincial border
<- gb_adm1("LAO")
laos_prov plot(laos_prov$geometry, graticule = TRUE, axes = TRUE)
District border
<- gb_adm2("LAO")
laos_dis plot(laos_dis$geometry, graticule = TRUE, axes = TRUE)
National borders in East Asia
<- gb_adm0(east_monsoon)
em_boundary
# Original data is too concise for the purpose, simplify the boundaries.
<- st_simplify(em_boundary, dTolerance = 0.01)
em_boundary_simp plot(st_geometry(em_boundary_simp))
Research Area
Myanmar lies west of the specified longitude; therefore, replace China’s longitude value accordingly. Similarly, since Japan is located north of the specified latitude, replace China’s latitude value with that of Japan. Japan is also situated east of the specified longitude.
The research area includes a 3 km buffer. Given that 0.01 degrees correspond to approximately 1.11 km, appropriate adjustments should be made.
<- em_boundary %>% st_bbox
tmp <- em_boundary %>% filter(shapeGroup == "MMR") %>% st_bbox
tmp_xmin <- em_boundary %>% filter(shapeGroup == "JPN") %>% st_bbox
tmp_ymax <- em_boundary %>% filter(shapeGroup == "JPN") %>% st_bbox
tmp_xmax <- em_boundary %>% filter(shapeGroup == "IDN") %>% st_bbox
tmp_ymin 1]] <- tmp_xmin[[1]]
tmp[[4]] <- tmp_ymax[[4]]
tmp[[2]] <- tmp_ymin[[2]]
tmp[[3]] <- tmp_xmax[[3]]
tmp[[1] <- tmp[1] - 0.03
tmp[2] <- tmp[2] - 0.03
tmp[3] <- tmp[3] + 0.03
tmp[4] <- tmp[4] + 0.03 tmp[
Use st_as_sfc() %>% st_sf() if you only have geometry data and need to manually create an sf object.
st_as_sfc(x): Converts an object (like WKT, WKB, or a numeric matrix) into a simple feature geometry list-column (sfc).
st_sf(sfc_object): Wraps the sfc object in a simple feature (sf) data frame.
<- tmp %>% st_as_sfc %>% st_sf
aoi plot(aoi, graticule = TRUE, axes = TRUE)
Mapping
Leaflet
<- "figures/leaflet/"
dir_leaflet <- leaflet(aoi) %>% addTiles() %>% addPolygons(color = "blue", weight = 1, fillOpacity = 0.1)
m <- paste0("aoi", ".html")
filename saveWidget(m, paste0(dir_leaflet, filename), selfcontained = TRUE)
leaflet(aoi) %>% addTiles() %>% addPolygons(color = "blue", weight = 1, fillOpacity = 0.1)
Area of interest
tmap
tmap_mode("view")
<- tm_shape(aoi) + tm_borders(lwd = 2)
p p
Area of interest
Climate Data
TerraClimate is a high-spatial resolution (4km) gridded dataset of monthly climate and hydroclimate for global land surfaces from 1958 to present ( TERRACLIMATE Dataset; Abatzoglou et al. (2018)).
In this research, monthly data for precipitation, temperature (max and min), climate water deficit, and potential and actual evapotranspiration provided in this database are used.
Importing Terraclimate data into R
- NetCDF
esri explains that NetCDF (network Common Data Form) is a file format for storing multidimensional scientific data (variables) such as temperature, humidity, pressure, wind speed, and direction.
- SpatRaster
Methods to create a SpatRaster. These objects can be created from scratch, from a filename, or from another object.
A SpatRaster represents a spatially referenced surface divided into three dimensional cells (rows, columns, and layers).
When a SpatRaster is created from one or more files, it does not load the cell (pixel) values into memory (RAM). It only reads the parameters that describe the geometry of the SpatRaster, such as the number of rows and columns and the coordinate reference system. The actual values will be read when needed.
Note that there are operating system level limitations to the number of files that can be opened simultaneously. Using a SpatRaster of very many files (e.g. 10,000) may cause R to crash when you use it in a computation. In situations like that you may need to split up the task or combine data into fewer (multi-layer) files. Also note that the GTiff format used for temporary files cannot store more than 65535 layers in a single file.
(Source: R documentation)
Precipitation
<- seq(1958,2024)
years <- "data/TerraClimate_data/"
ncpath <- "TerraClimate_ppt_"
ncname
for (x in years){
<- paste0(ncpath, ncname, x, ".nc")
ncfname <- rast(ncfname, subds = "ppt")
object assign(paste0("cl_ppt_", x), object)
}plot(cl_ppt_1958[[1]])
Cropping climate data by AOI
- Crop monthly precipitation data by AOI and save it to
tif
format file.
<- "data/raster/"
ras_dir
system.time(
for (x in years) {
<- get(paste0("cl_ppt_", x))
fname <- crop(fname, aoi)
object <- paste0("mon_cl_ppt_", x)
cname <- writeRaster(object,
c_object filename = file.path(ras_dir, paste0(cname, ".tif")),
overwrite = TRUE)
assign(cname, c_object)
} )
- Mapping Precipitation
# load data into R
<- "data/raster/"
ras_dir for (x in years){
<- paste0(ras_dir, "mon_cl_ppt_", x, ".tif")
ncfname <- rast(ncfname)
object assign(paste0("mon_cl_ppt_", x), object)
}
# Display
<- mon_cl_ppt_1958[[1]]
r <- colorNumeric(palette = "viridis", domain = values(r), na.color = "transparent")
r_pal
leaflet() %>%
addTiles() %>% # Add base map
addRasterImage(r, colors = r_pal, opacity = 0.8) %>%
addLegend(pal = r_pal, values = values(r), title = "Raster Values")
Cropped precipitation distribution in January 1958
Creating annual rainfall object
- Creating a multilayer object accommodating annual rainfalls from 1958 to 2024
# Annual rainfall
<- "mon_cl_ppt_"
fhead if (exists("a_rain")) {
rm(a_rain)
}for (x in years) {
<- paste0(fhead, x)
fname if (exists(fname)) {
<- get(fname)
rd00 <- app(rd00, sum) # calc() in the raster package
rd01 names(rd01) <- x
if (!exists("a_rain")) {
<- rd01
a_rain else {
} <- c(a_rain, rd01)
a_rain
}else {
} warning(paste0("The object does not exits: ", x))
}
}
cat(src(a_rain), "\n")
# newcrs <- "+proj=longlat +datum=WGS84"
<- "EPSG:4326"
newcrs <- project(a_rain, newcrs)
a_rain <- writeRaster(a_rain,
a_rain filename = file.path(
ras_dir,"a_rain.tif"
overwrite = TRUE
), )
- Mapping annual rainfall in 1958
Tmap
<- rast(file.path(ras_dir, "a_rain.tif"))
a_rain tmap_mode("view")
tm_shape(a_rain[[1]]) + tm_raster()
Leaflet
<- colorNumeric(palette = "viridis", domain = values(a_rain[[1]]), na.color = "transparent")
r_pal
# for R in docker
# base_path <- "./data/raster"
# r <- raster(file.path(base_path, "ar_1958.gri"))
leaflet() %>%
addTiles() %>% # Add base map
addRasterImage(a_rain[[1]], colors = r_pal, opacity = 0.8) %>%
addLegend(pal = r_pal, values = values(a_rain[[1]]),
title = "Raster Values")
Importing other climate variables
max and min temperature, ppt, aat, soil moisture, and def
<- seq(1958, 2024)
years <- "data/TerraClimate_data/"
ncpath <- "TerraClimate_"
ncname <- c("aet", "def", "pet", "q", "tmax", "tmin")
variables
for (var in variables) {
for (ye in years) {
<- paste0(ncpath, ncname, var, "_", ye, ".nc")
ncfname <- rast(ncfname, subds = cli)
object assign(paste0("cl_", var, "_", ye), object)
}printf("\n%s has been successfully imported.", var)
}
Cropping climate data by AOI.
for (var in variables) {
for (ye in years) {
<- paste0("cl_", var, "_", ye)
fname <- get(fname)
fdata <- crop(fdata, aoi)
object <- paste0("mon_", fname)
cname <- writeRaster(object,
c_object filename = file.path(
ras_dir,paste0(cname, ".tif")
),overwrite = TRUE
)assign(cname, c_object)
} }
Remove unnecessary intermediate objects
rm(list = ls(pattern = "^cl_"))
rm(list = ls(pattern = "^mon_"))
Net Primary Production (NPP)
Estimation of Potential NPP
The Potential Net Primary Production (NPP) is estimated using Miami model, as presented in Lieth (1973)(Lieth (1973)).
\[ NPP(Temp, Precip) = min((\frac{a}{1+exp(b-c*Temp)}), (d(1-exp(e*(Precip))))) \]
Where \(Temp\) is the mean annual temperature (°C), \(Precip\) is the mean annual precipitation (mm/year),
The constants are empirically determined as: \[ \begin{align} a &= 3000 \\ b &= 1.315 \\ c &= 0.119 \\ e &= 0.000664 \\ \end{align} \]
This model estimates NPP as the minimum of two functions: one driven by temperature and the other by precipitation.
First of all, we create datasets of max and minimum annual temperatures from 1958 to 2024.
<- seq(1958, 2024)
years <- "data/raster/"
ras_dir
for (var in c("tmax", "tmin")) {
for (year in years) {
<- paste0("mon_cl_", var, "_", year)
fname <- paste0(fname, ".tif")
file_name <- rast(file.path(ras_dir, file_name))
rasd assign(fname, rasd)
}
}
<- "tmin"
var <- paste0("mon_cl_", var, "_")
fhead <- paste0("a_", var)
objname if (exists(objname)) {
rm(list = objname)
}for (year in years) {
<- paste0(fhead, year)
fname if (exists(fname)) {
<- get(fname)
rd00 <- app(rd00, mean)
rd01 names(rd01) <- year
if (!exists(objname)) {
assign(objname, rd01)
else {
} <- get(objname)
existing <- c(existing, rd01)
combined assign(objname, combined)
}else {
} warning(paste0("The object does not exits: ", year))
}printf("%d is successfully imported\n", year)
}
<- c("tmax", "tmin")
vars for (var in vars) {
<- paste0("a_", var)
fname writeRaster(fname, filename = file.path( ras_dir, paste0(fname, ".tif")), overwrite = TRUE)
}rm(list = ls(pattern = "^mon_"))
Now, we can compute mean annual temperature.
<- c("a_tmax", "a_tmin")
vars for (var in vars) {
<- rast(file.path(ras_dir, paste0(var, ".tif")))
fdata assign(var, fdata)
}
# Calculate mean max temperature and min temperature for each layer
<- (a_tmin + a_tmax) / 2
a_tmean
writeRaster(a_tmean, filename = file.path( ras_dir, "a_tmean.tif"), overwrite = TRUE)
Finally, we can estimate NPP using the Miami model.
<- c("a_rain", "a_tmean")
vars for (var in vars) {
<- rast(file.path(ras_dir, paste0(var, ".tif")))
fdata assign(var, fdata)
}
<- function(x) {
fun_t 3000 / (1 + exp(1.315 - 0.119 * x))
}<- function(x) {
fun_p 3000 * (1 - exp(-0.000664 * x))
}<- app(a_tmean, fun_t)
npp_t <- app(a_rain, fun_p)
npp_p <- min(npp_t, npp_p)
a_npp
writeRaster(npp_t, filename = file.path(ras_dir, "npp_t.tif"), overwrite = TRUE)
writeRaster(npp_p, filename = file.path(ras_dir, "npp_p.tif"), overwrite = TRUE)
writeRaster(a_npp, filename = file.path(ras_dir, "a_npp.tif"), overwrite = TRUE)
##### mean annual npp for all
<- rast(file.path(ras_dir, paste0("a_npp.tif")))
a_npp <- subset(a_npp, 1)
rmap <- global(rmap, fun = "max", na.rm = TRUE)[[1]]
max_val <- c(0, 200, seq(500, 2500, by = 500), max_val)
npp_legend
tmap_mode("view")
<- tm_shape(rmap) +
p tm_raster(col.scale = tm_scale(col = npp_legend, values = "brewer.bu_gn"))
p
NPP in 1958