mapdeck icon indicating copy to clipboard operation
mapdeck copied to clipboard

Passing additional options to mapdeck layer in recentered maps

Open davidruvolo51 opened this issue 7 years ago • 4 comments

Passing additional options to mapdeck layer in recentered maps

There are some situations where maps are centered to a fixed location (e.g., city, point of interest, etc.). In the example below, I've pulled a list world airport locations and generated arcs (random arcs) from a fixed point of origin (Sydney International Airport). Destination points in North and South America were adjusted so they are plotted to the right of the home location (Sydney).

The location of the base map can be set using the argument location. However, since the location of the destination points extend into the next map tile this causes issues with the navigating the map. Any movement past the international date line causes all data points (arcs, points, text, etc.) to shift to the right by one tile. Using options such as max bounds and location are useful in these circumstances for re-positioning the base layer and fixing the map dimensions. The mapbox documentation states has the following options available: maxBounds and renderWorldCopies. However there does not seem to be method for passing these arguments to the map layer in R (i.e., mapdeck().

I've attempted to append the map with these arguments using the htmltools and htmlwidgets packages using htmltools::browsable(..., tags$script(...)) and htmlwidgets::onStaticRenderComplete(...,..some js code...), but did not have much luck as these arguments had no effect on a post-rendered map (see last example).

Is there another method for passing these arguments to the mapdeck function? If not, is it possible to expaned the mapdeck function to allow for these options to be passed to the map layer?

Example

Build sample data

# pkgs 
# install.packages("tidyverse")
# devtools::install_github("SymbolixAU/googlePolylines")
# devtools::install_github("SymbolixAU/mapdeck")

library(tidyverse)

# build dataset (using sample data from openflights.org)
# and add column names as listed here: https://openflights.org/data.html
url <- "https://raw.githubusercontent.com/jpatokal/openflights/master/data/airports-extended.dat"
raw <- read.table(url,sep = ",", stringsAsFactors = FALSE)


mapDF <- raw[,c(1:4,7,8)]   # select columns of interest

# adding "dest" as a prefix for lat and long colnames. 
colnames(mapDF) <- c("airportID", "name","city","country","dest_lat","dest_long")



# define center point and add to dataset: Sydney Kingsford Smith International Airport
originDF <- mapDF %>% filter(name == "Sydney Kingsford Smith International Airport")
mapDF$origin <- "Sydney International Airport"
mapDF$origin_lat <- originDF$dest_lat
mapDF$origin_lng <- originDF$dest_long


# reposition longitude values as the origin of the map is Sydney International Airport
center <- 151.177
mapDF$dest_long_fixed<- ifelse(mapDF$dest_long < center - 180, 
                               mapDF$dest_long + 360,
                               mapDF$dest_long)


# grab a sample of rows for better performance
plotDF <- mapDF[sample(NROW(mapDF),1000),]

Build map

Note: update the access token with yours. I am also saving the map as a standalone file.

# pkgs
library(mapdeck)

key = "your_token_goes_here"

# build map
map <- mapdeck(token = key, 
               style = "mapbox://styles/mapbox/dark-v9", pitch = 45,
               location = c(151.177, -33.9461), zoom = 1,
               height = "100%") %>%
  
  # plot 1000 arcs
  add_arc(data = plotDF,
          origin = c("origin_lng","origin_lat"),
          destination = c("dest_long_fixed","dest_lat"),
          stroke_from = "#FFC8FB",
          stroke_to = "#FFC8FB",
          stroke_from_opacity = 100,
          stroke_to_opacity = 200,
          stroke_width = 2,
          layer_id = "arc_layer") %>%
  
  # plot all points
  add_scatterplot(data= mapDF, 
                  lon = "dest_long_fixed",
                  lat = "dest_lat",
                  radius = 10000,
                  fill_colour = "#ffffff")

# save as standalone file
save_html(map,file = "world_flight_paths.html",background = "#000000")

Example passing additional js code to the map

My thinking on this was to

  1. Wrap the map in a div in order to target the map object,
  2. Replace the htmlwidget ids with static ids, and
  3. Pass options to the map using the new id
mapOut <- tagList(
  tags$div(id="mapbox",
    style="width:100vw; height:100vh;background-color: black;padding: 0;margin:0;",
    map,
  tags$script("
    // manually set htmlwidget ids with static ids
    var widget = document.getElementById('mapbox');
    var wDivs = widget.querySelector('div');
    wDivs.id = 'map';

    // manually update the script with corresponding id
    var scripts = document.querySelectorAll('script');
    scripts[6].dataset.for = 'map';

    // set access token
    mapboxgl.accessToken =' replace with your token'

    // set options
    var map = new mapboxgl.Map({
      container: 'map',
      style: 'mapbox://styles/mapbox/dark-v9',
      maxBounds: [ [-180,85], [180,85] ],
      center: [151.2073, -33.86785 ],
      zoom: 1,
      pitch: 40,
      renderWorldCopies: false
    });")
  )
)

# save as standalone file
save_html(map,file = "world_flight_paths.html",background = "#000000")

davidruvolo51 avatar Sep 05 '18 01:09 davidruvolo51

@davidruvolo51 thanks for the suggestion.

At first glance this looks possible. I'll dive deeper into it in a day or so.

SymbolixAU avatar Sep 05 '18 02:09 SymbolixAU

I haven't forgotten about this, but have prioritised other libraries. I'm working on this now.

SymbolixAU avatar Jan 11 '19 01:01 SymbolixAU

This will be moved to mapbox

dcooley avatar Jul 31 '19 10:07 dcooley

This is very exciting! I look forward to trying it out.

davidruvolo51 avatar Aug 20 '19 10:08 davidruvolo51