Coder Social home page Coder Social logo

crazycapivara / mapboxer Goto Github PK

View Code? Open in Web Editor NEW
50.0 2.0 8.0 2.54 MB

An R Interface to Mapbox GL JS

Home Page: https://crazycapivara.github.io/mapboxer/

License: Other

R 70.08% Shell 0.21% HTML 0.91% JavaScript 27.37% CSS 1.43%
r mapbox-gl-js webgl htmlwidgets spatial

mapboxer's Introduction

mapboxer: An R Interface to Mapbox GL JS

CRAN status github_status_badge Travis-CI Build Status Project Status: Active – The project has reached a stable, usable state and is being actively developed.

mapboxer makes Mapbox GL JS, an open source JavaScript library that uses WebGL to render interactive maps, available within R via the htmlwidgets package.

persons-in-manhatten

Note

mapboxer provides bindings to v1.x.x of Mapbox GL JS, which is under the 3-Clause BSD license. See also breaking changes in Mapbox GL JS v2.0.0.

Installation

Install the release version from CRAN with:

install.packages("mapboxer")

Install the development version from GitHub with:

# install.packages("remotes")
remotes::install_github("crazycapivara/mapboxer")

Usage

library(mapboxer)

map <- motor_vehicle_collisions_nyc %>%
  dplyr::mutate(
    color = ifelse(injured == 0, "yellow", "red")
  ) %>%
  as_mapbox_source() %>%
  mapboxer(
    center = c(-73.9165, 40.7114),
    zoom = 10
  ) %>%
  add_navigation_control() %>%
  add_circle_layer(
    circle_color = c("get", "color"),
    circle_blur = 1,
    circle_stroke_color = "red",
    circle_stroke_width = 1,
    popup = "<p>{{date}} {{time}}</p><p>Number of persons injured: {{injured}}</p>"
  )

if (interactive()) map

By default mapboxer uses Carto vector styles as basemaps. It is also possible to use raster tiles or a background color.

If you want to use styles from Mapbox it is recommended that you store your API token in an environment vatiable called MAPBOX_API_TOKEN.

Documentation

Development

All JavaScript code of mapboxer is located in javascript/src.

Install dependencies and build the library with:

npm install
npm run build

The module is written to inst/htmlwidgets.

Spin up the dev server with:

npm run start

mapboxer's People

Contributors

crazycapivara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

mapboxer's Issues

map.loaded()

For Shiny updates map.on("load" => ...) causes problems. Therefore, we need to do something like

if (map.loaded()) {
  // call function
} else {
  map.on("load", () => {
  // call function
  });
} 

Support deck.gl layers

This feature should go to a plugin package in the future.
Just test it with an external link to the deck.gl js lib

geolocate

Hello
is it possible to use geolocateControl of mapbox?

render mapboxer on shiny

