| |
| |
| |
| |
| |
|
|
| library(tidyverse) |
| library(profvis) |
|
|
| |
| benchmarks <- tibble( |
| step = character(), |
| description = character(), |
| time_sec = numeric(), |
| time_pct = numeric() |
| ) |
|
|
| start_overall <- Sys.time() |
|
|
| |
| |
| |
| t1 <- Sys.time() |
|
|
| library(shiny) |
| library(shinydashboard) |
| library(leaflet) |
| library(mapboxapi) |
| library(tidyverse) |
| library(tidycensus) |
| library(sf) |
| library(DT) |
| library(RColorBrewer) |
| library(terra) |
| library(data.table) |
| library(mapview) |
| library(sjPlot) |
| library(sjlabelled) |
| library(bslib) |
| library(shinycssloaders) |
| library(DBI) |
| library(duckdb) |
| library(dbplyr) |
| library(gtfsrouter) |
| library(tidytransit) |
| library(fmsb) |
| library(scales) |
|
|
| time_libraries <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "00_libraries", |
| description = "Load all 23 packages", |
| time_sec = time_libraries, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
| osm_greenspace <- st_read("/vsicurl/https://huggingface.co/datasets/boettiger-lab/sf_biodiv_access/resolve/main/greenspaces_osm_nad83.shp", quiet = TRUE) |> |
| st_transform(4326) |
| if (!"name" %in% names(osm_greenspace)) { |
| osm_greenspace$name <- "Unnamed Greenspace" |
| } |
| time_greenspace <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "01_greenspace", |
| description = "Load OSM greenspace polygons", |
| time_sec = time_greenspace, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
| greenspace_dist_raster <- terra::rast("/vsicurl/https://huggingface.co/datasets/boettiger-lab/sf_biodiv_access/resolve/main/nearest_greenspace_dist.tif") |
| greenspace_osmid_raster <- terra::rast("/vsicurl/https://huggingface.co/datasets/boettiger-lab/sf_biodiv_access/resolve/main/nearest_greenspace_osmid.tif") |
| time_gs_rasters <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "02_gs_rasters", |
| description = "Load greenspace distance rasters", |
| time_sec = time_gs_rasters, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
| ndvi <- terra::rast("/vsicurl/https://huggingface.co/datasets/boettiger-lab/sf_biodiv_access/resolve/main/SF_EastBay_NDVI_Sentinel_10.tif") |
| time_ndvi <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "03_ndvi", |
| description = "Load NDVI raster", |
| time_sec = time_ndvi, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
| download.file( |
| 'https://huggingface.co/datasets/boettiger-lab/sf_biodiv_access/resolve/main/cbg_vect_sf.Rdata', |
| '/tmp/cbg_vect_sf.Rdata', |
| mode = 'wb', |
| quiet = TRUE |
| ) |
| load('/tmp/cbg_vect_sf.Rdata') |
|
|
| if (!"unique_species" %in% names(cbg_vect_sf)) { |
| cbg_vect_sf$unique_species <- cbg_vect_sf$n_species |
| } |
| if (!"n_observations" %in% names(cbg_vect_sf)) { |
| cbg_vect_sf$n_observations <- cbg_vect_sf$n |
| } |
| if (!"median_inc" %in% names(cbg_vect_sf)) { |
| cbg_vect_sf$median_inc <- cbg_vect_sf$medincE |
| } |
| if (!"ndvi_mean" %in% names(cbg_vect_sf)) { |
| cbg_vect_sf$ndvi_mean <- cbg_vect_sf$ndvi_sentinel |
| } |
|
|
| time_cbg <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "04_cbg", |
| description = "Download + load census block groups", |
| time_sec = time_cbg, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
| biodiv_hotspots <- st_read("/vsicurl/https://huggingface.co/datasets/boettiger-lab/sf_biodiv_access/resolve/main/hotspots.shp", quiet = TRUE) |> |
| st_transform(4326) |
| biodiv_coldspots <- st_read("/vsicurl/https://huggingface.co/datasets/boettiger-lab/sf_biodiv_access/resolve/main/coldspots.shp", quiet = TRUE) |> |
| st_transform(4326) |
| time_hotcold <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "05_hotcold", |
| description = "Load hotspots and coldspots", |
| time_sec = time_hotcold, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
| rsf_projects <- st_read("data/source/RSF_Program_Projects_polygons.gpkg", quiet = TRUE) |> |
| st_transform(4326) |
| time_rsf <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "06_rsf", |
| description = "Load RSF program projects", |
| time_sec = time_rsf, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| time_gbif_setup <- 0.001 |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "07_gbif_setup", |
| description = "GBIF parquet path (lazy load in server)", |
| time_sec = time_gbif_setup, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
|
|
| gtfs_path <- '/Users/diegoellis/Desktop/RSF_next_steps/GPFS_OSM_Transit/sf_muni_gtfs-current/' |
|
|
| |
| gtfs_stops_sf <- tryCatch({ |
| read.csv(file.path(gtfs_path, 'stops.txt')) |> |
| st_as_sf(coords = c("stop_lon", "stop_lat"), crs = 4326) |
| }, error = function(e) { |
| warning("GTFS stops failed: ", e$message) |
| NULL |
| }) |
|
|
| |
| gtfs_shapes_raw <- read.csv(file.path(gtfs_path, 'shapes.txt')) |
| gtfs_trips_raw <- read.csv(file.path(gtfs_path, 'trips.txt')) |
| gtfs_routes_raw <- read.csv(file.path(gtfs_path, 'routes.txt')) |
|
|
| shape_route_map <- gtfs_trips_raw |> |
| distinct(shape_id, route_id) |
|
|
| route_meta <- gtfs_routes_raw |> |
| select(route_id, route_short_name, route_long_name, route_color) |> |
| mutate(route_color_hex = paste0("#", trimws(route_color))) |
|
|
| shapes_split <- gtfs_shapes_raw |> |
| arrange(shape_id, shape_pt_sequence) |> |
| group_by(shape_id) |> |
| group_split() |
|
|
| shape_geoms <- lapply(shapes_split, function(s) { |
| st_linestring(cbind(s$shape_pt_lon, s$shape_pt_lat)) |
| }) |
|
|
| gtfs_routes_sf <- st_sf( |
| shape_id = sapply(shapes_split, function(s) s$shape_id[1]), |
| geometry = st_sfc(shape_geoms, crs = 4326) |
| ) |> |
| left_join(shape_route_map, by = "shape_id") |> |
| left_join(route_meta, by = "route_id") |
|
|
| time_gtfs_basic <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "08_gtfs_basic", |
| description = "Load GTFS stops and route shapes", |
| time_sec = time_gtfs_basic, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
|
|
| gtfs_router <- tryCatch({ |
| gtfs_zip_path <- tempfile(fileext = ".zip") |
| old_wd <- getwd() |
| setwd(gtfs_path) |
| utils::zip(gtfs_zip_path, files = list.files('.', pattern = "\\.txt$")) |
| setwd(old_wd) |
|
|
| gr <- gtfsrouter::extract_gtfs(gtfs_zip_path) |
| gtfsrouter::gtfs_timetable(gr, day = "Monday") |
| }, error = function(e) { |
| warning("gtfsrouter failed: ", e$message) |
| NULL |
| }) |
|
|
| time_gtfs_router <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "09_gtfs_router", |
| description = "Initialize gtfsrouter + timetable", |
| time_sec = time_gtfs_router, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
|
|
| gtfs_stop_headways <- tryCatch({ |
| gt <- tidytransit::read_gtfs(gtfs_path) |
| tidytransit::get_stop_frequency(gt, start_time = 7 * 3600, end_time = 9 * 3600) |> |
| group_by(stop_id) |> |
| summarise( |
| mean_headway_min = mean(mean_headway, na.rm = TRUE) / 60, |
| n_departures_peak = sum(n_departures, na.rm = TRUE), |
| .groups = "drop" |
| ) |> |
| mutate(stop_id = as.character(stop_id)) |
| }, error = function(e) { |
| warning("tidytransit failed: ", e$message) |
| NULL |
| }) |
|
|
| if (!is.null(gtfs_stop_headways) && !is.null(gtfs_stops_sf)) { |
| gtfs_stops_sf <- gtfs_stops_sf |> |
| mutate(stop_id = as.character(stop_id)) |> |
| left_join(gtfs_stop_headways, by = "stop_id") |
| } |
|
|
| time_gtfs_headways <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "10_gtfs_headways", |
| description = "Compute transit stop headways (AM peak)", |
| time_sec = time_gtfs_headways, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
|
|
| calenviro_path <- '/Users/diegoellis/Downloads/calenviroscreen40gdb_F_2021.gdb' |
| if (!file.exists(calenviro_path)) { |
| calenviro_path <- '/Users/diegoellis/Desktop/Projects/Presentations/Data_Schell_Lab_Tutorial/calenviroscreen40gdb_F_2021.gdb' |
| } |
|
|
| cenv_sf <- tryCatch({ |
| sf::st_read(calenviro_path, quiet = TRUE) |> |
| dplyr::filter(grepl("san francisco", County, ignore.case = TRUE), !is.na(CIscore)) |> |
| dplyr::select( |
| Tract, CIscore, CIscoreP, |
| PM2_5, PM2_5_Pctl, Traffic, Traffic_Pctl, |
| Poverty, Poverty_Pctl, HousBurd, HousBurd_Pctl, |
| County |
| ) |> |
| sf::st_transform(4326) |> |
| sf::st_make_valid() |
| }, error = function(e) { |
| warning("CalEnviroScreen failed: ", e$message) |
| NULL |
| }) |
|
|
| time_calenviro <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "11_calenviro", |
| description = "Load CalEnviroScreen layer", |
| time_sec = time_calenviro, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| t1 <- Sys.time() |
|
|
| sf_ej_path <- '/Users/diegoellis/Downloads/San Francisco Environmental Justice Communities Map_20251217/geo_export_a21b0a0a-7306-46fd-8381-06581cdbe6e9.shp' |
|
|
| sf_ej_sf <- tryCatch({ |
| sf::st_read(sf_ej_path, quiet = TRUE) |> |
| dplyr::mutate( |
| symbol_hex = stringr::str_split(symbol_rgb, ",\\s*") |> |
| lapply(function(x) sprintf("#%02X%02X%02X", |
| as.integer(x[1]), as.integer(x[2]), as.integer(x[3]))) |> |
| unlist(), |
| ej_label = dplyr::case_when( |
| is.na(score) ~ "Not EJ", |
| score >= 21 ~ "High EJ burden (21-30)", |
| score >= 11 ~ "Moderate EJ burden (11-20)", |
| score >= 1 ~ "Low EJ burden (1-10)", |
| score == 0 ~ "Score 0", |
| TRUE ~ "Unknown" |
| ) |
| ) |> |
| sf::st_transform(4326) |> |
| sf::st_make_valid() |
| }, error = function(e) { |
| warning("SF EJ layer failed: ", e$message) |
| NULL |
| }) |
|
|
| time_ej <- as.numeric(difftime(Sys.time(), t1, units = "secs")) |
| benchmarks <- bind_rows(benchmarks, tibble( |
| step = "12_ej", |
| description = "Load SF EJ communities layer", |
| time_sec = time_ej, |
| time_pct = NA |
| )) |
|
|
| |
| |
| |
| time_overall <- as.numeric(difftime(Sys.time(), start_overall, units = "secs")) |
|
|
| benchmarks <- benchmarks |> |
| mutate(time_pct = round(100 * time_sec / time_overall, 1)) |
|
|
| |
| cat("\n") |
| cat("================================================================================\n") |
| cat("STARTUP PERFORMANCE BENCHMARK\n") |
| cat("================================================================================\n\n") |
|
|
| print(benchmarks |> select(step, description, time_sec, time_pct)) |
|
|
| cat("\n") |
| cat("TOTAL STARTUP TIME: ", round(time_overall, 2), " seconds\n") |
| cat("================================================================================\n\n") |
|
|
| |
| |
| |
| cat("OPTIMIZATION RECOMMENDATIONS:\n") |
| cat("================================================================================\n\n") |
|
|
| |
| slow_steps <- benchmarks |> |
| filter(time_sec > 5 | time_pct > 10) |> |
| arrange(desc(time_sec)) |
|
|
| if (nrow(slow_steps) > 0) { |
| cat("CRITICAL BOTTLENECKS (>5s or >10%):\n\n") |
| for (i in 1:nrow(slow_steps)) { |
| row <- slow_steps[i, ] |
| cat(" •", row$step, "(", row$time_sec, "s,", row$time_pct, "%)\n") |
| cat(" Description:", row$description, "\n") |
| |
| if (grepl("libraries", row$step)) { |
| cat(" Recommendation: Load packages only in server() if possible. Use lazy loading.\n") |
| } else if (grepl("download", row$step)) { |
| cat(" Recommendation: Cache downloaded files locally or use precomputed versions.\n") |
| } else if (grepl("gtfsrouter|tidytransit", row$step)) { |
| cat(" Recommendation: Pre-compute and cache GTFS timetable. Consider lazy loading for session.\n") |
| } else if (grepl("calenviro|ej", row$step)) { |
| cat(" Recommendation: Pre-filter to SF boundary. Store as .gpkg or parquet locally.\n") |
| } |
| cat("\n") |
| } |
| } else { |
| cat("No critical bottlenecks detected (all steps < 5s).\n\n") |
| } |
|
|
| |
| p <- ggplot(benchmarks, aes(x = reorder(step, -time_sec), y = time_sec, fill = time_pct)) + |
| geom_col() + |
| geom_text(aes(label = paste0(round(time_sec, 2), "s")), vjust = -0.3, size = 3) + |
| scale_fill_gradient(low = "green", high = "red", name = "% of Total") + |
| labs( |
| title = "Shiny App Startup Performance Profile", |
| subtitle = paste0("Total time: ", round(time_overall, 2), " seconds"), |
| x = "Loading Step", |
| y = "Time (seconds)" |
| ) + |
| theme_minimal() + |
| theme( |
| axis.text.x = element_text(angle = 45, hjust = 1, size = 9), |
| plot.title = element_text(face = "bold", size = 14), |
| legend.position = "right" |
| ) |
|
|
| print(p) |
|
|
| ggsave("/Users/diegoellis/Desktop/Projects/Postdoc/Biodiversity_Access_Indicator/SF_biodiv_access_shiny/startup_benchmark.png", |
| p, width = 12, height = 6, dpi = 150) |
|
|
| cat("\nBenchmark plot saved to: startup_benchmark.png\n") |
|
|
| |
| |
| |
| write_csv(benchmarks, |
| "/Users/diegoellis/Desktop/Projects/Postdoc/Biodiversity_Access_Indicator/SF_biodiv_access_shiny/startup_benchmarks.csv") |
|
|
| cat("Benchmark data saved to: startup_benchmarks.csv\n\n") |
|
|