TITLE: Shiny app to explore climate space of SEOSAW region
DATE: 2022-09-10
AUTHOR: John L. Godlee
====================================================================


I made an R Shiny web app to explore the climate space of the
SEOSAW region. The app can be found here, on shinyapps.io.

 [here, on shinyapps.io]:
https://johngodlee.shinyapps.io/climate_space/

A big part of getting the app to run smoothly was to pre-process
the data sources so they could be loaded quickly from disk,
subsetted quickly, and rendered quickly with ggplot(). I haven't
styled the app much to make it look pretty, as it was more a
learning experience on how code reactive objects in Shiny.

I loaded country outlines of Africa and the SEOSAW ecoregion from
the {seosawr} R package, and simplified them using {rmapshaper}:

   africa <- seosawr::africa
   seosaw_region <- seosawr::seosaw_region
   seosaw_bbox <- seosawr::seosaw_bbox

   africa_simp <- ms_simplify(africa,
     keep = 0.01, keep_shapes = FALSE) %>%
     st_intersection(., seosaw_bbox)

   seosaw_region_simp <- ms_simplify(seosaw_region,
     keep = 0.01, keep_shapes = FALSE)

I used climate data from WorldClim, which I downloaded at 10 minute
spatial resolution using the {raster} package:

 [WorldClim]: https://www.worldclim.org/

   bioclim <- getData("worldclim", var = "bio", res = 10)

which returns a raster stack object. Then I cropped and masked the
climate data with the SEOSAW region polygon:

   bioclim_crop <- mask(crop(bioclim, seosaw_region_simp),
seosaw_region_simp)

and finally, extracted the values and coordinates of each raster
cell for each raster layer, resulting in a large matrix, with cells
for rows, and bioclim variables or coordinates as columns, which I
saved as a .rds file.

   bioclim_val <- cbind(coordinates(bioclim_crop),
values(bioclim_crop))
   bioclim_val_fil <- bioclim_val[
     !apply(bioclim_val, 1, function(x) {
       all(is.na(x[!names(x) %in% c("x", "y")]))
     }),
   ]
   saveRDS(bioclim_val_fil, "app/data/bioclim_val_fil.rds")

The app allows you to draw a rectangle around the climate space of
interest using two bioclim variables which you can select from a
dropdown list. This process uses the brush operator in the Shiny
plotOutput() function. I subsetted the raster matrix to the values
returned by input$brush using reactive() in the Shiny app.

   rasterMapInput <- reactive({
   val_sel <- val[,c("x", "y", input$xvar, input$yvar)]
   if (!is.null(input$brush)) {
     xmin <- input$brush$xmin
     xmax <- input$brush$xmax
     ymin <- input$brush$ymin
     ymax <- input$brush$ymax
     val_sel <- val_sel[
       val_sel[,3] > xmin &
         val_sel[,3] < xmax &
         val_sel[,4] > ymin &
         val_sel[,4] < ymax,
       c("x", "y")]
   }
   as.data.frame(val_sel)
   })

Then I simply used ggplot() with rasterMapInput() as the data input
to geom_tile() to map the climate space selected on the map of
southern Africa.

   # Extract values from selected raster layers
   valInput <- reactive({
   as.data.frame(val[,c(input$xvar, input$yvar)])
   })

   output$plot1 <- renderPlot(
   ggplot() +
     geom_bin2d(data = valInput(),
       mapping = aes_string(x = names(valInput())[1], y =
names(valInput())[2]),
         colour = bg_col, fill = bg_col, bins = 100) +
     theme_classic() +
     theme(legend.position = "none")
   )

   output$plot2 <- renderPlot(
   map_plot +
     geom_tile(data = rasterMapInput(),
       aes(x = x, y = y),
       fill = bg_col)
   )

 ![Screenshot of the app with a dry and wet region
selected.](https://johngodlee.xyz/img_full/shiny_climate/scrot.png)