-
-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow layering of basemaps and setting of z-indices (if possible with maplibre/mapbox gl js) #7
Comments
Thanks for the note! This is actually natively supported in Mapbox / Maplibre - I'll need to make a few edits to expose it. I'll work up an example to show how! |
Hi @walkerke, I'd be really keen to see an example here showing that it's possible to show a map with the polygon layer above the base tiles but have the place labels and road networks above the polygon layer. I've seen it looks possible with mapbox (links below) but I'm not familiar enough with it to implement it within my shiny app. https://stackoverflow.com/questions/42753217/mapbox-gl-js-display-map-labels-above-layer Thanks for your work on this package - I really look forward to being able to move my current shiny app (currently leaflet/leafgl) to using mapgl! |
This is now implemented! If you are using Mapbox's new Standard style, there is a Here's how it works: A regular map with data on top of everything (default behavior): library(tigris)
library(mapgl)
options(tigris_use_cache = TRUE)
dallas <- tracts("TX", "Dallas", cb = TRUE)
# Above labels (default)
mapboxgl(mapbox_style("streets")) |>
fit_bounds(dallas) |>
add_fill_layer(
id = "dallas",
source = dallas,
fill_color = "green",
fill_opacity = 0.5
) Below place labels, above road networks: # Below labels with `before_id`:
mapboxgl(mapbox_style("streets")) |>
fit_bounds(dallas) |>
add_fill_layer(
id = "dallas",
source = dallas,
fill_color = "green",
fill_opacity = 0.5,
before_id = "building-entrance"
) Below road networks as well: # Below roads as well:
mapboxgl(mapbox_style("streets")) |>
fit_bounds(dallas) |>
add_fill_layer(
id = "dallas",
source = dallas,
fill_color = "green",
fill_opacity = 0.5,
before_id = "tunnel-path"
) I'll leave this issue open for now as I don't have an options to do the labels toggle you described yet; this is possible in Shiny with |
Okay. These are awesome new features. But I'm trying to work out a fairly graceful way of rearranging layers, including both layers of the vector tile basemap and data that i add to the map, and am not sure there's a clear way to do so yet. I was playing with splicing apart the json that defines the base tiles, which would let me implement what I did in leaflet in the first example as directly as possible. That is: I plucked out layers from the json, separated the base map into roads, background, labels, etc. Then I was hoping to use It may be possible but just a little underdocumented right now, but my attempts to use I get how I can toggle visibility of layers, including portions of the basemap, with Repex to help illustrate:
I'm hoping for a way to do at least one of the following:
|
Good questions! Regarding your three points:
|
Hm. Okay. I wanna try (1) with local Json. i'd be interested in seeing a example doing something like this using the mapgl library... For the other two, amazing. I hope these may become |
I concur with a need for more control on layer ordering. I'm getting weird behavior in a dynamic mapping application. I have a fill layer, a potential circle layer, and potential additional line or fill layers. The circle layer always stays on top, no matter what else is done. The added fill and/or line layers go between the base fill layer and the circle layer when first called, but if I update the base fill layer, the added fill and/or line layers fall beneath it. Having just a |
@CIOData so in your ideal use-case, you would have your line layer always sitting above any added fill layer? I believe user-added circles are always plotted on top of user-added fills and lines by default in the JS libraries - this is a behavior I do like as I think users will typically not want their circles obscured by new fills. For the line layer, I'll have to think this through. A new |
Yes, I would have those additional geographic accents (mostly line layers, but one is a fill layer) above the base choropleth map at all times. In |
Checking in on these! In particular, move_layer feels like it could be a fine solution, but there seems to be no exported function |
library(shiny)
library(mapgl)
library(tigris)
library(sf)
library(dplyr)
options(tigris_use_cache = TRUE)
# Load data outside of server function
rds <- roads("TX", "Tarrant")
tr <- tracts("TX", "Tarrant", cb = TRUE)
# Create random points within the bounds of Tarrant County
set.seed(123)
pois <- st_sample(st_as_sfc(st_bbox(tr)), 100) %>%
st_sf() %>%
mutate(id = row_number())
layer_ids <- c("Census tracts", "Local roads", "Points of Interest")
ui <- fluidPage(
titlePanel("Move Layers Example with Before ID"),
sidebarLayout(
sidebarPanel(
selectInput("layer_to_move", "Layer to Move:", choices = layer_ids),
selectInput("before_layer", "Move to:", choices = c("Top" = "Top",
"Behind Census tracts" = "Census tracts",
"Behind Local roads" = "Local roads",
"Behind Points of Interest" = "Points of Interest")),
actionButton("move_layer", "Move Layer")
),
mainPanel(
maplibreOutput("map")
)
)
)
server <- function(input, output, session) {
output$map <- renderMaplibre({
maplibre() |>
fit_bounds(rds) |>
add_fill_layer(
id = "Census tracts",
source = tr,
fill_color = "purple",
fill_opacity = 0.6
) |>
add_line_layer(
id = "Local roads",
source = rds,
line_color = "pink"
) |>
add_circle_layer(
id = "Points of Interest",
source = pois,
circle_color = "yellow",
circle_radius = 5,
circle_stroke_width = 1,
circle_stroke_color = "black"
) |>
add_layers_control(collapsible = TRUE)
})
observeEvent(input$move_layer, {
layer_id <- input$layer_to_move
before_id <- if(input$before_layer == "Top") NULL else input$before_layer
maplibre_proxy("map") |>
move_layer(layer_id = layer_id, before_id = before_id)
})
}
shinyApp(ui, server) |
@CIOData this app does something similar to what you've requested. When a given fill layer is updated (by clearing one layer and adding a new one), library(shiny)
library(mapgl)
library(tigris)
library(sf)
library(dplyr)
options(tigris_use_cache = TRUE)
# Load data outside of server function
rds <- roads("TX", "Tarrant")
block_groups <- block_groups("TX", "Tarrant", cb = TRUE)
tracts <- tracts("TX", "Tarrant", cb = TRUE)
counties <- counties("TX", cb = TRUE) %>% filter(NAME == "Tarrant")
# Create random points within the bounds of Tarrant County
set.seed(123)
pois <- st_sample(st_as_sfc(st_bbox(tracts)), 100) %>%
st_sf() %>%
mutate(id = row_number())
ui <- fluidPage(
titlePanel("Census Geography Selector with Layer Ordering"),
sidebarLayout(
sidebarPanel(
selectInput("geography", "Select Census Geography:",
choices = c("Block Groups", "Tracts", "County"))
),
mainPanel(
maplibreOutput("map")
)
)
)
server <- function(input, output, session) {
output$map <- renderMaplibre({
maplibre() %>%
fit_bounds(rds) %>%
add_line_layer(
id = "roads",
source = rds,
line_color = "red",
line_width = 1
) %>%
add_circle_layer(
id = "pois",
source = pois,
circle_color = "yellow",
circle_radius = 5,
circle_stroke_width = 1,
circle_stroke_color = "black"
)
})
observeEvent(input$geography, {
geo_data <- switch(input$geography,
"Block Groups" = block_groups,
"Tracts" = tracts,
"County" = counties)
maplibre_proxy("map") %>%
clear_layer("fill_layer") %>%
add_fill_layer(
id = "fill_layer",
source = geo_data,
fill_color = "purple",
fill_outline_color = "black",
fill_opacity = 0.6
) %>%
move_layer("roads") %>%
move_layer("pois")
})
}
shinyApp(ui, server) |
Hi!
I'm making plans to switch from leaflet to either deck.gl or maplibre gl js for a lot of my interactive mapping / shiny development work.
Using R/leaflet, I made a practice of initializing maps with different layers: one w/o labels and another with labels separate, and I put the data between them by setting z-indices.
For example, in leaflet, I had:
And then I could also add map panes for the data with a z-index between the NoLabel layer and the OnlyLabel layer, and give user ability to toggle labels on/off, and have labels appear above the data by default.
I don't see a way to layer provider tiles or basemaps in any R interface to maplibre or other gl js packages, like mapbox or deck.gl. If it's possible, i'd love to see features to layer basemaps and set z-indices using
mapgl
!!!!Thank you! I use many of your packages quite frequently.
The text was updated successfully, but these errors were encountered: