I'm trying to build a Shiny app containing a leaflet map showing movement paths, that can be bidirectionally filtered using two other columns in the dataset which contains the geometry data.
To do so, I'm trying to use selectizeGroupUI (shinyWidgets package), which allows bidirectional/mutually dependent filtering.
However, when I run the code I get the following error:
"Warning: Error in polygonData.default: Don't know how to get path data from object of class data.frame"
I have a feeling that this is because mapping path (linestring) data in a leaflet map requires the underlying dataset to be an sf object, whereas selectizeGroupUI converts the sf object into a data.table(?), hence the error message.
This is supported by the fact that when I convert the dataset from sf object to data.table and try to plot the paths as individual A and B coordinates (without a connecting line), the whole thing works perfectly.
Any idea whether there exists a work around?
Any help would be hugely appreciated, please and thanks!
** A reprex: **
library(tidyverse)
library(sf)
library(shiny)
library(shinyWidgets)
# generate the table with geometry data
geo_data <- structure(list(idx = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
start_lat = c(33.40693,33.64672, 33.57127, 33.42848, 33.54936, 33.53418, 33.60399, 33.49554,33.5056, 33.61696),
start_long = c(-112.0298, -111.9255, -112.049,-112.0998, -112.0912, -112.0911, -111.9273, -111.9687, -112.0563, -111.9866),
end_lat = c(33.40687, 33.64776, 33.57125, 33.42853,33.54893, 33.53488, 33.60401, 33.49647, 33.5056, 33.61654),
end_long = c(-112.0343,-111.9303, -112.0481, -112.0993, -112.0912, -112.0911, -111.931,-111.9711, -112.0541, -111.986)),
row.names = c(NA, -10L), spec = structure(list(cols = list(idx = structure(list(), class = c("collector_double","collector")),
start_lat = structure(list(), class = c("collector_double", "collector")),
start_long = structure(list(), class = c("collector_double", "collector")),
end_lat = structure(list(), class = c("collector_double", "collector")),
end_long = structure(list(), class = c("collector_double","collector"))),
default = structure(list(), class = c("collector_guess","collector")), delim = ","),
class = "col_spec"),class = c("data.table","data.frame"))
geo_data<- setDT(geo_data)
geo_data <- geo_data[
, {
geometry <- sf::st_linestring(x = matrix(c(start_lat, start_long, end_long, end_long), ncol = 2, byrow = T))
geometry <- sf::st_sfc(geometry)
geometry <- sf::st_sf(geometry = geometry)
}
, by = idx
]
# generate the table with columns to filter the geometry data, join with geometry data and convert to sf
table <- structure(list(idx = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
column1 = c("A", "A", "A", "B", "B", "B", "C", "C", "C", "C"),
column2 = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), row.names = c(NA, -10L),
class = c("tbl_df","tbl", "data.frame")) %>%
left_join(x = ., y = geo_data, by = "idx", keep = FALSE)
sf <- sf::st_as_sf(table)
# Shiny
ui <- fluidPage(
fluidRow(
column(
width = 10, offset = 1,
tags$h3("Filter data with selectize group"),
panel(
selectizeGroupUI(
id = "my-filters",
params = list(
column1 = list(inputId = "column1", title = "column1:"),
column2 = list(inputId = "column2", title = "column2:")
)
), status = "primary"
),
leafletOutput(outputId = "map")
)
)
)
server <- function(input, output, session) {
res_mod <- callModule(
module = selectizeGroupServer,
id = "my-filters",
data = sf,
vars = c("column1", "column2"))
output$map <- renderLeaflet({
leaflet() %>%
addPolylines(data = res_mod())
})
}
shinyApp(ui, server)