library(sf) library(dplyr) library(raster) library(NISTunits) library(ggplot2) library(extrafont) library(ggsn)
plot_bathymetry <- function(lake, max_levels_ft = data.frame(lake = c("Pleasant", "Long", "Plainfield"), max_ft = c(984, 1105, 1106), max_level = c(983.5, 1105.1, 1104.7)), fill = list(Pleasant = list(limits = c(-6, 25), breaks = c(20, 15, 10, 5, 0, -5), labels = c("20", "15", "10", "5", "0", "+5")), Long = list(limits = c(-7, 7), breaks = c(6, 3, 0, -3, -6), labels = c("6", "3", "0", "+3", "+6")), Plainfield = list(limits = c(-8.5, 8.5), breaks = c(8, 4, 0, -4, -8), labels = c("8", "4", "0", "+4", "+8"))), lakes = c("Pleasant", "Long", "Plainfield"), text_size = 10) { # Key Levels, all lakes ------------------------------------------------------ max_levels_ft$max_ft <- apply(max_levels_ft[,2:3], 1, min) key_levels <- CSLSscenarios::MODFLOW_metrics %>% filter(.data$lake %in% lakes, .data$metric == "exceedance_level", .data$variable == "50", .data$series == "month", .data$scenario == "no_irr", .data$sim == 1) %>% group_by(.data$lake, .data$metric, .data$variable) %>% summarise(median_m = median(.data$value), .groups = "drop") %>% ungroup() %>% left_join(max_levels_ft, by = "lake") %>% mutate(median_ft = NISTmeterTOft(.data$median_m), max_m = NISTftTOmeter(.data$max_ft)) %>% dplyr::select(lake = .data$lake, median_m = .data$median_m, median_ft = .data$median_ft, max_m = .data$max_m, max_ft = .data$max_ft) key_levels$min_m <- NA key_levels$min_ft <- NA for (i in 1:nrow(key_levels)) { l <- key_levels$lake[i] key_levels$min_m[i] <- minValue(CSLSdata::lake_raster[[l]]) key_levels$min_ft[i] <- NISTmeterTOft(key_levels$min_m[i]) } # Key levels, this lake ------------------------------------------------------ median_m <- key_levels$median_m[which(key_levels$lake == lake)] min_m <- key_levels$min_m[which(key_levels$lake == lake)] max_m <- key_levels$max_m[which(key_levels$lake == lake)] upper_contours <- seq(median_m, max_m, by = NISTftTOmeter(0.5)) lower_contours <- seq(median_m, min_m, by = -NISTftTOmeter(0.5)) lake_levels <- unique(c(rev(lower_contours), upper_contours)) # Breaks, this lake ---------------------------------------------------------- fill_limits <- fill[[lake]]$limits fill_breaks <- fill[[lake]]$breaks fill_labels <- fill[[lake]]$labels if (lake == "Pleasant") { scalebar_loc <- "topleft" interval <- 5 } else if (lake == "Plainfield") { scalebar_loc <- "bottomleft" interval <- 2 } else { scalebar_loc <- "bottomleft" interval <- 1 } # Raster --------------------------------------------------------------------- lake_raster <- CSLSdata::lake_raster[[lake]] lake_points <- as.data.frame(rasterToPoints(lake_raster)) colnames(lake_points) <- c("x", "y", "z") lake_points$z <- round(NISTmeterTOft(median_m - lake_points$z), 1) # Filled contours ------------------------------------------------------------ contours <- rasterToContour(lake_raster, levels = lake_levels) contours_sf <- st_as_sf(contours) contours_sf$level <- as.numeric(as.character(contours_sf$level)) contours_sf$level <- median_m - contours_sf$level contours_sf$level <- NISTmeterTOft(contours_sf$level) contours_poly <- st_polygonize(contours_sf) contours_poly <- contours_poly[order(contours_poly$level, decreasing = FALSE),] median <- rasterToContour(lake_raster, levels = median_m) median_sf <- st_as_sf(median) outline <- rasterToContour(lake_raster, levels = max_m) outline_sf <- st_as_sf(outline) # Line contours -------------------------------------------------------------- lake_levels <- lake_levels[(round(contours_sf$level,1) %% interval == 0) & round(contours_sf$level,1) > 0] contours <- rasterToContour(lake_raster, levels = lake_levels) contours_sf <- st_as_sf(contours) contours_sf$level <- as.numeric(as.character(contours_sf$level)) contours_sf$level <- median_m - contours_sf$level contours_sf$level <- round(NISTmeterTOft(contours_sf$level), 1) contours_sf <- st_cast(contours_sf, "LINESTRING") # Plot ----------------------------------------------------------------------- plot_obj <- ggplot() + geom_sf(data = outline_sf, color = NA, fill = NA) for (i in 1:length(contours_poly$level)) { plot_obj <- plot_obj + geom_sf(data = contours_poly[i,], aes(fill = .data$level), color = NA, size = 0.3) } if (lake == "Pleasant") { plot_obj <- plot_obj + geom_sf(data = contours_sf, color = "#072859", # color = "grey50", fill = NA) + scale_fill_gradientn(colors = c("#543005", "white", "#08306B"), values = c(0, 0.2, 1), limits = fill_limits, breaks = fill_breaks, labels = fill_labels) } else { plot_obj <- plot_obj + geom_sf(data = contours_sf, color = "#072859", fill = NA) + scale_fill_gradient2(low = "#543005", high = "#08306B", mid = "white", midpoint = 0, limits = fill_limits, breaks = fill_breaks, labels = fill_labels) } plot_obj <- plot_obj + geom_sf(data = median_sf, color = "black", fill = NA, size = 0.8) + labs(title = "", x = "", y = "", fill = "Lake Depth (ft)") + guides(fill = guide_colorbar(reverse = TRUE, title.position = "right"), color = FALSE) + ggsn::scalebar(data = outline_sf, location = scalebar_loc, dist = 0.1, dist_unit = "mi", transform = FALSE, height = 0.02, st.size = 3.5) + theme_void() + theme(text = element_text(family = "Segoe UI Semilight", size = 10), legend.title = element_text(angle = -90, vjust = 0.5, hjust = 0.5), legend.position = "right", legend.box = margin(0,0,0,0)) return(plot_obj) }
This vignette builds the bathymetry maps used in the CSLS Findings and Recommendations: Appendix B.
The solid line represents the median level in the "no-irrigated-agriculture" scenario. To duplicate the figures that appear in the appendix, add depth labels in another software (e.g., powerpoint or inskscape, white text w/shadows shows up most clearly).
plot_bathymetry("Pleasant") plot_bathymetry("Long") plot_bathymetry("Plainfield")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.