library(knitr) library(CSLSchem) library(dplyr) library(ggplot2) library(extrafont) library(patchwork) library(NISTunits) library(lubridate) library(stringr) library(patchwork) text_size <- 12 lakes <- c("Pleasant", "Long", "Plainfield") water_chem <- CSLSdata::water_chem plot_HOBO <- function(lake, water_chem) { ltmp <- filter_parameter(water_chem, "TEMPERATURE HOBO") %>% filter(.data$lake == !!lake, !is.na(.data$result)) %>% group_by(.data$date) %>% mutate(min_depth = min(.data$depth1_m), max_depth = max(.data$depth1_m)) %>% ungroup() %>% filter(.data$depth1_m == .data$min_depth | .data$depth1_m == .data$max_depth) %>% mutate(depth = ifelse(.data$depth1_m > 2, "Bottom", "Surface"), parameter = "Temperature") %>% select(.data$date, .data$result, .data$depth, .data$parameter) DO <- filter_parameter(water_chem, "DISSOLVED OXYGEN HOBO") %>% filter(.data$lake == !!lake, !is.na(.data$result)) %>% group_by(.data$date) %>% mutate(min_depth = min(.data$depth1_m), max_depth = max(.data$depth1_m)) %>% ungroup() %>% filter(.data$depth1_m == .data$min_depth | .data$depth1_m == .data$max_depth) %>% mutate(depth = ifelse(.data$depth1_m > 3, "Bottom", "Surface"), parameter = "DO") %>% select(.data$date, .data$result, .data$depth, .data$parameter) plot_df <- rbind(ltmp, DO) plot_obj <- ggplot() + geom_line(data = filter(plot_df, parameter == "Temperature"), aes(x = date, y = result, color = depth, linetype = parameter)) + geom_line(data = filter(plot_df, parameter == "DO"), aes(x = date, y = result*2, color = depth, linetype = parameter)) + scale_x_datetime(breaks = "2 months", date_labels = "%b %y") + labs(x = "", y = "Temperature (deg C)", title = sprintf("%s Lake", lake)) + scale_y_continuous(sec.axis = sec_axis(~./2, name = "Dissolved Oxygen (mg/L)")) + scale_color_brewer(name = "", palette = "Paired") + scale_linetype_manual(name = "", breaks = c("Temperature", "DO"), values = c("solid", "dotted")) + theme_bw() + theme(text = element_text(family = "Segoe UI Semilight", size = text_size), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.position = "top") return(plot_obj) } plot_field <- function(lake, water_chem) { ltmp <- filter_parameter(water_chem, "TEMPERATURE FIELD") %>% filter(.data$lake == !!lake, !is.na(.data$result)) %>% group_by(.data$date) %>% mutate(min_depth = min(.data$depth1_m), max_depth = max(.data$depth1_m)) %>% ungroup() %>% filter(.data$depth1_m == .data$min_depth | .data$depth1_m == .data$max_depth) %>% mutate(depth = ifelse(.data$depth1_m > 1.5, "Bottom", "Surface")) %>% select(.data$date, .data$result, .data$depth) DO <- filter_parameter(water_chem, "DISSOLVED OXYGEN FIELD") %>% filter(.data$lake == !!lake, !is.na(.data$result)) %>% group_by(.data$date) %>% mutate(min_depth = min(.data$depth1_m), max_depth = max(.data$depth1_m)) %>% ungroup() %>% filter(.data$depth1_m == .data$min_depth | .data$depth1_m == .data$max_depth) %>% mutate(depth = ifelse(.data$depth1_m > 1.5, "Bottom", "Surface")) %>% select(.data$date, .data$result, .data$depth) plot_obj <- ggplot() + geom_line(data = ltmp, aes(x = date, y = result, color = depth, linetype = "Temperature"), size = 1) + geom_line(data = DO, aes(x = date, y = result*2, color = depth, linetype = "DO"), size = 1) + scale_x_datetime(breaks = "2 months", date_labels = "%b %y") + labs(x = "", y = "Temperature (deg C)", title = sprintf("%s Lake", lake)) + scale_y_continuous(sec.axis = sec_axis(~./2, name = "Dissolved Oxygen (mg/L)")) + scale_color_brewer(name = "", palette = "Paired") + scale_linetype_manual(name = "", breaks = c("Temperature", "DO"), values = c("solid", "dotted")) + theme_bw() + theme(text = element_text(family = "Segoe UI Semilight", size = text_size), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.position = "top") return(plot_obj) }
p1 <- plot_HOBO("Pleasant", water_chem) p2 <- plot_field("Long", water_chem) p3 <- plot_field("Plainfield", water_chem) p1 + p2 + p3 + plot_layout(guides = "auto", ncol = 1) + plot_annotation(tag_levels = 'a') & theme(plot.tag = element_text(family = "Segoe UI Semibold", size = text_size))
lake <- "Pleasant" elev_area_vol <- CSLSdata::elev_area_vol elev_area_vol <- elev_area_vol %>% filter(.data$lake == !!lake) elev_area_vol$elev_ft <- NISTmeterTOft(elev_area_vol$elev_m) # Calculate maximum depth (meters) psnt_raster <- CSLSlevels::lake_raster[[lake]] min_elev <- raster::minValue(psnt_raster) elev_area_vol$max_depth_m <- elev_area_vol$elev_m - min_elev # Calculate log10 lake area (hectares) elev_area_vol$area_ha <- NISTsqrMeterTOhectare(elev_area_vol$area_m2) # Calculate Lathrop/Lillie ratio elev_area_vol$ratio <- (elev_area_vol$max_depth_m - 0.1)/ log10(elev_area_vol$area_ha) # Calculate approx elevation where ratio = 3.8 threshold_elev <- approx(x = elev_area_vol$ratio, y = elev_area_vol$elev_ft, xout = 3.8)$y thresholds <- data.frame(ratio = c(0,3.8,3.8,3.8), elev_ft = c(threshold_elev, threshold_elev, threshold_elev, min(elev_area_vol$elev_ft))) # Calculate 10, 50, 90 exceedance levels csls_levels <- CSLSlevels::csls_levels psnt_levels <- csls_levels %>% filter(.data$lake == !!lake, year(.data$date) >= 1981, year(.data$date) <= 2018) %>% mutate(level = .data$level_pred) psnt_probs <- CSLSlevels::calculate_exceedances(df = psnt_levels, probs = c(10,50,90)) psnt_probs$value <- NISTmeterTOft(psnt_probs$value) # Plot ratio vs. elevation plot_obj <- ggplot() + geom_line(data = elev_area_vol, aes(x = ratio, y = elev_ft), size = 1) + geom_path(data = thresholds, aes(x = ratio, y = elev_ft), linetype = "dashed") + geom_text(data = data.frame(x = 3.9, y = threshold_elev - 0.5, label = sprintf("%.1f ft", threshold_elev)), aes(x = x, y = y, label = label), hjust = 0, family = "Segoe UI Semilight", size = 3.5) + geom_text(data = data.frame(x = c(2, 2), y = c(threshold_elev + 1.5, threshold_elev - 1.5), label = c("Stratified Lake", "Mixed Lake")), aes(x = x, y = y, label = label), family = "Segoe UI Semilight", size = 3.5) + geom_rect(data = data.frame(ymin = psnt_probs$value[psnt_probs$variable == "90"], ymax = psnt_probs$value[psnt_probs$variable == "10"], xmin = -Inf, xmax = Inf), aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), fill = "grey", alpha = 0.5) + geom_hline(yintercept = psnt_probs$value[psnt_probs$variable == "50"]) + labs(x = "Lathrop/Lillie ratio", y = "Lake Elevation (ft)", title = sprintf("%s Lake", lake)) + scale_x_continuous(expand = c(0,0), limits = c(0,max(elev_area_vol$ratio))) + scale_y_continuous(expand = c(0,0)) + theme_bw() + theme(text = element_text(family = "Segoe UI Semilight", size = text_size), plot.title = element_text(hjust = 0.5)) plot_obj
lake <- "Pleasant" # Plot names plot_names <- data.frame(description = c("MANGANESE, TOTAL RECOVERABLE", "IRON TOTAL RECOVERABLE", "SULFATE TOTAL", "SULFATE DISS, AS SO4", "PHOSPHORUS TOTAL", "DISSOLVED OXYGEN FIELD"), name = c("Mn (ug/L)", "Fe (mg/L)", "SO4 (mg/L)", "SO4 (mg/L)", "P (ug/L)", "DO (mg/L)")) # Chem at lake bottom deep_chem <- water_chem %>% filter(.data$lake == !!lake, .data$site_type == "lake", !.data$description %in% c("TEMPERATURE HOBO", "DISSOLVED OXYGEN HOBO", "PH FIELD", "TEMPERATURE FIELD", "DISSOLVED OXYGEN FIELD", "CONDUCTIVITY FIELD"), .data$depth1_m > 3) %>% mutate(date = floor_date(.data$date, unit = "day"), depth = "Bottom") %>% dplyr::select(.data$date, .data$description, .data$result, .data$units, .data$depth1_m, .data$flag, .data$depth) deep_chem_days <- unique(deep_chem$date) deep_chem_day_depths <- unique(deep_chem[,c("date", "depth1_m")]) # DO at lake bottom deep_DO <- water_chem %>% filter(.data$lake == !!lake, .data$site_type == "lake", floor_date(.data$date, unit = "day") %in% deep_chem_days, .data$description == c("DISSOLVED OXYGEN FIELD"), .data$depth1_m > 3) %>% mutate(date = floor_date(.data$date, unit = "day"), depth = "Bottom") %>% dplyr::select(.data$date, .data$description, .data$result, .data$depth1_m, .data$depth) deep_DO <- merge(deep_DO, deep_chem_day_depths, by = c("date", "depth1_m")) # Chem and DO at lake surface shallow_chem <- water_chem %>% filter(.data$lake == !!lake, .data$site_type == "lake", .data$description %in% c("MANGANESE, TOTAL RECOVERABLE", "IRON TOTAL RECOVERABLE", "SULFATE TOTAL", "SULFATE DISS, AS SO4", "PHOSPHORUS TOTAL", "DISSOLVED OXYGEN FIELD"), .data$depth1_m == 0) %>% mutate(date = floor_date(.data$date, unit = "day"), depth = "Surface") %>% filter(.data$date %in% deep_chem_days) %>% select(.data$date, .data$description, .data$result, .data$depth) all_chem <- bind_rows(deep_chem, shallow_chem, deep_DO) all_chem$name <- as.character(all_chem$description) for (p in 1:nrow(plot_names)) { all_chem$name <- str_replace_all(all_chem$name, as.character(plot_names$description[p]), as.character(plot_names$name[p])) } all_chem <- all_chem %>% mutate(year = year(.data$date), day = yday(.data$date), result = ifelse(.data$description == "PHOSPHORUS TOTAL", as.numeric(.data$result)*1000, as.numeric(.data$result))) %>% filter(.data$day > yday(as_datetime("2018-07-15")), .data$day < yday(as_datetime("2018-09-15"))) limits <- data.frame(name = c("Mn (ug/L)", "Fe (mg/L)", "SO4 (mg/L)", "P (ug/L)", "DO (mg/L)", "Mn (ug/L)", "Fe (mg/L)", "SO4 (mg/L)", "P (ug/L)", "DO (mg/L)"), lims = c(0, 0, 0, 0, 0, 15, 3, 10, 20, 15)) # Chem at lake bottom HOBO_DO <- water_chem %>% filter(.data$lake == !!lake, .data$site_type == "lake", .data$description %in% c("DISSOLVED OXYGEN HOBO"), .data$depth1_m > 3, yday(.data$date) > yday(as_datetime("2018-07-15")), yday(.data$date) < yday(as_datetime("2018-09-15"))) %>% group_by(date = floor_date(.data$date, unit = "hour")) %>% mutate(max_depth = max(.data$depth1_m), name = "DO (mg/L)") %>% ungroup() %>% filter(.data$depth1_m == .data$max_depth) # Plot plot_obj <- ggplot() + geom_blank(data = limits, aes(x = as.Date(median(all_chem$day), origin = as.Date("2018-01-01")), y = .data$lims)) + geom_line(data = HOBO_DO, aes(x = as.Date(.data$date), y = as.numeric(.data$result), color = "2018_Bottom")) + geom_line(data = HOBO_DO, aes(x = as.Date(.data$date - years(1)), y = as.numeric(.data$result), color = "2019_Bottom")) + geom_point(data = all_chem, aes(x = as.Date(.data$day, origin = as.Date("2018-01-01")), y = .data$result, shape = sprintf("%d_%s", .data$year, .data$depth), color = sprintf("%d_%s", .data$year, .data$depth)), size = 2) + facet_wrap(~name, ncol = 1, strip.position = "left", scales = "free_y") + labs(x = "", y = "") + # scale_y_continuous(limits = c(0,limits$max)) + scale_x_date(breaks = c(as.Date("2018-07-15"), as.Date("2018-08-05"), as.Date("2018-08-26"), as.Date("2018-09-16")), minor_breaks = c(as.Date("2018-07-15"), as.Date("2018-07-22"), as.Date("2018-07-29"), as.Date("2018-08-05"), as.Date("2018-08-12"), as.Date("2018-08-19"), as.Date("2018-08-26"), as.Date("2018-09-02"), as.Date("2018-09-09"), as.Date("2018-09-16")), date_labels = "%b %d", limits = c(as.Date("2018-07-15"), as.Date("2018-09-16")), expand = c(0,0)) + scale_shape_manual(name = "", labels = c("2018 Surface", "2019 Surface", "2018 Bottom", "2019 Bottom"), breaks = c("2018_Surface", "2019_Surface", "2018_Bottom", "2019_Bottom"), values = c(16, 16, 17, 17)) + scale_color_manual(name = "", labels = c("2018 Surface", "2019 Surface", "2018 Bottom", "2019 Bottom"), breaks = c("2018_Surface", "2019_Surface", "2018_Bottom", "2019_Bottom"), values = c("#A6CEE3", "#1F78B4", "#FB9A99", "#E31A1C")) + theme_bw() + theme(text = element_text(family = "Segoe UI Semilight", size = text_size), legend.position = "right", legend.margin = margin(0,0,0,0), legend.box.margin = margin(0,0,0,0)) plot_obj
water_chem <- CSLSdata::water_chem water_clarity <- water_chem %>% filter(.data$site_type == "lake", .data$description %in% c("SECCHI DEPTH - FEET", "SECCHI DEPTH HIT BOTTOM", "CHLOROPHYLL A, FLUORESCENCE (WELSCHMAYER 1994)"), yday(.data$date) > yday(as_datetime("2018-05-01")), yday(.data$date) < yday(as_datetime("2018-11-15")), .data$flag != "BAD_SAMPLE") %>% mutate(date = floor_date(.data$date, unit = "day"), result = ifelse(.data$result == "ND", "0", .data$result)) %>% select(.data$lake, .data$date, .data$description, .data$result) depth <- water_clarity %>% filter(.data$description == "SECCHI DEPTH - FEET") bottom <- water_clarity %>% filter(.data$description == "SECCHI DEPTH HIT BOTTOM") chla <- water_clarity %>% filter(.data$description == "CHLOROPHYLL A, FLUORESCENCE (WELSCHMAYER 1994)") water_clarity <- full_join(depth, bottom, by = c("date", "lake")) %>% full_join(chla, by = c("date", "lake")) water_clarity$day <- yday(water_clarity$date) water_clarity$year <- year(water_clarity$date) p1 <- ggplot(filter(water_clarity, !is.na(.data$description.y) & !is.na(.data$description.x))) + geom_line(aes(x = as.Date(.data$day, origin = "2018-01-01"), y = as.numeric(.data$result.x), group = as.factor(.data$year), color = as.factor(.data$year))) + geom_point(aes(x = as.Date(.data$day, origin = "2018-01-01"), y = as.numeric(.data$result.x), color = as.factor(.data$year), shape = .data$result.y), size = 2) + facet_grid(~lake, scales = "free_y") + scale_y_reverse(limits = c(30,0)) + scale_x_date(date_breaks = "1 month", date_minor_breaks = "1 month", date_labels = "%b") + scale_color_manual(name = "", values = c("#A6CEE3", "#1F78B4")) + scale_shape_manual(name = "Secchi Hit Bottom?", breaks = c("YES","NO"), labels = c("Yes","No"), values = c(8, 16)) + labs(y = "Secchi Depth (ft)", x = "") + theme_bw() + theme(text = element_text(family = "Segoe UI Semilight", size = text_size), legend.position = "top") p2 <- ggplot(filter(water_clarity, !is.na(.data$description))) + geom_blank(data = water_clarity, aes(x = as.Date(.data$day, origin = "2018-01-01"), y = as.numeric(.data$result.x))) + geom_line(aes(x = as.Date(.data$day, origin = "2018-01-01"), y = as.numeric(.data$result), group = as.factor(.data$year), color = as.factor(.data$year))) + geom_point(aes(x = as.Date(.data$day, origin = "2018-01-01"), y = as.numeric(.data$result), color = as.factor(.data$year)), size = 2) + facet_grid(~lake, scales = "free_y") + scale_x_date(date_breaks = "1 month", date_minor_breaks = "1 month", date_labels = "%b") + scale_color_manual(name = "", values = c("#A6CEE3", "#1F78B4")) + labs(y = "Chlorophyll A (ug/L)", x = "") + theme_bw() + theme(text = element_text(family = "Segoe UI Semilight", size = text_size), legend.position = "top") p1 + p2 + plot_layout(ncol = 1, guides = "collect") & theme(legend.position = "top", legend.box = "horizontal")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.