File size: 2,804 Bytes
3cf94ac
 
 
72ec702
 
66a02d0
 
 
 
 
 
 
 
9f1c48e
 
 
 
 
 
 
66a02d0
 
 
9f1c48e
 
 
 
 
 
 
 
 
 
 
 
 
66a02d0
9f1c48e
66a02d0
07d31be
 
 
fd48dc7
66a02d0
 
 
 
 
 
07d31be
fd48dc7
07d31be
fd48dc7
 
07d31be
 
 
 
 
 
 
 
 
 
 
 
fd48dc7
9f1c48e
 
 
 
 
 
 
07d31be
fd48dc7
66a02d0
2c1140f
66a02d0
fd48dc7
 
 
3cf94ac
07d31be
3cf94ac
07d31be
 
 
 
 
 
 
133e140
07d31be
 
 
 
 
 
 
0118a3f
07d31be
3cf94ac
 
07d31be
 
66a02d0
0118a3f
9f1c48e
 
07d31be
3cf94ac
 
 
 
 
 
 
 
 
 
66a02d0
 
3cf94ac
 
 
0118a3f
07d31be
8efece1
 
3cf94ac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
library(dplyr)
library(duckdbfs)
library(mapgl)
library(glue)

public_endpoint <- Sys.getenv(
  "AWS_PUBLIC_ENDPOINT",
  Sys.getenv("AWS_S3_ENDPOINT")
)
# intialize data

duckdbfs::duckdb_secrets()
inat <- open_dataset("s3://public-inat/hex")

common <- open_dataset(
  "s3://public-inat/taxonomy/vernacular/VernacularNames-english.csv",
  format = 'csv',
  recursive = FALSE
) |>
  select(id, vernacularName)
taxa <- open_dataset(
  glue("s3://public-inat/taxonomy/taxa.parquet"),
  recursive = FALSE
) |>
  select(
    "id",
    "scientificName",
    "kingdom",
    "phylum",
    "class",
    "order",
    "family",
    "genus",
    "specificEpithet",
    "infraspecificEpithet"
  )

taxa <- common |> inner_join(taxa)

get_hash <- function(aoi, rank, taxon) {
  digest::digest(list(aoi, rank, taxon))
}

# Also requires get_h3_aoi() from utils.R
richness <- function(inat, aoi, rank = NULL, taxon = NULL, zoom = 3) {
  public_endpoint <- Sys.getenv(
    "AWS_PUBLIC_ENDPOINT",
    Sys.getenv("AWS_S3_ENDPOINT")
  )
  hash <- get_hash(aoi, rank, taxon)
  s3 <- paste0("s3://public-data/cache/inat/", hash, ".h3j")
  url <- gsub("s3://", glue("https://{public_endpoint}/"), s3)

  # check if hash exists
  cache_hit <- tryCatch(
    {
      duckdbfs::open_dataset(s3)
      TRUE
    },
    error = function(e) FALSE,
    finally = FALSE
  )

  if (cache_hit) {
    return(url)
  }

  if (rank == "" || rank == "NULL") {
    rank <- NULL
  }
  if (taxon == "" || taxon == "NULL") {
    taxon <- NULL
  }

  # Subset by taxon, if requested
  if (!is.null(rank) && !is.null(taxon)) {
    inat <- taxa |>
      rename(taxon_id = id) |>
      filter(.data[[rank]] == taxon) |>
      select(taxon_id) |>
      inner_join(inat, by = "taxon_id")
  }

  inat <- inat |> rename(h3id = h4)

  # Subset by area, if requested
  if (nrow(aoi) > 0) {
    inat <-
      get_h3_aoi(aoi, precision = 4) |>
      select(h3id) |>
      inner_join(inat, by = "h3id")
  }

  # Aggregate to h4 hex
  inat |>
    distinct(taxon_id, h3id) |>
    group_by(h3id) |>
    summarise(n = n()) |>
    mutate(height = n / max(n)) |>
    duckdbfs::to_h3j(s3)

  return(url)
}

richness_map <- function(url, gdf) {
  bounds <- as.vector(sf::st_bbox(gdf))
  m <-
    maplibre() |>
    #    add_draw_control() |>
    add_geocoder_control() |>
    add_h3j_source("h3j_source", url = url) |>
    add_fill_extrusion_layer(
      id = "h3j_layer",
      source = "h3j_source",
      tooltip = "n",
      fill_extrusion_color = viridis_pal("height"),
      fill_extrusion_height = list(
        "interpolate",
        list("linear"),
        list("zoom"),
        0,
        0,
        1,
        list("*", 100000, list("get", "height"))
      ),
      fill_extrusion_opacity = 0.7
    ) |>
    fit_bounds(bounds, animate = TRUE)

  return(m)
}