#' The Eviatlas Shiny App Server.
#' @importFrom utils read.csv write.csv data
#' @param input input set by Shiny.
#' @param output output set by Shiny.
#' @param session session set by Shiny.
#' @import shiny
#' @export
shiny_server <-
function(input, output, session) {
data_internal <- reactiveValues(
raw = NULL,
cols = NULL,
short_cols = NULL,
filtered = NULL
)
if (!exists("study_data", envir = parent.env(environment()), inherits = FALSE)) {
message("study_data not available, using default sample data...")
study_data <- eviatlas::eviatlas_pilotdata
}
output$environment <- renderPrint(
print(ls(envir = parent.env(environment())))
)
# DATA TAB
# if no data are available but input$sample_or_real == 'sample', show intro text
output$start_text <- renderPrint({
cat(readr::read_file(system.file("html_shiny", "AboutEvi.html", package = "eviatlas")))
})
output$about_sysmap_text <- renderPrint({
cat(readr::read_file(system.file("html_shiny", "AboutSysMap.html", package = "eviatlas")))
})
output$how_works_text <- renderPrint({
cat(readr::read_file(system.file("html_shiny", "HowEviWorks.html", package = "eviatlas")))
})
output$how_cite_text <- renderPrint({
cat(readr::read_file(system.file("html_shiny", "HowCiteEvi.html", package = "eviatlas")))
})
output$uploaded_attributes <- renderPrint({
if (is.null(data_internal$raw) & input$sample_or_real == "user") {
cat("Upload a dataset using the panel to the right -->")
} else {
cat("<h3>Attributes of uploaded data:</h3>")
}
})
# if CSV data are supplied, add them to data_internal
observeEvent(input$sysmapdata_upload, {
data_internal$raw <- read.csv(
file = input$sysmapdata_upload$datapath,
header = input$header,
sep = input$sep,
dec = input$dec,
quote = input$quote,
fileEncoding = input$upload_encoding,
stringsAsFactors = F
)
data_internal$filtered <- data_internal$raw # instantiate filtered table with raw values
})
# if shapefile data are supplied, add them to data_internal
observeEvent(input$shape, {
req(input$shape)
shpdf <- input$shape
tempdirname <- dirname(shpdf$datapath[1])
for (i in 1:nrow(shpdf)) {
file.rename(shpdf$datapath[i], paste0(tempdirname, "/", shpdf$name[i]))
}
data_internal$raw <- sf::st_read(
paste(tempdirname,
shpdf$name[grep(pattern = "*.shp$", shpdf$name)],
sep = "/"
)
)
data_internal$filtered <- data_internal$raw # instantiate filtered table with raw values
})
data_active <- reactive({
req(data_internal$raw)
dataset_gateway <- (!is.null(input$map_filtered_select))
d_out <- if (dataset_gateway && input$map_filtered_select == TRUE) {
data_internal$filtered
} else {
data_internal$raw
}
d_out
})
# if user switches to internal data, clear in-app data
observeEvent(input$sample_or_real, {
if (input$sample_or_real == "sample") {
data_internal$raw <- get("study_data")
data_internal$filtered <- data_internal$raw # instantiate filtered table with raw values
} else {
data_internal$raw <- NULL
data_internal$filtered <- NULL
}
})
# give an outline of what that dataset contains
output$data_summary <- renderPrint({
if (!is.null(data_internal$raw)) {
cat(paste0(
"You've uploaded a dataset containing ", nrow(data_internal$raw),
" rows and ", ncol(data_internal$raw),
" columns. If this is not what you expected, you might want to",
" adjust the CSV properties settings on the right and try again.<br>",
"<br> Detected column names as follows:<br>",
paste(colnames(data_internal$raw), collapse = "<br>")
))
}
})
# FILTER TAB
output$filter_selector <- renderUI({
req(data_internal$raw)
shinyWidgets::pickerInput(
"selected_variable",
label = "Select Columns:",
choices = colnames(data_internal$raw),
selected = colnames(data_active())[1:10],
width = "100%", options = list(`actions-box` = TRUE, `selectedTextFormat` = "static"),
multiple = T
)
})
output$go_button <- renderUI({
if (!is.null(data_internal$raw)) {
actionButton("go_subset", "Apply Filter")
} else {
wellPanel('To start, upload data in the "About EviAtlas" tab.')
}
})
observeEvent(input$go_subset, {
data_internal$filtered <- filtered_df()
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "mapdatabase_filter_select",
value = TRUE
)
})
##### begin dynamic filter #####
fields <- reactive({
c(colnames(data_internal$raw))
})
# filter_by <- function (df, ...) {
# filter_conditions <- quos(...)
# df %>% dplyr::filter(!!!filter_conditions)
# }
# filter on 1 column
filter1_by <- function(df, fcol1, fv1) {
filter_var1 <- dplyr::quo(fcol1)
df %>%
dplyr::filter_at(
dplyr::vars(!!filter_var1), dplyr::all_vars(. == fv1)
)
}
# filter on 2 columns
filter2_by <- function(df, fcol1, fv1, fcol2, fv2) {
filter_var1 <- dplyr::quo(fcol1)
filter_var2 <- dplyr::quo(fcol2)
df %>%
dplyr::filter_at(
dplyr::vars(!!filter_var1), dplyr::all_vars(. == fv1)
) %>%
dplyr::filter_at(
dplyr::vars(!!filter_var2), dplyr::all_vars(. == fv2)
)
}
# filter on 3 columns
filter3_by <- function(df, fcol1, fv1, fcol2, fv2, fcol3, fv3) {
filter_var1 <- dplyr::quo(fcol1)
filter_var2 <- dplyr::quo(fcol2)
filter_var3 <- dplyr::quo(fcol3)
df %>%
dplyr::filter_at(
dplyr::vars(!!filter_var1), dplyr::all_vars(. == fv1)
) %>%
dplyr::filter_at(
dplyr::vars(!!filter_var2), dplyr::all_vars(. == fv2)
) %>%
dplyr::filter_at(
dplyr::vars(!!filter_var3), dplyr::all_vars(. == fv3)
)
}
filtered_df <- reactive({
# case when all three filters are used
if (input$filter3req & input$filter2req) {
filter3_by(
data_internal$raw, input$filter1, input$filter1val,
input$filter2, input$filter2val,
input$filter3, input$filter3val
)
} else if (input$filter2req) {
# case when two filters are used
filter2_by(
data_internal$raw, input$filter1, input$filter1val,
input$filter2, input$filter2val
)
} else {
# case when only one filter is used
filter1_by(data_internal$raw, input$filter1, input$filter1val)
}
})
# vector of picklist values for the first selected filter
choicevec1 <- reactive({
req(data_internal$raw)
if (any(class(data_internal$raw) == "sf")) {
data_internal$raw %>%
sf::st_drop_geometry() %>%
dplyr::select(input$filter1) %>%
unique()
} else {
data_internal$raw %>%
dplyr::select(input$filter1) %>%
unique()
}
})
# select first filter column from fields vector
output$filter1eval <- renderUI({
selectInput("filter1", "Select filter criteria 1:", choices = fields())
})
# renders the picklist for the first selected filter
output$filter1choice <- renderUI(
selectizeInput(
"filter1val",
"Select filter 1 condition:",
choices = choicevec1(),
multiple = TRUE
)
)
# second column chosen from all remaining fields
output$filter2eval <- renderUI({
selectInput("filter2", "Select filter criteria 2:",
choices = fields()[fields() != input$filter1]
)
})
# vector of picklist values for the second selected filter
choicevec2 <- reactive({
req(data_internal$raw)
if (any(class(data_internal$raw) == "sf")) {
filter1_by(
sf::st_drop_geometry(data_internal$raw), input$filter1, input$filter1val
) %>%
dplyr::select(input$filter2) %>%
unique()
} else {
filter1_by(
data_internal$raw, input$filter1, input$filter1val
) %>%
dplyr::select(input$filter2) %>%
unique()
}
})
# renders picklist for filter 2
output$filter2choice <- renderUI(
selectizeInput(
"filter2val",
"Select filter 2 condition:",
choices = choicevec2(),
multiple = TRUE
)
)
# third column selected from remaining fields
output$filter3eval <- renderUI({
selectInput("filter3",
"Select filter criteria 3:",
choices = fields()[!fields() %in% c(input$filter1, input$filter2)]
)
})
# vector of picklist values for third selected column
choicevec3 <- reactive({
req(data_internal$raw)
if (any(class(data_internal$raw) == "sf")) {
filter2_by(
sf::st_drop_geometry(data_internal$raw),
input$filter1, input$filter1val,
input$filter2, input$filter2val
) %>%
dplyr::select(input$filter3) %>%
unique()
} else {
filter2_by(
data_internal$raw, input$filter1,
input$filter1val, input$filter2,
input$filter2val
) %>%
dplyr::select(input$filter3) %>%
unique()
}
})
# render picklist for filter 3
output$filter3choice <- renderUI(
selectizeInput(
"filter3val",
"Select filter 3 condition:",
choices = choicevec3(),
multiple = TRUE
)
)
##### end dynamic filter ####
output$filtered_table <- DT::renderDataTable(
DT::datatable(data_active(),
filter = c("top"),
# caption = "Use the boxes below column headers to filter data",
class = c("display", "compact"),
style = "bootstrap",
options = list(
scrollX = TRUE,
scrollY = TRUE,
responsive = T,
columnDefs = list(list(
targets = c(1:min(25, ncol(data_internal$filtered))), # will apply render function to lesser of first 25 columns or number of columns in displayed data
render = htmlwidgets::JS( # limits character strings longer than 50 characters to their first 30 chars, and has whole string appear as a tooltip
"function(data, type, row, meta) {",
"return type === 'display' && data.length > 50 ?",
"'<span title=\"' + data + '\">' + data.substr(0, 30) + '...</span>' : data;",
"}"
)
))
)
),
server = T
)
# download the filtered data
output$download_filtered <- downloadHandler(
"eviatlas-datatable-filtered.csv",
content = function(file) {
s <- input$filtered_table_rows_all
write.csv(data_internal$filtered[s, , drop = FALSE], file)
}
)
# map UI
output$map_columns <- renderUI({
req(input$sample_or_real != "shapefile")
if (!is.null(data_internal$raw)) {
div(list(
div(
selectInput(
inputId = "map_lat_select",
label = "Select Latitude Column",
choices = colnames(data_active()),
selected = eviatlas:::get_latitude_cols(data_active())
)
),
div(
selectInput(
inputId = "map_lng_select",
label = "Select Longitude Column",
choices = colnames(data_active()),
selected = eviatlas:::get_longitude_cols(data_active())
)
)
))
} else {
wellPanel('To use the map, upload data in the "About EviAtlas" tab.')
}
})
output$atlas_filter <- renderUI({
# req(data_internal$raw)
div(
title = "Use the Map Database tab to subset data",
shinyWidgets::materialSwitch(
inputId = "map_filtered_select",
label = "Use filtered data?",
value = FALSE,
inline = T,
status = "primary"
)
)
})
output$atlas_link_popup <- renderUI({
req(input$sample_or_real != "shapefile") # does not work for shapefiles currently
div(
title = "If your dataset has a link to each study, you can include it in the popup when a point is clicked with the mouse. If you have any hyperlinks you wish to display in the pop-up (e.g. email addresses or URLs), select them here.",
selectInput(
inputId = "map_link_select",
label = "Select Link Column (in pop-up)",
choices = c("", eviatlas:::get_link_cols(data_internal$raw)),
selected = ""
)
)
})
output$atlas_selectmap <- renderUI({
req(data_internal$raw)
div(
title = "You can change the default basemap to highlight different geographical features or change the language of map labels",
selectInput(
inputId = "map_basemap_select",
label = "Select Basemap",
choices = c("OpenStreetMap", "OpenTopoMap", "Stamen.TonerLite", "Esri.WorldStreetMap"),
selected = "OpenStreetMap"
)
)
})
output$atlas_popups <- renderUI({
# req(data_internal$raw)
div(
title = "Multiple columns are allowed as popups",
selectizeInput(
inputId = "map_popup_select",
label = "Select Popup Info",
selected = colnames(data_active())[1],
choices = colnames(data_active()),
multiple = T
)
)
})
output$cluster_columns <- renderUI({
req(data_internal$raw)
req(input$sample_or_real != "shapefile") # does not work for shapefiles currently
div(
title = "Toggle displaying points in relative geographic clusters",
shinyWidgets::materialSwitch(
inputId = "map_cluster_select",
label = "Cluster Map Points?",
value = FALSE,
status = "primary"
)
)
})
output$cluster_size <- renderUI({
req(input$sample_or_real != "shapefile") # does not work for shapefiles currently
div(
title = "Adjust cluster sensitivity. Higher numbers correspond to smaller distances",
shinyWidgets::noUiSliderInput(
inputId = "cluster_size_select",
label = "Cluster Sensitivity",
value = 4,
step = 1,
min = 4,
max = 16
)
)
})
output$atlas_color_by <- renderUI({
req(data_internal$raw)
req(input$sample_or_real != "shapefile") # does not work for shapefiles currently
div(
title = "Select variable to color points by",
selectInput(
inputId = "atlas_color_by_select",
label = "Color points by:",
choices = c("", colnames(data_active())),
selected = ""
)
)
})
observeEvent(input$map_filtered_select, {
# Change values for map inputs whenever button is toggled
updateSelectInput(
session,
"map_lat_select",
choices = colnames(data_active()),
selected = eviatlas:::get_latitude_cols(data_active())
)
updateSelectInput(
session,
"map_lng_select",
choices = colnames(data_active()),
selected = eviatlas:::get_longitude_cols(data_active())
)
updateSelectInput(session, "map_link_select",
choices = c("", eviatlas:::get_link_cols(data_active()))
)
updateSelectInput(session, "map_popup_select",
choices = colnames(data_active()),
selected = colnames(data_active())[1]
)
})
# BARPLOT
output$barplot_selector <- renderUI({
req(data_internal$raw)
selectInput(
inputId = "select_timetrend_col",
label = "Select variable 1",
choices = c("", eviatlas:::get_histogram_viable_columns(data_active())),
selected = ""
)
})
# Location Frequency Plot
output$location_plot_selector <- renderUI({
req(data_internal$raw)
selectInput(
inputId = "select_loc_col",
label = "Select Variable 2",
choices = c("", eviatlas:::get_histogram_viable_columns(data_active())),
selected = ""
)
})
## HEATMAP
output$heatmap_selector <- renderUI({
req(data_internal$raw)
div(
list(
div(
style = "display: inline-block; width = '10%'",
br()
),
div(
style = "display: inline-block; width = '40%'",
title = "Select which categorical variable you wish to cross tabulate along the x axis in a heat map. Values must be discrete categories (i.e. not free text and not decimal)",
selectInput(
inputId = "heat_select_x",
label = "Select X variable",
choices = c("", eviatlas:::get_histogram_viable_columns(data_active())),
selected = ""
)
),
div(
style = "display: inline-block; width = '40%'",
title = "Select which categorical variable you wish to cross tabulate along the y axis in a heat map. Values must be discrete categories (i.e. not free text and not decimal)",
selectInput(
inputId = "heat_select_y",
label = "Select Y variable",
choices = c("", eviatlas:::get_histogram_viable_columns(data_active())),
selected = ""
)
)
)
)
})
gen_time_trend_plot <- reactive({
eviatlas:::GenTimeTrend(data_active(), input$select_timetrend_col)
})
gen_location_trend_plot <- reactive({
eviatlas:::GenLocationTrend(data_active(), input$select_loc_col)
})
output$plot1 <- renderPlot({
req(input$select_timetrend_col)
gen_time_trend_plot()
})
output$plot2 <- renderPlot({
req(input$select_loc_col)
gen_location_trend_plot()
})
output$save_plot_1 <- downloadHandler(
filename = "eviatlas1.png",
content = function(file) {
device <- function(..., width, height) {
grDevices::png(...,
width = width, height = height,
res = 300, units = "in"
)
}
ggplot2::ggsave(file, plot = gen_time_trend_plot(), device = device)
}
)
output$save_plot_2 <- downloadHandler(
filename = "eviatlas2.png",
content = function(file) {
device <- function(..., width, height) {
grDevices::png(...,
width = width, height = height,
res = 300, units = "in"
)
}
ggplot2::ggsave(file, plot = gen_location_trend_plot(), device = device)
}
)
gen_heatmap <- reactive({
eviatlas:::GenHeatMap(data_active(), c(input$heat_select_x, input$heat_select_y))
})
output$heatmap <- renderPlot({
req(input$heat_select_x)
req(input$heat_select_y)
gen_heatmap()
})
output$heat_x_axis <- renderPrint({
input$heat_select_x
})
output$heat_y_axis <- renderPrint({
input$heat_select_y
})
observeEvent(input$map_filter_select, {
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "heatmap_filtered_select",
value = as.logical(input$map_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "barplots_filtered_select",
value = as.logical(input$map_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "mapdatabase_filter_select",
value = as.logical(input$map_filter_select)
)
})
observeEvent(input$heatmap_filter_select, {
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "map_filtered_select",
value = as.logical(input$heatmap_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "barplots_filtered_select",
value = as.logical(input$heatmap_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "mapdatabase_filter_select",
value = as.logical(input$heatmap_filter_select)
)
})
observeEvent(input$barplots_filter_select, {
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "map_filtered_select",
value = as.logical(input$barplots_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "heatmap_filter_select",
value = as.logical(input$barplots_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "mapdatabase_filter_select",
value = as.logical(input$barplots_filter_select)
)
})
observeEvent(input$mapdatabase_filter_select, {
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "map_filtered_select",
value = as.logical(input$mapdatabase_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "heatmap_filter_select",
value = as.logical(input$mapdatabase_filter_select)
)
shinyWidgets::updateMaterialSwitch(
session = session, inputId = "barplots_filter_select",
value = as.logical(input$mapdatabase_filter_select)
)
})
output$save_heatmap <- downloadHandler(
filename = "eviatlasHeatmap.png",
content = function(file) {
device <- function(..., width, height) {
grDevices::png(...,
width = width, height = width,
res = 300, units = "in"
)
}
ggplot2::ggsave(file, plot = gen_heatmap(), device = device)
}
)
generate_systematic_map <- reactive({
# Generate basemap
if (input$sample_or_real == "shapefile") {
eviatlas:::sys_map_shapefile(data_active(), popups = popup_string())
} else {
eviatlas:::sys_map(data_active())
}
})
output$map <- leaflet::renderLeaflet({
generate_systematic_map() %>%
htmlwidgets::onRender(
"function(el, x) {
L.easyPrint({
sizeModes: ['Current', 'A4Landscape', 'A4Portrait'],
filename: 'EviAtlasMap',
exportOnly: true,
hideControlContainer: true
}).addTo(this);
}"
)
})
cluster_level <- reactive({
input$cluster_size_select
})
popup_string <- reactive({
popup_string <- ""
# TODO: Vectorize this
for (popup in input$map_popup_select) {
popup_string <- paste0(
popup_string, "<strong>", popup, "</strong>: ",
stringr::str_replace_all(
stringr::str_wrap(
data_active()[[popup]]
), stringr::coll("\n"), "<br/>"
), "<br/>"
)
}
popup_string
})
atlas_point_links <- reactive({
if (input$map_link_select != "") {
links_input <- sapply(data_active()[input$map_link_select], as.character)
links <- paste0(
"<strong><a target='_blank' rel='noopener noreferrer' href='",
links_input, "'>Link to paper</a></strong>"
)
} else {
links <- ""
}
links
})
cluster_options <- reactive({
dplyr::if_else(
input$map_cluster_select,
parse(text = paste0(
"leaflet::markerClusterOptions(freezeAtZoom = ",
input$cluster_size_select, ")"
)),
NULL
)
})
observe({
req(!is.null(input$atlas_color_by_select)) # could be anything in the evidence atlas pane
req(input$sample_or_real != "shapefile") # shapefiles are handled differently, so they have their own section
radiusby <- input$atlas_radius_select
lat_plotted <-
as.numeric(unlist(data_active() %>%
dplyr::select(input$map_lat_select)))
lng_plotted <-
as.numeric(unlist(data_active() %>%
dplyr::select(input$map_lng_select)))
if (input$atlas_color_by_select != "") {
color_user <- input$atlas_color_by_select
factpal <- leaflet::colorFactor(RColorBrewer::brewer.pal(9, "Set1"),
data_active()$color_user,
reverse = TRUE
)
colorby <- ~ factpal(data_active()[[color_user]])
if (length(unique(data_active()[, color_user])) < 9) {
leaflet::leafletProxy("map", data = data_active()) %>%
leaflet::addLegend(
title = stringr::str_to_title(stringr::str_replace_all(color_user, "\\.", " ")),
position = "topright",
pal = factpal,
values = data_active()[, color_user],
layerId = "color_by_legend",
group = "legend",
na.label = "None",
opacity = .8
)
}
else {
leaflet::leafletProxy("map") %>%
leaflet::removeControl("color_by_legend")
}
} else {
colorby <- "blue"
}
leaflet::leafletProxy("map", data = data_active()) %>%
leaflet::clearMarkers() %>%
leaflet::clearMarkerClusters() %>%
leaflet::addCircleMarkers(
lat = ~lat_plotted, lng = ~lng_plotted,
popup = ~ paste(popup_string(), atlas_point_links()),
popupOptions = leaflet::popupOptions(
maxWidth = 500,
maxHeight = 200
),
radius = ~ as.numeric(radiusby * 3),
color = colorby,
stroke = FALSE, fillOpacity = 0.7,
label = ~ lapply(popup_string(), shiny::HTML),
clusterOptions = eval(cluster_options())
)
})
observeEvent(input$map_title_select, {
leaflet::leafletProxy("map") %>%
leaflet::removeControl("atlas_title") %>%
leaflet::addControl(input$map_title_select,
position = "topleft",
className = "map-title",
layerId = "atlas_title"
)
})
observeEvent(input$map_basemap_select, {
leaflet::leafletProxy("map") %>%
leaflet::removeTiles("atlas_basemap") %>%
leaflet::addProviderTiles(input$map_basemap_select,
layerId = "atlas_basemap"
)
})
atlas_for_saving <- reactive({
# This is redundant to everything in the app, but the is best solution I could find
# for saving a map that's been heavily edited with leaflet::leafletProxy
if (input$sample_or_real == "shapefile") {
return(
eviatlas:::sys_map_shapefile(data_active(),
popups = popup_string()
) %>%
leaflet::setView(
lng = input$map_center$lng,
lat = input$map_center$lat,
zoom = input$map_zoom
) %>%
leaflet::addControl(
input$map_title_select,
position = "topleft",
className = "map-title",
layerId = "atlas_title"
) %>%
leaflet::addProviderTiles(input$map_basemap_select,
layerId = "atlas_basemap"
)
)
} # end shapefile
radiusby <- input$atlas_radius_select
lat_plotted <-
as.numeric(unlist(data_active() %>%
dplyr::select(input$map_lat_select)))
lng_plotted <-
as.numeric(unlist(data_active() %>%
dplyr::select(input$map_lng_select)))
if (input$atlas_color_by_select != "") {
legend <- TRUE
color_user <- input$atlas_color_by_select
factpal <- leaflet::colorFactor(RColorBrewer::brewer.pal(9, "Set1"),
data_active()$color_user,
reverse = TRUE
)
colorby <- ~ factpal(data_active()[[color_user]])
} else {
legend <- FALSE
colorby <- "blue"
color_user <- ""
}
# call the foundational Leaflet map
map_out <- generate_systematic_map() %>%
# store the view based on UI
leaflet::setView(
lng = input$map_center$lng,
lat = input$map_center$lat,
zoom = input$map_zoom
) %>%
leaflet::addControl(input$map_title_select,
position = "topleft",
className = "map-title",
layerId = "atlas_title"
) %>%
leaflet::addProviderTiles(input$map_basemap_select,
layerId = "atlas_basemap"
) %>%
leaflet::addCircleMarkers(
lat = ~lat_plotted, lng = ~lng_plotted,
popup = ~ paste(popup_string(), atlas_point_links()),
radius = ~ as.numeric(radiusby * 3),
color = colorby,
stroke = FALSE, fillOpacity = 0.7,
label = ~ popup_string() %>% lapply(shiny::HTML),
clusterOptions = eval(cluster_options())
)
if (legend) {
map_out %<>%
leaflet::addLegend(
title = stringr::str_to_title(stringr::str_replace_all(color_user, "\\.", " ")),
position = "topright",
pal = factpal,
values = data_active()[, color_user],
layerId = "color_by_legend",
group = "legend",
na.label = "None",
opacity = .8
)
}
map_out
})
output$savemap_interactive <- downloadHandler(
filename = paste0("eviAtlasMap", Sys.Date(), ".html"),
content = function(file) {
htmlwidgets::saveWidget(
widget = atlas_for_saving(),
file = file
)
}
)
output$savemap_pdf <- downloadHandler(
filename = paste0("eviAtlasMap", Sys.Date(), ".pdf"),
content = function(file) {
mapview::mapshot(
x = atlas_for_saving(),
file = file,
cliprect = "viewport",
selfcontained = FALSE
)
}
)
output$savemap_png <- downloadHandler(
filename = paste0("eviAtlasMap", Sys.Date(), ".png"),
content = function(file) {
mapview::mapshot(
x = atlas_for_saving(),
file = file,
cliprect = "viewport",
selfcontained = FALSE
)
}
)
outputOptions(output, "cluster_columns", suspendWhenHidden = FALSE)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.