|
|
|
|
|
function(input, output, session) { |
|
|
|
|
|
session$sendCustomMessage("freezeUI", list(text = "Loading stations...")) |
|
|
|
|
|
filtered_parquet_data <- reactive({ |
|
|
month_number <- match(input$month, month.name) |
|
|
|
|
|
|
|
|
dataset <- if (input$parameter %in% c("Temperature", "Air Temperature")) tavg_dataset else prec_dataset |
|
|
|
|
|
|
|
|
dataset %>% |
|
|
filter( |
|
|
VALUE >= -90, |
|
|
YEAR >= input$year_range[1], |
|
|
YEAR <= input$year_range[2], |
|
|
MONTH == month_number |
|
|
) %>% |
|
|
group_by(ID) %>% |
|
|
|
|
|
|
|
|
|
|
|
summarize(mean_value = mean(VALUE, na.rm = TRUE)) %>% |
|
|
collect() |
|
|
}) |
|
|
|
|
|
|
|
|
filtered_stations <- reactive({ |
|
|
filtered_data <- filtered_parquet_data() |
|
|
|
|
|
stations_info <- if (input$parameter %in% c("Temperature", "Air Temperature")) stations_data else prec_stations_data |
|
|
|
|
|
|
|
|
stations_info %>% |
|
|
filter( |
|
|
first_year <= input$year_range[1], |
|
|
last_year >= input$year_range[2], |
|
|
ID %in% filtered_data$ID |
|
|
) %>% |
|
|
left_join(filtered_data, by = "ID") |
|
|
}) |
|
|
|
|
|
output$map_title <- renderText({ |
|
|
paste("Multiannual mean:", input$year_range[1], "to", input$year_range[2]) |
|
|
}) |
|
|
|
|
|
|
|
|
initial_lng <- 5 |
|
|
initial_lat <- mean(stations_data$LATITUDE, na.rm = TRUE) |
|
|
initial_zoom <- 2 |
|
|
|
|
|
|
|
|
|
|
|
selected_station_id <- reactiveVal(NULL) |
|
|
previous_station_id <- reactiveVal(NULL) |
|
|
|
|
|
|
|
|
style_change_trigger <- reactiveVal(0) |
|
|
stations_before_id <- reactiveVal(NULL) |
|
|
current_raster_layers <- reactiveVal(character(0)) |
|
|
stations_loaded <- reactiveVal(FALSE) |
|
|
basemap_debounced <- shiny::debounce(reactive(input$basemap), 200) |
|
|
|
|
|
|
|
|
|
|
|
output$station_map <- renderMaplibre({ |
|
|
print("Initializing MapLibre...") |
|
|
maplibre( |
|
|
style = ofm_positron_style, |
|
|
center = c(initial_lng, initial_lat), |
|
|
zoom = initial_zoom |
|
|
) %>% |
|
|
add_navigation_control(show_compass = FALSE, visualize_pitch = FALSE, position = "top-left") |
|
|
}) |
|
|
|
|
|
|
|
|
observeEvent(input$home_zoom, { |
|
|
maplibre_proxy("station_map") %>% |
|
|
fly_to(center = c(initial_lng, initial_lat), zoom = initial_zoom) |
|
|
}) |
|
|
|
|
|
|
|
|
label_layer_ids <- c( |
|
|
|
|
|
"waterway_line_label", "water_name_point_label", "water_name_line_label", |
|
|
"highway-name-path", "highway-name-minor", "highway-name-major", |
|
|
"highway-shield-non-us", "highway-shield-us-interstate", "road_shield_us", |
|
|
"airport", "label_other", "label_village", "label_town", "label_state", |
|
|
"label_city", "label_city_capital", "label_country_3", "label_country_2", "label_country_1", |
|
|
|
|
|
"road_oneway", "road_oneway_opposite", "poi_r20", "poi_r7", "poi_r1", "poi_transit", |
|
|
|
|
|
"waterway-line-label", "water-name-point-label", "water-name-line-label", |
|
|
"highway-shield-non-us", "highway-shield-us-interstate", "road-shield-us", |
|
|
"label-other", "label-village", "label-town", "label-state", |
|
|
"label-city", "label-city-capital", "label-country-3", "label-country-2", "label-country-1", |
|
|
|
|
|
"place_villages", "place_town", "place_country_2", "place_country_1", |
|
|
"place_state", "place_continent", "place_city_r6", "place_city_r5", |
|
|
"place_city_dot_r7", "place_city_dot_r4", "place_city_dot_r2", "place_city_dot_z7", |
|
|
"place_capital_dot_z7", "place_capital", "roadname_minor", "roadname_sec", |
|
|
"roadname_pri", "roadname_major", "motorway_name", "watername_ocean", |
|
|
"watername_sea", "watername_lake", "watername_lake_line", "poi_stadium", |
|
|
"poi_park", "poi_zoo", "airport_label", "country-label", "state-label", |
|
|
"settlement-major-label", "settlement-minor-label", "settlement-subdivision-label", |
|
|
"road-label", "waterway-label", "natural-point-label", "poi-label", "airport-label" |
|
|
) |
|
|
|
|
|
non_label_layer_ids <- c( |
|
|
"background", "park", "water", "landcover_ice_shelf", "landcover_glacier", |
|
|
"landuse_residential", "landcover_wood", "waterway", "building", |
|
|
"tunnel_motorway_casing", "tunnel_motorway_inner", "aeroway-taxiway", |
|
|
"aeroway-runway-casing", "aeroway-area", "aeroway-runway", |
|
|
"road_area_pier", "road_pier", "highway_path", "highway_minor", |
|
|
"highway_major_casing", "highway_major_inner", "highway_major_subtle", |
|
|
"highway_motorway_casing", "highway_motorway_inner", "highway_motorway_subtle", |
|
|
"railway_transit", "railway_transit_dashline", "railway_service", |
|
|
"railway_service_dashline", "railway", "railway_dashline", |
|
|
"highway_motorway_bridge_casing", "highway_motorway_bridge_inner", |
|
|
"boundary_3", "boundary_2", "boundary_disputed" |
|
|
) |
|
|
|
|
|
apply_label_visibility <- function(proxy, show_labels) { |
|
|
visibility <- if (isTRUE(show_labels)) "visible" else "none" |
|
|
for (layer_id in label_layer_ids) { |
|
|
tryCatch( |
|
|
{ |
|
|
proxy %>% set_layout_property(layer_id, "visibility", visibility) |
|
|
}, |
|
|
error = function(e) {} |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
observeEvent(basemap_debounced(), { |
|
|
basemap <- basemap_debounced() |
|
|
proxy <- maplibre_proxy("station_map") |
|
|
|
|
|
if (basemap %in% c("ofm_positron", "ofm_bright")) { |
|
|
style_url <- if (basemap == "ofm_positron") ofm_positron_style else ofm_bright_style |
|
|
proxy %>% set_style(style_url, preserve_layers = FALSE) |
|
|
stations_before_id("waterway_line_label") |
|
|
|
|
|
current_session <- shiny::getDefaultReactiveDomain() |
|
|
selected_basemap <- basemap |
|
|
|
|
|
later::later(function() { |
|
|
shiny::withReactiveDomain(current_session, { |
|
|
current_basemap <- isolate(input$basemap) |
|
|
if (current_basemap != selected_basemap) { |
|
|
return() |
|
|
} |
|
|
apply_label_visibility(maplibre_proxy("station_map"), isolate(input$show_labels)) |
|
|
style_change_trigger(isolate(style_change_trigger()) + 1) |
|
|
}) |
|
|
}, delay = 0.35) |
|
|
} else if (basemap == "sentinel") { |
|
|
proxy %>% set_style(ofm_positron_style, preserve_layers = FALSE) |
|
|
|
|
|
current_session <- shiny::getDefaultReactiveDomain() |
|
|
selected_basemap <- basemap |
|
|
|
|
|
later::later(function() { |
|
|
shiny::withReactiveDomain(current_session, { |
|
|
current_basemap <- isolate(input$basemap) |
|
|
if (current_basemap != selected_basemap) { |
|
|
return() |
|
|
} |
|
|
|
|
|
unique_suffix <- as.numeric(Sys.time()) * 1000 |
|
|
source_id <- paste0("sentinel_source_", unique_suffix) |
|
|
layer_id <- paste0("sentinel_layer_", unique_suffix) |
|
|
|
|
|
maplibre_proxy("station_map") %>% |
|
|
add_raster_source(id = source_id, tiles = c(sentinel_url), tileSize = 256, attribution = sentinel_attribution) %>% |
|
|
add_layer(id = layer_id, type = "raster", source = source_id, paint = list("raster-opacity" = 1), before_id = "background") |
|
|
|
|
|
for (layer_id_kill in non_label_layer_ids) { |
|
|
tryCatch( |
|
|
{ |
|
|
maplibre_proxy("station_map") %>% set_layout_property(layer_id_kill, "visibility", "none") |
|
|
}, |
|
|
error = function(e) {} |
|
|
) |
|
|
} |
|
|
|
|
|
apply_label_visibility(maplibre_proxy("station_map"), isolate(input$show_labels)) |
|
|
stations_before_id("waterway_line_label") |
|
|
style_change_trigger(isolate(style_change_trigger()) + 1) |
|
|
}) |
|
|
}, delay = 0.5) |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
observeEvent(input$show_labels, { |
|
|
req(input$basemap %in% c("ofm_positron", "ofm_bright", "sentinel")) |
|
|
apply_label_visibility(maplibre_proxy("station_map"), input$show_labels) |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
map_initialized <- reactiveVal(FALSE) |
|
|
|
|
|
|
|
|
|
|
|
observe({ |
|
|
req(input$station_map_zoom) |
|
|
if (!map_initialized()) { |
|
|
later::later(function() { |
|
|
map_initialized(TRUE) |
|
|
}, delay = 0.5) |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
observe({ |
|
|
req(map_initialized()) |
|
|
req(filtered_stations()) |
|
|
style_change_trigger() |
|
|
|
|
|
|
|
|
session$sendCustomMessage("freezeUI", list(text = "Loading stations...")) |
|
|
|
|
|
data <- filtered_stations() |
|
|
param <- input$parameter |
|
|
|
|
|
|
|
|
|
|
|
if (param %in% c("Temperature", "Air Temperature")) { |
|
|
palette_domain <- data$mean_value |
|
|
bins <- c(-Inf, -40, -30, -20, -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5, 15, 17.5, 20, 22.5, 25, 27.5, 30, 35, 40, Inf) |
|
|
blues <- colorRampPalette(c("#053061", "#4393c3", "#d1e5f0"))(10) |
|
|
reds <- colorRampPalette(c("#fff7bc", "#fdae61", "#d73027", "#67001f"))(15) |
|
|
palette_colors <- c(blues, reds) |
|
|
units <- "°C" |
|
|
prefix <- "Mean Temp:" |
|
|
} else { |
|
|
palette_domain <- data$mean_value |
|
|
palette_colors <- colorRampPalette(RColorBrewer::brewer.pal(9, "YlGnBu"))(12) |
|
|
units <- "mm" |
|
|
prefix <- "Mean Precip:" |
|
|
bins <- c(0, 10, 25, 50, 75, 100, 150, 200, 300, 500, 1000, 2000, Inf) |
|
|
} |
|
|
|
|
|
|
|
|
pal_fun <- colorBin(palette_colors, domain = palette_domain, bins = bins, na.color = "transparent") |
|
|
|
|
|
|
|
|
|
|
|
yr <- input$year_range |
|
|
popup_html <- paste0( |
|
|
"Station: ", data$NAME, "<br>", |
|
|
"Country: ", data$Country, "<br>", |
|
|
"ID: ", data$ID, "<br>", |
|
|
"Elevation: ", data$STNELEV, " m<br>", |
|
|
"Available years: ", data$first_year, " - ", data$last_year, "<br>", |
|
|
"Selected years: ", yr[1], " - ", yr[2], "<br>", |
|
|
prefix, " ", round(data$mean_value, 1), " ", units, |
|
|
"<br><span style='color:red;'>Click to get graph and data</span>" |
|
|
) |
|
|
|
|
|
map_data <- data %>% |
|
|
mutate( |
|
|
circle_color = pal_fun(mean_value), |
|
|
popup_content = popup_html |
|
|
) %>% |
|
|
st_as_sf(coords = c("LONGITUDE", "LATITUDE"), crs = 4326) |
|
|
|
|
|
|
|
|
maplibre_proxy("station_map") %>% |
|
|
clear_layer("stations") %>% |
|
|
add_circle_layer( |
|
|
id = "stations", |
|
|
source = map_data, |
|
|
circle_color = get_column("circle_color"), |
|
|
circle_radius = 5, |
|
|
circle_stroke_color = get_column("circle_color"), |
|
|
circle_stroke_width = 2, |
|
|
circle_opacity = 0.7, |
|
|
circle_stroke_opacity = 1, |
|
|
tooltip = get_column("popup_content"), |
|
|
before_id = stations_before_id() |
|
|
) |
|
|
|
|
|
|
|
|
cur_sel <- isolate(selected_station_id()) |
|
|
update_selection_style(cur_sel) |
|
|
|
|
|
|
|
|
session$sendCustomMessage("unfreezeUI", list()) |
|
|
}) |
|
|
|
|
|
|
|
|
update_selection_style <- function(id) { |
|
|
if (is.null(id)) { |
|
|
|
|
|
maplibre_proxy("station_map") %>% |
|
|
set_paint_property("stations", "circle-radius", 5) %>% |
|
|
set_paint_property("stations", "circle-stroke-width", 2) %>% |
|
|
|
|
|
set_paint_property("stations", "circle-stroke-color", list("get", "circle_color")) |
|
|
} else { |
|
|
|
|
|
|
|
|
radius_expr <- list("case", list("==", list("get", "ID"), id), 8, 5) |
|
|
|
|
|
|
|
|
width_expr <- list("case", list("==", list("get", "ID"), id), 3, 2) |
|
|
|
|
|
|
|
|
color_expr <- list("case", list("==", list("get", "ID"), id), "#FF0000", list("get", "circle_color")) |
|
|
|
|
|
maplibre_proxy("station_map") %>% |
|
|
set_paint_property("stations", "circle-radius", radius_expr) %>% |
|
|
set_paint_property("stations", "circle-stroke-width", width_expr) %>% |
|
|
set_paint_property("stations", "circle-stroke-color", color_expr) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
observeEvent(selected_station_id(), |
|
|
{ |
|
|
req(map_initialized()) |
|
|
update_selection_style(selected_station_id()) |
|
|
}, |
|
|
ignoreInit = TRUE |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
time_series_data <- reactive({ |
|
|
req(selected_station_id()) |
|
|
|
|
|
station_id <- selected_station_id() |
|
|
month <- input$month |
|
|
dataset <- if (input$parameter == "Temperature") tavg_dataset else prec_dataset |
|
|
|
|
|
|
|
|
time_series_data <- |
|
|
dataset %>% |
|
|
filter( |
|
|
VALUE >= -90, |
|
|
YEAR >= input$year_range[1], |
|
|
YEAR <= input$year_range[2], |
|
|
MONTH == match(input$month, month.name), |
|
|
ID == station_id |
|
|
) %>% |
|
|
collect() |> |
|
|
mutate(YEAR = as.numeric(YEAR)) |
|
|
|
|
|
time_series_data |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
output$time_series_plot <- renderPlotly({ |
|
|
data <- time_series_data() |
|
|
req(nrow(data) > 0) |
|
|
|
|
|
station_id <- selected_station_id() |
|
|
month <- input$month |
|
|
param <- input$parameter |
|
|
y_label <- if (param == "Temperature") "Temperature (°C)" else "Precipitation (mm)" |
|
|
title <- if (param == "Temperature") "Daily Mean Temperature" else "Total Precipitation" |
|
|
|
|
|
render_time_series_plot(data, station_id, month, y_label, title) |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
observeEvent(input$station_map_feature_click, { |
|
|
clicked <- input$station_map_feature_click |
|
|
|
|
|
|
|
|
is_station_layer <- FALSE |
|
|
if (!is.null(clicked$layer_id) && clicked$layer_id == "stations") is_station_layer <- TRUE |
|
|
if (!is.null(clicked$layer) && clicked$layer == "stations") is_station_layer <- TRUE |
|
|
|
|
|
if (!is.null(clicked) && is_station_layer) { |
|
|
|
|
|
props <- clicked$properties |
|
|
|
|
|
click_id <- if (!is.null(props$ID)) props$ID else props$id |
|
|
|
|
|
print(paste("Selected ID:", click_id)) |
|
|
if (!is.null(click_id)) { |
|
|
selected_station_id(click_id) |
|
|
|
|
|
|
|
|
if (!is.null(clicked$lng) && !is.null(clicked$lat)) { |
|
|
maplibre_proxy("station_map") %>% |
|
|
fly_to(center = c(clicked$lng, clicked$lat), zoom = input$station_map_zoom) |
|
|
} |
|
|
} |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
url_initialized <- reactiveVal(FALSE) |
|
|
|
|
|
parse_url_params <- function(query) { |
|
|
params <- list() |
|
|
if (length(query) == 0 || query == "") { |
|
|
return(params) |
|
|
} |
|
|
|
|
|
q_str <- sub("^\\?", "", query) |
|
|
pairs <- strsplit(q_str, "&")[[1]] |
|
|
for (pair in pairs) { |
|
|
parts <- strsplit(pair, "=")[[1]] |
|
|
if (length(parts) == 2) { |
|
|
key <- parts[1] |
|
|
val <- URLdecode(parts[2]) |
|
|
params[[key]] <- val |
|
|
} |
|
|
} |
|
|
params |
|
|
} |
|
|
|
|
|
|
|
|
observe({ |
|
|
req(!url_initialized()) |
|
|
query <- session$clientData$url_search |
|
|
params <- parse_url_params(query) |
|
|
|
|
|
if (length(params) > 0) { |
|
|
|
|
|
if (!is.null(params$parameter)) { |
|
|
updateSelectInput(session, "parameter", selected = params$parameter) |
|
|
} |
|
|
|
|
|
|
|
|
if (!is.null(params$month)) { |
|
|
updateSelectInput(session, "month", selected = params$month) |
|
|
} |
|
|
|
|
|
|
|
|
if (!is.null(params$start) && !is.null(params$end)) { |
|
|
updateSliderInput(session, "year_range", value = c(as.numeric(params$start), as.numeric(params$end))) |
|
|
} |
|
|
|
|
|
|
|
|
if (!is.null(params$station)) { |
|
|
station_ref <- params$station |
|
|
shinyjs::delay(1000, { |
|
|
stations_info <- if (input$parameter %in% c("Temperature", "Air Temperature")) stations_data else prec_stations_data |
|
|
match <- stations_info %>% filter(ID == station_ref | NAME == station_ref) |
|
|
if (nrow(match) > 0) { |
|
|
selected_station_id(match$ID[1]) |
|
|
} |
|
|
}) |
|
|
} |
|
|
} |
|
|
url_initialized(TRUE) |
|
|
}) |
|
|
|
|
|
|
|
|
broadcast_state <- function() { |
|
|
sid <- selected_station_id() |
|
|
st_meta <- NULL |
|
|
if (!is.null(sid)) { |
|
|
stations_info <- if (input$parameter %in% c("Temperature", "Air Temperature")) stations_data else prec_stations_data |
|
|
st_meta <- stations_info %>% |
|
|
filter(ID == sid) %>% |
|
|
head(1) |
|
|
} |
|
|
|
|
|
station_id <- if (!is.null(st_meta) && nrow(st_meta) > 0) as.character(st_meta$ID) else NULL |
|
|
station_name <- if (!is.null(st_meta) && nrow(st_meta) > 0) as.character(st_meta$NAME) else NULL |
|
|
country <- if (!is.null(st_meta) && nrow(st_meta) > 0) as.character(st_meta$Country) else NULL |
|
|
|
|
|
session$sendCustomMessage("updateParentURL", list( |
|
|
station = station_id, |
|
|
stationName = station_name, |
|
|
country = country, |
|
|
parameter = input$parameter, |
|
|
month = input$month, |
|
|
yearStart = input$year_range[1], |
|
|
yearEnd = input$year_range[2] |
|
|
)) |
|
|
} |
|
|
|
|
|
|
|
|
observe({ |
|
|
|
|
|
sid <- selected_station_id() |
|
|
param <- input$parameter |
|
|
month <- input$month |
|
|
year_range <- input$year_range |
|
|
|
|
|
req(url_initialized()) |
|
|
|
|
|
|
|
|
st_meta <- NULL |
|
|
if (!is.null(sid)) { |
|
|
stations_info <- if (param %in% c("Temperature", "Air Temperature")) stations_data else prec_stations_data |
|
|
st_meta <- stations_info %>% |
|
|
filter(ID == sid) %>% |
|
|
head(1) |
|
|
} |
|
|
|
|
|
station_id <- if (!is.null(st_meta) && nrow(st_meta) > 0) as.character(st_meta$ID) else NULL |
|
|
station_name <- if (!is.null(st_meta) && nrow(st_meta) > 0) as.character(st_meta$NAME) else NULL |
|
|
country <- if (!is.null(st_meta) && nrow(st_meta) > 0) as.character(st_meta$Country) else NULL |
|
|
|
|
|
session$sendCustomMessage("updateParentURL", list( |
|
|
station = station_id, |
|
|
stationName = station_name, |
|
|
country = country, |
|
|
parameter = param, |
|
|
month = month, |
|
|
yearStart = year_range[1], |
|
|
yearEnd = year_range[2] |
|
|
)) |
|
|
}) |
|
|
|
|
|
|
|
|
observe({ |
|
|
req(input$month, input$year_range) |
|
|
|
|
|
station_id <- selected_station_id() |
|
|
month <- input$month |
|
|
param <- input$parameter |
|
|
y_label <- if (param == "Temperature") "Temperature (°C)" else "Precipitation (mm)" |
|
|
title <- if (param == "Temperature") "Daily Mean Temperature" else "Total Precipitation" |
|
|
|
|
|
|
|
|
output$time_series_plot <- renderPlotly({ |
|
|
data <- time_series_data() |
|
|
req(nrow(data) > 0) |
|
|
|
|
|
render_time_series_plot(data, station_id, month, y_label, title) |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
plot_available <- reactive({ |
|
|
req(selected_station_id()) |
|
|
nrow(time_series_data()) > 0 |
|
|
}) |
|
|
|
|
|
|
|
|
output$plot_available <- reactive({ |
|
|
plot_available() |
|
|
}) |
|
|
outputOptions(output, "plot_available", suspendWhenHidden = FALSE) |
|
|
|
|
|
|
|
|
|
|
|
output$plot_panel <- renderUI({ |
|
|
if (plot_available()) { |
|
|
absolutePanel( |
|
|
draggable = F, |
|
|
bottom = 30, |
|
|
left = "50%", |
|
|
right = "auto", |
|
|
width = "95%", |
|
|
height = "auto", |
|
|
style = "transform: translateX(-50%); max-width: 450px; background-color: rgba(255, 255, 255, 0.8); border-radius: 10px; padding: 10px;", |
|
|
|
|
|
|
|
|
plotlyOutput("time_series_plot", height = "200px"), |
|
|
|
|
|
|
|
|
downloadButton( |
|
|
outputId = "download_data", |
|
|
label = NULL, |
|
|
icon = icon("download"), |
|
|
class = "custom-download-button", |
|
|
style = "float: left; margin-top: -10px;" |
|
|
) |> |
|
|
tooltip("Download data") |
|
|
) |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
output$map_legend <- renderUI({ |
|
|
param <- input$parameter |
|
|
|
|
|
|
|
|
if (param %in% c("Temperature", "Air Temperature")) { |
|
|
bins <- c(-Inf, -40, -30, -20, -15, -12.5, -10, -7.5, -5, -2.5, 0, 2.5, 5, 7.5, 10, 12.5, 15, 17.5, 20, 22.5, 25, 27.5, 30, 35, 40, Inf) |
|
|
blues <- colorRampPalette(c("#053061", "#4393c3", "#d1e5f0"))(10) |
|
|
reds <- colorRampPalette(c("#fff7bc", "#fdae61", "#d73027", "#67001f"))(15) |
|
|
colors <- c(blues, reds) |
|
|
units <- "°C" |
|
|
|
|
|
|
|
|
display_bins <- rev(bins) |
|
|
display_colors <- rev(colors) |
|
|
} else { |
|
|
|
|
|
colors <- colorRampPalette(RColorBrewer::brewer.pal(9, "YlGnBu"))(12) |
|
|
units <- "mm" |
|
|
bins <- c(0, 10, 25, 50, 75, 100, 150, 200, 300, 500, 1000, 2000, Inf) |
|
|
|
|
|
display_bins <- rev(bins) |
|
|
display_colors <- rev(colors) |
|
|
} |
|
|
|
|
|
|
|
|
legend_items <- lapply(seq_along(display_colors), function(i) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val_high <- display_bins[i] |
|
|
val_low <- display_bins[i + 1] |
|
|
color <- display_colors[i] |
|
|
|
|
|
label_text <- if (is.infinite(val_high)) { |
|
|
paste0("> ", val_low) |
|
|
} else if (is.infinite(val_low)) { |
|
|
paste0("< ", val_high) |
|
|
} else { |
|
|
paste0(val_low, " – ", val_high) |
|
|
} |
|
|
|
|
|
tags$div( |
|
|
style = "display: flex; align-items: center; margin-bottom: 0px;", |
|
|
tags$span( |
|
|
style = sprintf("background: %s; width: 18px; height: 18px; margin-right: 8px; display: inline-block; opacity: 0.9; border: 1px solid #ccc; border-bottom: none;", color) |
|
|
), |
|
|
tags$span( |
|
|
style = "font-size: 11px;", |
|
|
label_text |
|
|
) |
|
|
) |
|
|
}) |
|
|
|
|
|
absolutePanel( |
|
|
bottom = 30, left = 20, |
|
|
draggable = FALSE, |
|
|
width = 130, |
|
|
style = "background: white; padding: 10px; border-radius: 4px; box-shadow: 0 0 5px rgba(0,0,0,0.3); max-height: 80vh; overflow-y: auto;", |
|
|
tags$h6(style = "margin-top: 0; margin-bottom: 8px; font-weight: bold; text-align: center;", units), |
|
|
do.call(tags$div, legend_items) |
|
|
) |
|
|
}) |
|
|
|
|
|
|
|
|
output$download_data <- downloadHandler( |
|
|
filename = function() { |
|
|
|
|
|
station_id <- selected_station_id() |
|
|
month <- input$month |
|
|
info <- if (input$parameter %in% c("Temperature", "Air Temperature")) tavg_meta else prec_meta |
|
|
paste0(info$NAME[info$ID == station_id], "_", station_id, "_", month, ".csv") |
|
|
}, |
|
|
content = function(file) { |
|
|
|
|
|
data <- time_series_data() |
|
|
|
|
|
|
|
|
write.csv(data, file, row.names = FALSE) |
|
|
} |
|
|
) |
|
|
} |
|
|
|