Plot Raster Data

Last updated on 2024-09-10 | Edit this page

Overview

Questions

  • How can I create categorized or customized maps of raster data?
  • How can I customize the colour scheme of a raster image?

Objectives

After completing this episode, participants should be able to…

  • Build customized plots for a single band raster using the ggplot2 package.

Things you’ll need to complete this episode

See the setup instructions for detailed information about the software, data, and other prerequisites you will need to work through the examples in this episode.

In this part, we will plot our raster object using ggplot2 with customized coloring schemes. We will continue working with the Digital Surface Model (DSM) raster from the previous episode.

Plotting Data Using Breaks

In the previous plot, our DSM was coloured with a continuous colour range. For clarity and visibility, we may prefer to view the data “symbolized” or coloured according to ranges of values. This is comparable to a “classified” map. For that, we need to tell ggplot() how many groups to break our data into and where those breaks should be. To make these decisions, it is useful to first explore the distribution of the data using a bar plot. To begin with, we will use dplyr’s mutate() function combined with cut() to split the data into 3 bins.

R

DSM_TUD_df <- DSM_TUD_df %>%
  mutate(fct_elevation = cut(`tud-dsm-5m`, breaks = 3))

ggplot() +
    geom_bar(data = DSM_TUD_df, aes(fct_elevation))

To see the cut-off values for the groups, we can ask for the levels of fct_elevation:

R

levels(DSM_TUD_df$fct_elevation)

OUTPUT

[1] "(-5.49,27.1]" "(27.1,59.6]"  "(59.6,92.2]" 

And we can get the count of values (that is, number of pixels) in each group using dplyr’s count() function:

R

DSM_TUD_df %>% 
  count(fct_elevation)

OUTPUT

  fct_elevation      n
1  (-5.49,27.1] 277100
2   (27.1,59.6]   1469
3   (59.6,92.2]    123

We might prefer to customize the cut-off values for these groups. Lets round the cut-off values so that we have groups for the ranges of -10 - 0m, 0 - 5m, and 5 - 100m. To implement this we will give cut() a numeric vector of break points instead of the number of breaks we want.

R

custom_bins <- c(-10, 0, 5, 100)

DSM_TUD_df <- DSM_TUD_df %>%
  mutate(fct_elevation_cb = cut(`tud-dsm-5m`, breaks = custom_bins))

levels(DSM_TUD_df$fct_elevation_cb)

OUTPUT

[1] "(-10,0]" "(0,5]"   "(5,100]"

Data tip

Note that 4 break values will result in 3 bins of data.

The bin intervals are shown using ( to mean exclusive and ] to mean inclusive. For example: (0, 10] means “from 0 through 10”.

And now we can plot our bar plot again, using the new groups:

R

ggplot() +
  geom_bar(data = DSM_TUD_df, aes(fct_elevation_cb))

And we can get the count of values in each group in the same way we did before:

R

DSM_TUD_df %>% 
  count(fct_elevation_cb)

OUTPUT

  fct_elevation_cb      n
1          (-10,0] 113877
2            (0,5] 101446
3          (5,100]  63369

We can use those groups to plot our raster data, with each group being a different colour:

R

ggplot() +
  geom_raster(data = DSM_TUD_df , aes(x = x, y = y, fill = fct_elevation_cb)) + 
  coord_quickmap()

The plot above uses the default colours inside ggplot2 for raster objects. We can specify our own colours to make the plot look a little nicer. R has a built in set of colours for plotting terrain, which are built in to the terrain.colors() function. Since we have three bins, we want to create a 3-colour palette:

R

terrain.colors(3)

OUTPUT

[1] "#00A600" "#ECB176" "#F2F2F2"

The terrain.colors() function returns hex colours - each of these character strings represents a colour. To use these in our map, we pass them across using the scale_fill_manual() function.

R

ggplot() +
 geom_raster(data = DSM_TUD_df , aes(x = x, y = y, fill = fct_elevation_cb)) + 
    scale_fill_manual(values = terrain.colors(3)) + 
    coord_quickmap()

More Plot Formatting


If we need to create multiple plots using the same colour palette, we can create an R object (my_col) for the set of colours that we want to use. We can then quickly change the palette across all plots by modifying the my_col object, rather than each individual plot.

We can give the legend a more meaningful title by passing a value to the name argument of the scale_fill_manual() function.

R

my_col <- terrain.colors(3)

ggplot() +
 geom_raster(data = DSM_TUD_df , aes(x = x, y = y,
                                      fill = fct_elevation_cb)) + 
    scale_fill_manual(values = my_col, name = "Elevation") + 
    coord_quickmap()

The axis labels x and y are not necessary, so we can turn them off by passing element_blank() to the relevant part of the theme() function.

R

ggplot() +
 geom_raster(data = DSM_TUD_df , aes(x = x, y = y,
                                      fill = fct_elevation_cb)) + 
    scale_fill_manual(values = my_col, name = "Elevation") +
    theme(axis.title = element_blank()) + 
    coord_quickmap()

Challenge: Plot Using Custom Breaks

Create a plot of the TU Delft Digital Surface Model (DSM_TUD) that has:

  1. Six classified ranges of values (break points) that are evenly divided among the range of pixel values.
  2. A plot title.

R

DSM_TUD_df <- DSM_TUD_df %>%
  mutate(fct_elevation_6 = cut(`tud-dsm-5m`, breaks = 6))

levels(DSM_TUD_df$fct_elevation_6)

OUTPUT

[1] "(-5.49,10.9]" "(10.9,27.1]"  "(27.1,43.3]"  "(43.3,59.6]"  "(59.6,75.8]"
[6] "(75.8,92.2]" 

R

my_col <- terrain.colors(6)

ggplot() +
  geom_raster(data = DSM_TUD_df, aes(x = x, y = y,
                                       fill = fct_elevation_6)) +
  scale_fill_manual(values = my_col, name = "Elevation") +
  coord_quickmap() +
  labs(title = "Elevation Classes of the Digital Surface Model (DSM)")

Key Points

  • Continuous data ranges can be grouped into categories using mutate() and cut().
  • Use the built-in terrain.colors() or set your preferred colour scheme manually.