8.2 Raster data visualization: geom_raster()
and geom_stars()
This section shows how to use geom_raster()
and geom_stars()
to create maps from raster datasets of two object classes: Raster
\(^*\) objects from the raster
package and stars
objects from the stars
package. geom_raster
does not accept either Raster
\(^*\) or stars
as the input. Instead, geom_raster()
accepts a data.frame
with coordinates to create maps. So, it is a two-step procedure
- convert raster dataset into a
data.frame
with coordinates - use
geom_raster()
to make a map
geom_stars()
from the stars
package accepts a stars
object, and no data transformation is necessary.
We use the following objects that have the same information but come in different object classes for illustration in this section.
Raster as stars
<- readRDS("Data/tmax_Jan_09_stars.rds") tmax_Jan_09
Raster as RasterStack
<- stack("Data/tmax_Jan_09.tif") tmax_Jan_09_rs
8.2.1 Visualize Raster
\(^*\) with geom_raster()
In order to create maps from the information stored in Raster
\(^*\) objects, you first convert them to a regular data.frame
using as.data.frame()
as follows:
#--- convert to data.frame ---#
<-
tmax_Jan_09_df as.data.frame(tmax_Jan_09_rs, xy = TRUE) %>%
#--- remove cells with NA for any of the layers ---#
na.omit() %>%
#--- change the variable names ---#
setnames(
paste0("tmax_Jan_09.", 1:5),
seq(ymd("2009-01-01"), ymd("2009-01-05"), by = "days") %>%
as.character()
)
#--- take a look ---#
head(tmax_Jan_09_df)
x y 2009-01-01 2009-01-02 2009-01-03 2009-01-04 2009-01-05
17578 -95.12500 49.41667 -12.863 -11.455 -17.516 -12.755 -26.446
18982 -95.16667 49.37500 -12.698 -11.441 -17.436 -12.672 -25.889
18983 -95.12500 49.37500 -12.921 -11.611 -17.589 -12.830 -26.544
18984 -95.08333 49.37500 -13.074 -11.827 -17.684 -12.913 -26.535
18985 -95.04167 49.37500 -13.591 -12.220 -17.920 -12.684 -25.780
18986 -95.00000 49.37500 -13.688 -12.177 -17.911 -12.548 -25.424
The xy = TRUE
option adds the coordinates of the centroid of the raster cells, and na.omit()
removes cells that are outside of the Kansas border and have NA values. Notice that each band comprises a column in the data.frame
.
Once the conversion is done, you can use geom_raster()
to create a map. Unlike geom_sf()
, you need to supply the variables names for the geographical coordinates (here x
for longitude and y
for latitude). Further, you also need to specify which variable to use for fill color differentiation.
(<- ggplot(data = tmax_Jan_09_df) +
g_tmax_map geom_raster(aes(x = x, y = y, fill = `2009-01-01`)) +
scale_fill_viridis_c() +
theme_void() +
theme(
legend.position = "bottom"
) )
You can add coord_equal()
so that one degree in latitude and longitude are the same length on the map. Of course, one degree in longitude and one degree in latitude are not the same length for US. However, distortion is smaller compared to the default at least.
+ coord_equal() g_tmax_map
We only visualized tmax data for one day (layer.1
) out of five days of tmax records. To present all of them at the same time we can facet using facet_wrap()
. However, before we do that we need to have the data in a long format like this:
<-
tmax_long_df %>%
tmax_Jan_09_df pivot_longer(
c(-x, -y),
names_to = "date",
values_to = "tmax"
)
#--- take a look ---#
head(tmax_long_df)
# A tibble: 6 × 4
x y date tmax
<dbl> <dbl> <chr> <dbl>
1 -95.1 49.4 2009-01-01 -12.9
2 -95.1 49.4 2009-01-02 -11.5
3 -95.1 49.4 2009-01-03 -17.5
4 -95.1 49.4 2009-01-04 -12.8
5 -95.1 49.4 2009-01-05 -26.4
6 -95.2 49.4 2009-01-01 -12.7
Let’s now use facet_wrap()
to create a series of tmax maps.
ggplot() +
geom_raster(data = tmax_long_df, aes(x = x, y = y, fill = tmax)) +
facet_wrap(date ~ .) +
coord_equal() +
scale_fill_viridis_c() +
theme_void() +
theme(
legend.position = "bottom"
)
8.2.2 Visualize stars
with geom_raster()
Similarly with Raster
\(^*\) objects, we first need to convert a stars
to a regular data.frame
using as.data.frame()
as follows:
#--- converting to a data.frame ---#
<- as.data.frame(tmax_Jan_09, xy = TRUE) %>%
tmax_long_df na.omit()
#--- take a look ---#
head(tmax_Jan_09_df)
x y 2009-01-01 2009-01-02 2009-01-03 2009-01-04 2009-01-05
17578 -95.12500 49.41667 -12.863 -11.455 -17.516 -12.755 -26.446
18982 -95.16667 49.37500 -12.698 -11.441 -17.436 -12.672 -25.889
18983 -95.12500 49.37500 -12.921 -11.611 -17.589 -12.830 -26.544
18984 -95.08333 49.37500 -13.074 -11.827 -17.684 -12.913 -26.535
18985 -95.04167 49.37500 -13.591 -12.220 -17.920 -12.684 -25.780
18986 -95.00000 49.37500 -13.688 -12.177 -17.911 -12.548 -25.424
One key difference from the conversion of Raster
\(^*\) objects is that the data.frame
is already in the long format, which means that you can immediately make faceted figures like this:
ggplot() +
geom_raster(data = tmax_long_df, aes(x = x, y = y, fill = tmax)) +
facet_wrap(date ~ .) +
coord_equal() +
scale_fill_viridis_c() +
theme_void() +
theme(
legend.position = "bottom"
)
8.2.3 Visualize stars
with geom_stars()
We saw above that geom_raster()
requires converting a stars
object to a data.frame
first before creating a map. geom_stars()
from the stars
package lets you use a stars
object directly to easily create a map under the ggplot2
framework. geom_stars()
works just like geom_sf()
. All you need to do is supply a stars
object to geom_stars()
as data.
ggplot() +
geom_stars(data = tmax_Jan_09) +
theme_void()
The fill color of the raster cells are automatically set to the attribute (here tmax) as if aes(fill = tmax)
. It is a good idea to add coord_equal()
because of the same issue we saw with geom_raster()
.
ggplot() +
geom_stars(data = tmax_Jan_09) +
theme_void() +
coord_equal()
By default, geom_stars()
plots only the first band. In order to present all the layers at the same time, you can add facet_wrap( ~ x)
where x is the name of the third dimension of the stars object (date
here).
ggplot() +
geom_stars(data = tmax_Jan_09) +
facet_wrap(~date) +
coord_equal() +
theme_void()
8.2.4 adding geom_sf()
layers
You can easily add geom_sf()
layers to a map created with geom_raster()
or geom_stars()
. Let’s crop the tmax data to Kansas and create a map of tmax values displayed on top of the Kansas county borders.
#--- crop to KS ---#
<- tmax_Jan_09 %>%
KS_tmax_Jan_09_stars st_crop(., KS_county)
#--- convert to a df ---#
<- as.data.frame(KS_tmax_Jan_09_stars, xy = TRUE) %>%
KS_tmax_Jan_09_df na.omit()
8.2.4.1 adding geom_sf()
to a map with geom_raster()
ggplot() +
geom_raster(data = KS_tmax_Jan_09_df, aes(x = x, y = y, fill = tmax)) +
geom_sf(data = KS_county, fill = NA) +
facet_wrap(date ~ .) +
scale_fill_viridis_c() +
theme_void() +
theme(
legend.position = "bottom"
)
Notice that coord_equal()
is not necessary in the above code. Indeed, if you try to add coord_equal()
, you will have an error.
ggplot() +
geom_raster(data = KS_tmax_Jan_09_df, aes(x = x, y = y, fill = tmax)) +
geom_sf(data = KS_county, fill = NA) +
facet_wrap(date ~ .) +
coord_equal() +
scale_fill_viridis_c() +
theme_void() +
theme(
legend.position = "bottom"
)
Error in `f()`:
! geom_sf() must be used with coord_sf()
Further, the original stars
or Raster
\(^*\) must have the same CRS as the sf
objects. The following code transforms the CRS of KS_county
to 32614
and try to plot them together.
ggplot() +
geom_raster(data = KS_tmax_Jan_09_df, aes(x = x, y = y, fill = tmax)) +
geom_sf(data = st_transform(KS_county, 32614), fill = NA) +
facet_wrap(date ~ .) +
scale_fill_viridis_c() +
theme_void() +
theme(
legend.position = "bottom"
)
When plotting multiple sf
objects, the CRS for the map was set to the CRS of the sf
objects used for the first geom_sf()
layer, and the rest of the sf
objects followed suit. That is not the case here.
8.2.4.2 adding geom_sf()
to a map with geom_stars()
This is basically the same as the case with geom_stars()
ggplot() +
geom_stars(data = KS_tmax_Jan_09_stars) +
geom_sf(data = KS_county, fill = NA) +
facet_wrap(~date) +
theme_void()
Just like the case with geom_raster()
, coord_equal()
is not necessary and the stars
and sf
objects must have the same CRS.
ggplot() +
geom_stars(data = KS_tmax_Jan_09_stars) +
geom_sf(data = st_transform(KS_county, 32614), fill = NA) +
facet_wrap(~date) +
theme_void()