Setup

library(tidyverse)
library(sf)
library(readr)
library(readxl)
library(lubridate)
library(tmap)
library(raster)
library(tmaptools)
library(ggspatial)
library(prettymapr)
library(basemaps)
library(cowplot)
library(shiny)

tmap_mode("plot")

Define File Paths

mapping_dir <- "C:/Users/zklein/OneDrive - DOI/Documents/zk_whitebark_learning_and_strategizing/mapping_related"

cone_dir <- "C:/Users/zklein/OneDrive - DOI/Documents/R-directory/cone_collection_mapping"

gis_dir <- "C:/Users/zklein/OneDrive - DOI/General - NPS-SIEN-White Pine Mortality/GIS_layers"

Load Spatial Data

YOSE_boundary <- st_read(file.path(mapping_dir,
                                   "NPS_ParkBoundaries/YOSE_NP_boundary/YOSE_NP_boundary.shp"),
                         quiet = TRUE)

SEKI_boundary <- st_read(file.path(mapping_dir,
                                   "NPS_ParkBoundaries/SEKI_NP_boundary/SEKI_NP.shp"),
                         quiet = TRUE)

SEKI_whitebark_dist <- st_read(file.path(
  gis_dir,
  "WhitePine_Distribution/White_Pine_Distribution_dissolved/SEKI_WhitebarkPine_Dist_Dissolved.shp"
), quiet = TRUE)

SEKI_foxtail_dist <- st_read(file.path(
  gis_dir,
  "WhitePine_Distribution/White_Pine_Distribution_dissolved/SEKI_FoxtailPine_Dist_Dissolved.shp"
), quiet = TRUE)

YOSE_whitebark_dist <- st_read(file.path(
  gis_dir,
  "WhitePine_Distribution/White_Pine_Distribution_dissolved/YOSE_WhitebarkPine_Dist_Dissolved.shp"
), quiet = TRUE)

USFS_boundary <- st_read(file.path(
  mapping_dir,
  "Forest_Administrative_Boundaries/Forest_Administrative_Boundaries_(Feature_Layer).shp"
), quiet = TRUE)

ca_boundary <- st_read(file.path(
  mapping_dir,
  "NPS_ParkBoundaries/ca_state/CA_State.shp"
), quiet = TRUE)

cone_sites <- read_excel(file.path(cone_dir,
                                   "2024_2025_ConeCollections.xlsx"))

Prepare Spatial Layers

USFS_boundary_sosierra <-
  USFS_boundary %>%
  filter(FORESTNAME %in%
           c("Inyo National Forest",
             "Sierra National Forest",
             "Sequoia National Forest")) %>%
  dplyr::select(-c(
    OBJECTID, ADMINFORES, FORESTNUMB,
    FORESTORGC, REGION, GIS_ACRES,
    SHAPELEN, SHAPEAREA
  )) %>%
  rename(UNIT_NAME = FORESTNAME) %>%
  mutate(
    UNIT_TYPE = "National Forest",
    UNIT_CODE = case_when(
      UNIT_NAME == "Inyo National Forest" ~ "INYO_NF",
      UNIT_NAME == "Sequoia National Forest" ~ "SEQU_NF",
      UNIT_NAME == "Sierra National Forest" ~ "SIER_NF"
    )
  ) %>%
  st_transform(26911)

SEKI_boundary <- st_transform(SEKI_boundary, 26911)
YOSE_boundary <- st_transform(YOSE_boundary, 26911)
SEKI_foxtail_dist <- st_transform(SEKI_foxtail_dist, 26911)

cone_sites_sf <-
  st_as_sf(cone_sites,
           coords = c("Long", "Lat"),
           crs = 4326) %>%
  mutate(
    Date = as.factor(Date),
    `Area Name` = as.factor(`Area Name`)
  ) %>%
  st_transform(26911)

parks_boundary <-
  bind_rows(YOSE_boundary, SEKI_boundary)

parks_boundary_sosierra <-
  parks_boundary %>%
  dplyr::select(-c(
    GIS_Notes,
    STATE,
    REGION,
    GNIS_ID,
    PARKNAME,
    DATE_EDIT,
    CREATED_BY
  ))

so_sierra_boundaries <-
  bind_rows(
    parks_boundary_sosierra,
    USFS_boundary_sosierra
  )

Load California Whitebark Pine Distribution

