Open James-G-Hill opened 7 months ago
I still have to migrate the tmapProxy
/shiny integration in v4.
Your input is welcome, so thanks for that. However, I don't understand exactly what you mean yet. Are you looking for something like tmap_leaflet(tm, layers = c(1,3,5))
? If so, why don't you just create a tmap with those layers?
Could you perhaps share a minimal use case / example, of something you want to achieve?
shiny functions implemented for v4 :-) Please check if you have time @Nowosad @nickbearman @James-G-Hill @olivroy
If anything is missing or you have feature requests, please let me know
I've tried to modify the app from geocompr (https://github.com/geocompx/geocompr/blob/main/apps/CycleHireApp/app.R) to use the shiny features of tmap and it seems to be working fine (except the issue mentioned at https://github.com/r-tmap/tmap/issues/904):
library(shiny)
library(sf)
library(spData)
library(spDataLarge)
library(leaflet)
library(tmap)
library(units)
library(dplyr)
library(stringr)
tmap_mode("view")
# Based on input coordinates finding the nearest bicycle points
ui = fluidPage(
# Application title
titlePanel("CycleHireApp"),
# Numeric Input from User
bootstrapPage(
div(style = "display:inline-block",
numericInput("x", ("Enter x-coordinate of your location"), value = 51.5, step = 0.001)),
div(style = "display:inline-block",
numericInput("y", ("Enter y-coordinate of your location"), value = -0.1, step = 0.001)),
div(style = "display:inline-block",
numericInput("num", "How many cycles are you looking for?", value = 1, step = 1))
),
# Where leaflet map will be rendered
fluidRow(
tmapOutput("map", height = 300)
)
)
server = function(input, output, session) {
#Centering the leaflet map onto London - use if needed
map_centre = matrix(c(-0.2574846, 51.4948089), nrow = 1, ncol = 2,
dimnames = list(c("r1"), c("X", "Y")))
#Based on input coords calculating top 5 closest stations to be displayed
#Making reactive object of input location coordinates
input_pt = reactive({
matrix(c(input$y, input$x), nrow = 1, ncol = 2,
dimnames = list(c("r1"), c("X", "Y")))
})
input_pt_sf = reactive({
st_as_sf(as.data.frame(input_pt()), coords = c("X", "Y"), crs = "EPSG:4326")
})
#Rendering the output map showing the input coordinates
output$map = renderTmap({
tm_shape() +
tm_basemap() +
tm_view(set.view = c(input_pt()[, "X"], input_pt()[, "Y"], 15))
})
#Finding the top distance between input coordinates and all other cycle stations, then sorting them.
data = reactive({
cycle_hire$dist = st_point(input_pt()) |>
st_sfc() |>
st_set_crs("EPSG:4326") |>
st_distance(cycle_hire$geometry) |>
t() |>
set_units("km")
cycle_hire[order(cycle_hire$dist), ]
})
#Filtering the distance data from above to show top 5 closest stations meeting requirement of # of bikes needed
filteredData = reactive({
data() |>
filter(nbikes >= input$num) |>
head(5) |>
mutate(popup = str_c(str_c("Station:", name, sep = " "),
str_c("Available bikes:", nbikes, sep = " "), sep = "<br/>"))
})
#Making changes to the output leaflet map reflecting the cycle stations found above
icons = tmap_icons(system.file("img/airplane.png", package = "tmap"))
observe({
proxy = tmapProxy("map", session, x = {
tm_remove_layer(402) +
tm_shape(input_pt_sf()) +
tm_markers(size = 4, zindex = 402) +
tm_remove_layer(401) +
tm_shape(filteredData()) +
tm_symbols(shape = icons, zindex = 401)
})
})
}
# Run the application
shinyApp(ui = ui, server = server)
@mtennekes Sorry, I have been away from this for a long time; when I look at my maps again soon I'll see if what you've done has fixed what I was trying to do.
I was working on integrating
tmap
andleaflet
this week in a package so that I can usetmap
to create a static map then convert toleaflet
when necessary & add any extra interactive elements on top. This is achievable withtmap_leaflet
(although there were some annoyances such as the default converted Leaflet always showing 3 basemaps and then having to define the 1 basemap I want separately withtmap_options(basemaps)
.I thought it would be great to define any layers that could be static in
tmap
and then convert toleaflet
when I need to. This would reduce duplication of effort acrosstmap
andleaflet
.However, one problem I came across is that I want to be able to use the layers I defined in leaflet with a proxy map. If I convert with
tmap_leaflet
I get a full leaflet map, not layers I can then add to a proxy map.Is there any way to convert individual layers from
tmap
toleaflet
format? Or extract layers from the output oftmap_leaflet
and add them to anotherleaflet
map.I'm guessing this is not possible to do with the current version of
tmap
but maybe such an ability could be added in future?Ultimately, I'd like to be able to define a
tm_lines
then convert to leaflet and attach it so that the lines and legend appear correctly on the leaflet map.