Hello everyone, i have a problem to render a filtered mapboxer on shiny. I get the error Problem withmutate()columncolor. e[34mℹe[39m color = pal(pop_est). e[31mxe[39m unused argument (pop_est) and i don't now why.

Any ideas or suggestions?
Thanks for reading me
The code is the following:

data("World")

ui <- fluidPage(
  
  selectInput("var","escoge un continente",
              choices = list("Asia" = "Asia",
                             "Africa" = "Africa",
                             "Europa" = "Europe",
                             "America" = "North America")       
  ),
  mapboxerOutput("map")
  
)

server <- function(input, output){
  
  dato <- reactive({
    
    World |> 
      filter(continent == input$var)
  
  })
  
  pal <- reactive({
    scales::col_quantile("Greys",  dato()$pop_est)
  })
  
  bbox <- reactive({
    unname(sf::st_bbox(dato() ))
  })
  
  output$map <- renderMapboxer({
    
    dato() %>%
      dplyr::mutate(color = pal(pop_est)) %>%
      as_mapbox_source() %>%
      mapboxer(bounds = bbox(), pitch = 25, zoom = 10) %>%
      add_navigation_control() %>%
      add_fill_layer(
        fill_color = c("get", "color"),
        fill_opacity = 0.5,
        fill_outline_color = "white",
        popup = "Población estimada: {{pop_est}}"
      )
    
  })
  
  
  
}



shinyApp(ui, server)

Mapboxer extras

Hello, I would like to manually draw a polygon on a map. I've been searching for such an option in mapboxer but couldn't find. I would also like to manually draw an area on a map which selects points (coordinates) and e.g. calculate some statistics for the points instantly. In general, I'd like to use options available in package leaflet.extras. Please take a look here for working example: https://gist.github.com/mndrake/aee9a0f5c53018860e46766d0131cd29

My question is if it's possible to mix mapboxer with leaflet.extras to use all options available there? Or maybe mapboxer can't be mixed in any way with leaflet functions?

mapboxer_proxy doesn't work with modules

Hello,
I have encountered an issue with implementing mapboxer_proxy in a modularized app. Simply, after clicking a button I want points to be displayed on a map. Everything works smoothly in a non-modularized app but when I use modules then it doesn't work. Interestingly, leafletProxy works fine even in a modularized app, so I really don't know where the problem lies. Maybe there's some issue with mapboxer_proxy itself? Or maybe I make a mistake somewhere.

Here is a link to StackOverflow where I described my issue + added working app.R code (modularized and non-modularized): https://stackoverflow.com/questions/66509929/why-mapboxer-proxy-is-not-working-in-a-modularized-shiny-app

I also tried with set_data instead of add_circle_layer but it doesn't solve the problem. Could you please advise me on that issue?

layer examples

  • Polygon
  • Line
  • Text
  • Points / Circles
  • Markers
  • Icons / Symbols

Add legend control to main branch?

Hi there! Thanks for this great package - super useful and easy to use!

I was looking into adding a legend to a map and noticed you have a PR merged for this, #53, but it's only been merged into the develop branch. Just curious if you had plans to integrate this into the main branch or if there's some reason it's been left as a development feature.

Thanks!

Control over layers/groups

Hi,

I'm somehow referring to issue #62. I would like to cover 2 issues here:

  • layers control
  • groups

As for the first issue - I would like to hide/show points on the map upon clicking on the button (in short - toggle points on the map). I'm wondering how I could do it using mapboxer since I can't get to layer's properties like visibility. What I can only do, I guess, is setting visibility using set_layout_properties e.g. set_layout_property(ns("map"), layer_id="points", property="visibility", value="visible"). However, I don't know how to first get to the layer's properties (something what's possible in mapbox's function getLayoutProperty). Please take a look at this example from mapbox site:
https://docs.mapbox.com/mapbox-gl-js/example/toggle-layers/
where visibility is get/set using getLayoutProperty/setLayoutProperty.

Or maybe there's other way to do it, without getting and setting visibility from a layer. Below is my workable example from #62, where I added some dummy code (in observeEvent) showing how I would 'toggle' points on the map (I have only one button in this example but in my app I have 3 buttons and want to add some logic to observe event, e.g if points 'xyz' are visible one the map then show points 'kkk' etc.).

Another issue is groups. Is it possible to make groups using mapboxer just like it's possible in leaflet? In leaflet I can use function addLayersControl which manage groups quite easily (also enables toggling points on a map). Please take a look at this example where it's shown clearly: https://rstudio.github.io/leaflet/showhide.html

And here is my workable example with commented dummy code:

library(shiny)
library(mapboxer)
library(dplyr)
library(sf)

Sys.setenv(MAPBOX_API_TOKEN =    "pk.eyJ1IjoiaHdsIiwiYSI6ImNramJxY2YxcDV2YXoyeW40YXlvbmUyazQifQ.7HBEvMyrAnVpkKO7MNH7ww")

moduleServer <- function(id, module) {
callModule(module, id)
}

# UI 
mod_btn_UI <- function(id) {

ns <- NS(id)
tagList(
    actionButton(ns("btn"), "Click me!"),
    mapboxerOutput(ns("map"))
    #leafletOutput(ns("map"), width = "100%")
)
}

# Server 
mod_btn_server <- function(id){
moduleServer(id, function(input, output, session) {
    
  ns <- NS(id)
  
    coords <- quakes %>%
        sf::st_as_sf(coords = c("long","lat"), crs = 4326)
         
    output$map <- mapboxer::renderMapboxer({
        mapboxer::mapboxer(
            style = mapboxer::basemaps$Mapbox$light_v10,
            center = c(174.387636,-33.543557),
            logoPosition = "bottom-left",
            pitch = 5,
            padding = 0,
            zoom = 3)
    })
    
    # visibility = mapboxer::get_layout_property(ns(map),layer_id="xyz",'visibility')

    observeEvent(input$btn, {
      # if(visibility == "visible") {
      # mapboxer::set_layout_property(ns("map"),"xyz",'visibility',"none")
      # }
      # else {
        mapboxer::mapboxer_proxy(ns("map")) %>%
            mapboxer::add_circle_layer(
                id = "xyz",
                source = mapboxer::as_mapbox_source(coords),
                circle_color = "#952444",
                circle_opacity = 0.7,
                circle_radius = 6
            ) %>%
            mapboxer::update_mapboxer()
      # }
    })
                   
})
}

# App 

ui <- fluidPage(    
tagList(
    mod_btn_UI("test-btn"))
)

server <- function(input, output, session) {
mod_btn_server("test-btn")    
}

shinyApp(ui = ui, server = server)

set_style for mapboxer_proxy

At the moment set_style only sets the initial style, but it should wor for mapboxer_proxy objects as well:

set_style.mapboxer_proxy <- function(...)

Add map_options param to mapboxer object

Add function to define map options:

map_options <- function(center = NULL, bounds = NULL, ...) {
  list(center, bounds, ...)
}

And use it as input for mapboxer()

Filter on multiple

Hi,
I've tried for a while to figure out the syntax for filtering on multiple string-values in mapboxer. The syntax in mapboxer/mapbox is very unfamiliar to me (strictly an R-user with background as a biologist). I am sorry if this is a stupid question to post, but I'm really stuck ...

Example:

require(tidyverse)
require(mapboxer)

#### Show "all" data (ex 1)
motor_vehicle_collisions_nyc %>%  
  mutate(brand = rep_len(c("Aissan", "Besla", "Coyota", "Dolvo"), 
                         length.out = dim(.)[1])) %>%
  mutate(color = rep_len(c("blue", "green", "red", "yellow"), 
                         length.out = dim(.)[1])) %>% 
  dplyr::filter(injured > 1) %>%
  as_mapbox_source() %>%
  mapboxer(
    center = c(-73.9165, 40.7114),
    zoom = 9
  ) %>%
  add_circle_layer(circle_color = c("get", "color"))

#### Filter on one brand (ex 2)
motor_vehicle_collisions_nyc %>%  
  mutate(brand = rep_len(c("Aissan", "Besla", "Coyota", "Dolvo"), 
                         length.out = dim(.)[1])) %>%
  mutate(color = rep_len(c("blue", "green", "red", "yellow"), 
                         length.out = dim(.)[1])) %>% 
  dplyr::filter(injured > 1) %>%
  as_mapbox_source() %>%
  mapboxer(
    center = c(-73.9165, 40.7114),
    zoom = 9
  ) %>%
  add_circle_layer(circle_color = c("get", "color"),
                   filter = list("==", "brand", "Besla"))

#### To filter on multiple brands I could of course do (ex 3)
motor_vehicle_collisions_nyc %>%  
  mutate(brand = rep_len(c("Aissan", "Besla", "Coyota", "Dolvo"), 
                         length.out = dim(.)[1])) %>%
  mutate(color = rep_len(c("blue", "green", "red", "yellow"), 
                         length.out = dim(.)[1])) %>% 
  dplyr::filter(brand %in% c("Aissan", "Besla")) %>% 
  dplyr::filter(injured > 1) %>%
  as_mapbox_source() %>%
  mapboxer(
    center = c(-73.9165, 40.7114),
    zoom = 9
  ) %>%
  add_circle_layer(circle_color = c("get", "color"))

But, if I need to filter on multiple brands from an actual mapbox source, the last example (ex 3) is not an option. I would like to know how to specify that in ex 2. What should the syntax in the filter look like to include more than one brand? (I've tried stuff from the mapbox expressions documentation, but I don't think I've got the syntax right, and there is no error message telling me what is wrong, so I'm completely lost ...)
Hope you can point me in the right direction.
Best,
Guri

slider control

  • add a custom control for sliders that sets the filter of a layer (and layer props?)
  • slider groups to set multiple filters

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.