inat-ranges / app.R
cboettig's picture
:eagle:
af53f9f
library(shiny)
library(bslib)
library(shinybusy)
source("utils.R")
source("inat-ranges.R")
public_endpoint <- Sys.getenv("AWS_PUBLIC_ENDPOINT", Sys.getenv("AWS_S3_ENDPOINT"))
# intialize data
load_h3()
load_spatial()
duckdbfs::duckdb_secrets()
inat <- open_dataset("s3://public-inat/hex")
taxa <- open_dataset(glue("s3://public-inat/taxonomy/taxa.parquet"),
recursive = FALSE) |> rename(taxon_id = id)
cache <- tempfile(fileext = ".json")
# I/O limited, we can have many more processes than CPU threads
con <- duckdbfs::cached_connection()
DBI::dbExecute(con, "SET threads = 128;")
###### User interface ######
ui <- page_sidebar(
title = "iNaturalist Rangemaps",
markdown("Visualize species richness from [iNaturalist Range map datasets](https://www.inaturalist.org/pages/range_maps).
Pan & zoom the map over the desired area and hit 'map richness', or draw the desired area with the draw tool.
Filter by specific taxonomic ranks or view all 100,293 mapped species.
Note that larger areas will be slower to compute. (Area selections that overlap the antimerdian may create visual artefacts).
"),
shinybusy::add_busy_spinner(),
sidebar = sidebar(
card(
markdown("Filter by taxonomic group or toggle off to see all species."),
input_switch("filter", "filter taxa:", value = TRUE),
varSelectInput("rank", NULL, taxa, selected = "class"),
textInput("taxon", NULL, "Aves")
),
actionButton("get_features", "Map richness")
),
card(
maplibreOutput("map"),
)
)
###### Server ######
server <- function(input, output, session) {
# observeEvent(input$map_bbox, { }) # We can react to any zoom/pan on the map
output$map <- renderMaplibre({
# Hacky -- we sidecar the metadata here
if(file.exists(cache)) {
meta <- jsonlite::read_json(cache)
print(meta$url)
} else {
meta <- list(X = -110,
Y = 37,
zoom = 4,
url = paste0("https://",
public_endpoint,
"/public-data/inat-tmp-ranges.h3j"))
}
m <- richness_map(meta)
m
})
observeEvent(input$get_features, {
# Use the bbox as the focal area unless user has selected a focal area
drawn_features <- get_drawn_features(mapboxgl_proxy("map"))
if(nrow(drawn_features) > 0) {
aoi <- drawn_features
} else if (!is.null(input$map_bbox)){
aoi <- sf::st_bbox(unlist(input$map_bbox), crs = 4326)
} else {
aoi <- spData::us_states
}
rank <- taxon <- NULL
if (input$filter) {
rank <- input$rank
taxon <- input$taxon
}
message("Computing richness...")
meta <- richness(inat, aoi, rank, taxon, zoom = input$map_zoom)
jsonlite::write_json(meta, cache, auto_unbox = TRUE)
message(paste("rendering", meta$url))
session$reload()
})
}
shinyApp(ui, server)