USFS_CA_WBP_fgdb <-
  file.path(mapping_dir,
            "USFS_Slaton_WBP_Map/WhitebarkPine_CA_2020_v1.gdb")

st_layers(USFS_CA_WBP_fgdb)
## Driver: OpenFileGDB 
## Available layers:
##                 layer_name geometry_type features fields
## 1 WhitebarkPine_CA_2020_v1 Multi Polygon    12926      3
##                    crs_name
## 1 NAD83 / California Albers
USFS_WBP_dist <-
  st_read(
    USFS_CA_WBP_fgdb,
    layer = "WhitebarkPine_CA_2020_v1",
    quiet = TRUE
  ) %>%
  st_transform(26911)
## Warning in CPL_read_ogr(dsn, layer, query, as.character(options), quiet, : GDAL
## Message 1: organizePolygons() received a polygon with more than 100 parts. The
## processing may be really slow.  You can skip the processing by setting
## METHOD=SKIP, or only make it analyze counter-clock wise parts by setting
## METHOD=ONLY_CCW if you can assume that the outline of holes is counter-clock
## wise defined
USFS_WBP_dist_dissolved <-
  st_union(USFS_WBP_dist)

California Distribution Map

tm_shape(ca_boundary) +
  tm_borders() +
  tm_shape(USFS_WBP_dist) +
  tm_polygons(col = "#458B74")

Load ADS 2025 Data

ADS_2025_fgdb <-
  file.path(mapping_dir,
            "ADS_2025.gdb")

st_layers(ADS_2025_fgdb)
## Driver: OpenFileGDB 
## Available layers:
##                  layer_name     geometry_type features fields
## 1          Flightlines_2025 Multi Line String       59      8
## 2 Buffered_Flightlines_2025     Multi Polygon        3      2
## 3                  ADS_2025     Multi Polygon     2573     25
##                                 crs_name
## 1 USA_Contiguous_Albers_Equal_Area_Conic
## 2 USA_Contiguous_Albers_Equal_Area_Conic
## 3 USA_Contiguous_Albers_Equal_Area_Conic
ADS_2025 <-
  st_read(
    ADS_2025_fgdb,
    layer = "ADS_2025",
    quiet = TRUE
  )

ADS_2025_whitebark <-
  ADS_2025 %>%
  filter(
    HOST %in%
      c(
        "whitebark pine",
        "lodgepole pine",
        "limber pine",
        "Unknown conifer",
        "foxtail pine",
        "California red fir"
      )
  )

Initial ADS Map

tm_shape(so_sierra_boundaries) +
  tm_borders() +
  tm_shape(USFS_WBP_dist_dissolved) +
  tm_borders() +
  tm_shape(SEKI_foxtail_dist) +
  tm_borders() +
  tm_shape(ADS_2025_whitebark) +
  tm_polygons(fill = "HOST")

Filter ADS Polygons by Species Distribution

combined_dist <-
  st_union(
    USFS_WBP_dist_dissolved,
    SEKI_foxtail_dist
  )

ADS_2025_whitebark <-
  ADS_2025_whitebark %>%
  st_transform(st_crs(combined_dist)) %>%
  st_cast("MULTIPOLYGON")

polygons_filtered <-
  ADS_2025_whitebark[
    st_intersects(
      ADS_2025_whitebark,
      combined_dist,
      sparse = FALSE
    ),
  ] 

polygons_filtered_2 <- polygons_filtered %>% group_by(HOST) %>%
  mutate(
    Site_ID = paste0(
      case_when(
        HOST == "whitebark pine" ~ "WBP-",
        HOST == "foxtail pine" ~ "FTP-",
        HOST == "California red fir" ~ "CRF-",
        HOST == "limber pine" ~ "LP-",
        TRUE ~ "UNK-"
      ),
      sprintf("%03d", row_number())
    )
  ) %>%
  ungroup()

Filtered ADS Map

tm_shape(SEKI_boundary) +
  tm_borders() +
  #tm_shape(USFS_WBP_dist_dissolved) +
  tm_borders() +
  #tm_shape(SEKI_foxtail_dist) +
  tm_borders() +
  tm_shape(polygons_filtered_2) +
  tm_polygons(fill = "HOST") + 
  tm_text(
    text = "Site_ID",
    size = 0.6,
    just = "left",
    xmod = 0.5,
    ymod = 0.3
  )
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_text()`: migrate the layer options 'just' to 'options =
## opt_tm_text(<HERE>)'