Introduction

Geographic Resources Analysis Support System (GRASS) is the pioneer member of the is a very powerful geographic information system (GIS) software for geospatial data analysis, image processing, spatiotemporal modeling, and visualization (https://grass.osgeo.org/). Similarly, R is a free statistical software, and has now over 15,000 extension packages developed independently. Combining their capabilities will greatly improve a user’s processing power.

In this module, the students will learn to

Please follow the steps below to complete GRASS GIS task within R and RStudio IDE:

1. Create/Open a GRASS databaase

The initGRASS command from rgrass library either opens (if existing) or creates a GRASS database. You need to supply the GISDbase folder C:/session10, location loc and mapset PERMANENT.

library("rgrass")
initGRASS("C:/Program Files/GRASS GIS 8.2",
                 gisDbase="C:/session10", location="loc", 
                 mapset="PERMANENT", override=TRUE)

2. Set CRS

If the GRASS database is newly created, you need to set the Coordinate Reference System (CRS) first. This tutorial uses UTM 51N.

execGRASS("g.proj", flags = "c", epsg = 32651)

3. Import spatial data

We will import raster and vector layers on the newly created GRASS database, and then and change the environmental settings using g.region

If the GRASS database is newly created, you need to import raster and vector datasets, and setup its working environment.

a. import a raster layer

The next command will work only if the digital elevation model (DEM) dem_region8.tif is stored in C:/session10/. Otherwise, download the image in your local folder and place its appropriate folder location.

#GRASS: r.in.gdal input=D:/Jun_turnover_files/DEM/dem_region8.tif output=dem8 --o
execGRASS("r.in.gdal", 
          input="C:/session10/dem_region8.tif",
          output="dem8",
          flag="overwrite")

# check if raster dem8 is properly imported
execGRASS("g.list", 
          type="raster", pattern="dem8") # GRASS: g.list type=raster

b. Use the dem8 raster properties

as the AOI region settings of the GRASS database

  • check the default region settings
# GRASS equivalent: g.region -p
execGRASS("g.region", flag="p")
  • change AOI region settings
# GRASS equivalent: g.region raster=dem8 -p
execGRASS("g.region", raster="dem8", flag="p")

c. Import a vector layer

The next command will work only if the vector layer samarisland.geojson is saved in C:/session10/ folder. It contains a boundary delineation of the 3 provinces of Samar.

# GRASS: v.in.ogr input=D:/gisclass/samarisland.geojson output=samarisland
execGRASS("v.in.ogr",
          input="C:/session10/samarisland.geojson",
          output="samarisland",
          flag="overwrite")

# check if properly imported
# GRASS: g.list type=vector
execGRASS("g.list", type="vector", pattern="samarisland") # g.list type=vector
  • Erase unnecessary columns from the imported vector’s attribute table
# check the original column names
# GRASS: db.columns table=samarisland
execGRASS("db.columns", table="samarisland")

# delete unnecessary columns
# GRASS: v.db.dropcolumn map=samarisland columns=ID_0,ISO,ID_1,NAME_0,VARNAME_1,NL_NAME_1,HASC_1,CC_1,TYPE_1,ENGTYPE_1,VALIDFR_1,VALIDTO_1,REMARKS_1
execGRASS("v.db.dropcolumn",
          map="samarisland",
          columns="ID_0,ISO,ID_1,NAME_0,VARNAME_1,NL_NAME_1,HASC_1,CC_1,TYPE_1,ENGTYPE_1,VALIDFR_1,VALIDTO_1,REMARKS_1")

# check the remaining column names
execGRASS("db.columns", table="samarisland")
  • Add a new column to the vector

Add a new column and assign a value of 1. It will be used in creating a raster layer with a value of 1 for all the 3 samar provinces. We will use this raster to mask or limit the the analysis within the terrestrial boundaries of the 3 provinces of Samar. Neighboring provinces and the sea will be excluded in the analysis as long as a mask is set.

# "add an column name imask"
# v.db.addcolumn map=samarisland columns="imask integer"
execGRASS("v.db.addcolumn",
          map="samarisland",
          columns="imask integer")

# assign a value of 1 to imask column
# GRASS: v.db.update map=samarisland column=imask value=1
execGRASS("v.db.update",
          map="samarisland",
          column="imask",
          value="1")

d. Reduce the g.region settings

To enhance processing speed and use lesser file storage, we will reduce our area of interest using g.region settings based from a smaller extent of a raster. To do this, we have to create a new raster covering only the 3 Samar provinces. Then, use that smaller raster compared to the original dem8 raster, as the new basis for the g.region settings.

  • Convert vector to raster

Use v.to.rast (https://grass.osgeo.org/grass82/manuals/v.to.rast.html) to convert from vector to raster. The code below will create a raster with a value of 1 for the 3 provinces of Samar, the rest will have a NULL value.

# vector to raster convertion
#v.to.rast input=samarisland type=area output=samisland use=attr attribute_column=imask value=1 --o
execGRASS("v.to.rast",
          input="samarisland",
          type="area",
          output="samisland",
          use="attr",
          attribute_column="imask",
          flag="overwrite")

# check if raster layers samisland is created
execGRASS("g.list", type="raster", pattern="samisland")
  • Zoom the g.region settings to the non-zero extent of the input raster

We will reduce the extent of our region area of interest to the extent samisland raster, which is smaller than the extent of dem8 used earlier. We do this by changing the g.region area of interest to the non-zero extent of the samarisland raster. The code below will reduce the extent of the area of interest in the succeeding operations The GRASS command g.region -p will display their difference before and after running the g.region zoom=samisland code.

  • check current region
# GRASS: g.region -p
execGRASS("g.region", flag="p")
  • Reduce the extent of the region area of interest
# GRASS:g.region zoom=samislsamislandand
execGRASS("g.region", zoom="samisland")
  • check current region, and compare with the previous region
# GRASS: g.region -p
execGRASS("g.region", flag="p")

e. Using mask

We can further limit the processing area to the non-zero part of the input mask, which can either be a raster or vector layer. We will limit processing only within the island of Samar using the r.mask module. Data processing will be within the non-zero pixels of the input raster samisland mask, while the sea and the neighboring provinces are ignored.

#GRASS: r.mask raster=samisland
execGRASS("r.mask", raster="samisland",
          flag="overwrite")

Run execGRASS("r.mask", flag="r") to remove the mask

4. Delineate a synthetic stream

#Delineate a watershed basin boundary
#GRASS: r.watershed elevation=dem8 threshold=50000 stream=d.stream --o
execGRASS("r.watershed",
          elevation="dem8",
          threshold=50000,
          stream="rstream",
          flag="overwrite")

If there is no error, the next command will show the rstream raster

execGRASS("g.list", type="raster", pattern="rstream")

The r.thin command will make stream width into 1 pixel wide only in prepation for vector convertion

#r.thin --o input=d.stream output=stream_thin
execGRASS("r.thin",input="rstream",
          output="rstream_thin", 
          flag="overwrite")
#r.to.vect --o type=line input=stream_thin output=vstream
execGRASS("r.to.vect",
          type="line",
          input="rstream_thin",
          output="vstream",
          flag="overwrite")

5. Generate a landform map

Any area with 8 degrees or less slope will be considered as flat.

#r.geomorphon elevation=dem8 forms=rgeomorph flat=5
execGRASS("r.geomorphon",
          elevation="dem8",
          forms="rgeomorph",
          flat=8,
          flag="overwrite")
#display landform categories
#r.category rgeomorph
execGRASS("r.category", map="rgeomorph")

6. Delineate a watershed basin boundary

The r.watershed module above delineates a watershed basin boundary and stream network from a digital elevation model (DEM). Use dem8 as the input DEM, threshold or a minimum 300,000 pixels (resolution is approcimately 30x30 meter) to be considered a watershed. Any sub-watershed that has less than 300,000 pixels are ignored, leading to NULL pixels along the coastal areas.

a. Get only large watersheds by enlarging the threshold=300,000

#r.watershed elevation=dem8 basin=rbasin threshold=300000 --o
execGRASS("r.watershed",
          elevation="dem8",
          threshold=300000,
          basin="rbasin",
          flag="overwrite")

b. Reclassify to combine watersheds

#r.recode input=rbasin output=rbasin4 rules=C:/session10/rc.txt
execGRASS("r.recode",
          input="rbasin",
          output="rbasin2",
          rules="C:/session10/rc.txt",
          flag="overwrite")

The rc.txt contains:

2:2:1:1
4:4:2:2
6:6:3:3
8:8:4:4
12:16:5:5
18:26:6:6
28:32:7:7
34:34:8:8
36:36:9:9
38:38:10:10
40:40:11:11
42:42:12:12

c. check raster statistics to the area per subwatershed

execGRASS("r.report",
          map="rbasin2", 
          units="h",
          output="C:/session10/statreport.txt")

d. convert watershed boundaries from raster to vector

#r.to.vect type=area input=rbasin2 output=vbasin --o -sv
execGRASS("r.to.vect",
          type="area",
          input="rbasin2",
          output="vbasin",
          flag=c("overwrite", "s", "v"))

execGRASS("g.list",type="vector", pattern="vbasin")

e. compute the area per watershed in hectare

# add a hectare column
# execGRASS("v.db.dropcolumn",
#           map="vbasin",
#           columns="hectare")

execGRASS("v.db.addcolumn",
          map="vbasin",
          columns="hectare double precision")
execGRASS("db.columns", table="vbasin")

# compute area in hectare
#v.to.db --o map=vwatershed2 layer=1 type=boundary option=area columns=hectare unit=hectares
execGRASS("v.to.db",
          map="vbasin",
          type="boundary",
          option="area",
          columns="hectare",
          units="hectares",
          flag="overwrite")

# display column names of the attribute table
execGRASS("db.columns", table="vbasin")
  • display the newly computed column values
#execGRASS("db.describe", table="vbasin")
execGRASS("v.db.select",map="vbasin", 
          columns=c("cat","hectare"),
          format="csv")

7. Cross tabulate watershed and landform maps

#r.cross input=rbasin,rgeomorph output=crossbasmorp --o
execGRASS("r.cross", 
          input=c("rbasin2","rgeomorph"),
          output="crossbasmorp",
          flag="overwrite")
execGRASS("g.list", type="raster",pattern="crossbasmorp")
#r.report map=crossbasmorp units=h output=C:/session10/crosstab.txt
execGRASS("r.report", map="crossbasmorp", units="h", 
          output="C:/session10/crosstab.txt", 
          flag="overwrite")

Summary

This tutorial may be your first use of R, though not yet that extensive since we used only the two (2) rgrass package functions initGRASS and execGRASS. initGRASS simply opened an invisible GRASS GIS interface within R. On the other hand, execGRASS run GRASS GIS commands with almost exactly the same syntax as running in the GRASS console or command prompt.

In summary, we were able to:

Though we are able to demonstrate that we can use R and RStudio as the integrated development environment (IDE) for GRASS, in the next sessions, we shall discover the power of R both in spatial and nonspatial analysis of geospatial data.