Chapter 12 Calculating class area from raster
12.1 Simple area and area fraction calculations on a classified raster
For this tutorial you will need to load the following packages:
library(raster)
library(sf)
library(tidyverse)You will often come across the task of extracting the area each of your raster classes occupies within your entire raster area. There is a simple way of doing this using raster and dplyr. The output will be a comprehensive table. First let’s create some dummy data to work with:
12.1.1 Creating dummy data
x <- raster(ncol=100, nrow=100, xmn=-10000, xmx=10000, ymn=-10000, ymx=10000)
res(x)<-100 # we are using a resolution of 100 x 100 so that each pixel is 1ha in size
#populate the raster with values
values(x)<-base::sample(5, ncell(x), replace = T, prob = c(10,30,20,5,35))
plot(x)
Our raster now contains 5 classes that could e.g. be land-use types such as forest, infrastructure or pasture. We additionally gave each class a probability of occurrence so that we can double check of our calculated areas are correct. In total, our raster x has 4^{4} cells.
12.1.2 Preparing the raster for area calculation
To get area metrics, we need to transform the raster into a data frame:
rast_df<-x%>%as.data.frame(xy = T, na.rm = T)To count each pixel, we can assign an extra column to this dataframe with an ID 1 to be able to tally all cells. Additionally, we are extracting the resolution of our raster as a variable to our environment to later calculate the area.
rast_df$ID<-1
reso<-res(x)[1]
head(rast_df)## x y layer ID
## 1 -9950 9950 3 1
## 2 -9850 9950 5 1
## 3 -9750 9950 4 1
## 4 -9650 9950 4 1
## 5 -9550 9950 2 1
## 6 -9450 9950 2 1
The layer column contains the class each pixel was assigned to. This will be universal for any raster you put in. ID is the same for each row, this is only needed in the next step.
12.1.3 Compiling a comprehensive table
area<-rast_df%>%group_by(layer)%>%
summarise(pixelsum = sum(ID), area_ha = (pixelsum*reso^2)/10000)%>%
mutate(sumA = sum(pixelsum), per = 100*pixelsum/sumA)%>%
rename(class = layer)## `summarise()` ungrouping output (override with `.groups` argument)
area## # A tibble: 5 x 5
## class pixelsum area_ha sumA per
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 4020 4020 40000 10.0
## 2 2 11978 11978 40000 29.9
## 3 3 7951 7951 40000 19.9
## 4 4 1930 1930 40000 4.82
## 5 5 14121 14121 40000 35.3
And there we go. Each class has it’s pixelsum calculated, then using the sum we can calculate the area in ha (or else, here you can alternate the code). In this case the pixel sum matches our area_ha because one pixel is already of size 1 ha. We can change the code to e.g. calculate area_km2.
area_km2<-rast_df%>%group_by(layer)%>%
summarise(pixelsum = sum(ID), area_km2 = pixelsum/100)%>%
mutate(sumA = sum(pixelsum), per = 100*pixelsum/sumA)%>%
rename(class = layer)## `summarise()` ungrouping output (override with `.groups` argument)
area_km2## # A tibble: 5 x 5
## class pixelsum area_km2 sumA per
## <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 4020 40.2 40000 10.0
## 2 2 11978 120. 40000 29.9
## 3 3 7951 79.5 40000 19.9
## 4 4 1930 19.3 40000 4.82
## 5 5 14121 141. 40000 35.3
Next we calculate the sum of all pixels (sumA) using mutate() to get the total raster area. This should in this case be the same as ncell(x) (40000). To derive the percentage of the entire each class occupies, we just need to divide the pixelsum of each class by the total sum and multiply by 100. This should match our probabilities we assigned for each class when filling the raster with values:
area_km2$per == summary(as.factor(values(x)))/400## 1 2 3 4 5
## TRUE TRUE TRUE TRUE TRUE
Enjoy trying it out on your own raster with some actual class ares!