SymbolixAU / mapdeck

R interface to Deck.gl and Mapbox

Home Page:https://symbolixau.github.io/mapdeck/articles/mapdeck.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`repeat_view = TRUE` does not work within Shiny

yvanrichard opened this issue · comments

Describe the bug
repeat_view = TRUE leads to a frozen view within Shiny with the browser console returning plenty of Uncaught TypeError: cyclic object value

To Reproduce

library(data.table)
library(sf)
library(mapdeck)
library(shiny)

key <- "***"
set_token(key)

n <- 1000L; x0 <- -179; y0 <- -42
pts <- data.table(x = rnorm(n, x0, 2), y = rnorm(n, y0, 2), indiv = sample(LETTERS, n, repl=T))
pts <- st_as_sf(pts, coords = c('x', 'y'), crs = 4326, remove = F)

shinyApp(
    ui = fluidPage(mapdeckOutput('map', height='800px')),
    server = function(input, output) {
        output$map <-renderMapdeck({
            mapdeck(location = c(x0, y0) , zoom = 3 ,
                    style = 'mapbox://styles/mapbox/dark-v10' , show_view_state = TRUE ,
                    repeat_view = TRUE) %>%
                add_scatterplot(data = pts , fill_colour = "indiv" , fill_opacity = 0.5 ,
                                stroke_opacity = 0 , radius_min_pixels = 2 ,
                                palette = 'rainbow_hcl')
        })
    }
)

Expected behaviour
Features on both sides of the international date line should get displayed with repeat_view=TRUE. This option is essential when dealing with features around the date line, as otherwise half of them disappear when dragging the view left or right.

Versions

sessionInfo()
R version 4.1.2 (2021-11-01)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0

locale:
 [1] LC_CTYPE=en_NZ.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_NZ.UTF-8        LC_COLLATE=en_NZ.UTF-8    
 [5] LC_MONETARY=en_NZ.UTF-8    LC_MESSAGES=en_NZ.UTF-8   
 [7] LC_PAPER=en_NZ.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_NZ.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] shiny_1.7.1       mapdeck_0.3.40003 sf_1.0-4          data.table_1.14.2

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.7         jquerylib_0.1.4    bslib_0.3.1        pillar_1.6.4      
 [5] compiler_4.1.2     later_1.3.0        class_7.3-19       tools_4.1.2       
 [9] digest_0.6.29      jsonlite_1.7.2     lifecycle_1.0.1    tibble_3.1.6      
[13] pkgconfig_2.0.3    rlang_0.4.12       DBI_1.1.1          yaml_2.2.1        
[17] fastmap_1.1.0      e1071_1.7-9        dplyr_1.0.7        sass_0.4.0        
[21] generics_0.1.1     vctrs_0.3.8        htmlwidgets_1.5.4  classInt_0.4-3    
[25] grid_4.1.2         tidyselect_1.1.1   glue_1.5.1         R6_2.5.1          
[29] jsonify_1.2.1      fansi_0.5.0        purrr_0.3.4        magrittr_2.0.1    
[33] promises_1.2.0.1   ellipsis_0.3.2     htmltools_0.5.2    units_0.7-2       
[37] assertthat_0.2.1   xtable_1.8-4       mime_0.12          httpuv_1.6.3      
[41] utf8_1.2.2         KernSmooth_2.23-20 proxy_0.4-26       cachem_1.0.6      
[45] crayon_1.4.2      
commented

Thanks for the report; yes I can reproduce this also. But it's strange it only happens in shiny, and not a standard plot.

It is strange, indeed. I can't tell you why, unfortunately.

FYI, it works when using rdeck, but I'd like to use mapdeck as your trip layer is better.

library(data.table)
library(sf)
library(rdeck)
library(shiny)

options(rdeck.mapbox_access_token = "***")

n <- 1000L; x0 <- -179; y0 <- -42
pts <- data.table(x = rnorm(n, x0, 2), y = rnorm(n, y0, 2), indiv = sample(LETTERS, n, repl=T))
pts <- st_as_sf(pts, coords = c('x', 'y'), crs = 4326, remove = F)

shinyApp(
    ui = fluidPage(rdeckOutput('map', height='800px')),
    server = function(input, output) {
        output$map <- renderRdeck({
            rdeck(initial_view_state = view_state(center = c(x0, y0) , zoom = 3),
                  map_style = 'mapbox://styles/mapbox/dark-v10'
                  ) %>%
                add_scatterplot_layer(data = pts ,
                                      get_fill_color = scale_color_category(
                                          col = indiv,
                                          palette = colorRampPalette(colors = get_palette('rainbow_hcl', F))(length(unique(pts$indiv)))
                                      ) , opacity = 0.5,
                                      radius_min_pixels = 2)
        })
    }
)
commented

I've narrowed it down and the error is coming from the drag events (which are only available in a Shiny app, hence only getting the error there).

I'll keep looking for a solution

commented

I really have no idea what changed in either {shiny} or deck.gl to cause the circular reference, but I've followed the solution here and it seems to work.

You can test it now if you want using remotes::install_github("SymbolixAU/mapdeck", ref = "issue349")

That sounds great, thank you!

Unfortunately I get this error when trying to install the new version:

> remotes::install_github("SymbolixAU/mapdeck", ref = "issue349")
Downloading GitHub repo SymbolixAU/mapdeck@issue349
Error: Failed to install 'mapdeck' from GitHub:
  Missing commas separating Remotes: 'dcooley/geometries
    dcooley/sfheaders
    SymbolixAU/geojsonsf
    SymbolixAU/spatialwidget'
commented

try now.

Brilliant, working now! Thank you so much!

commented

Notes / Tests:

  • is this only happening when repeate_view = TRUE
  • Is it safe / correct to Stringify the info object before Shiny.onInputChnage()
    • is the object returned to R correct

No, don't stringify; use a function in stead, something like

function removeCircular(obj) {
const seen = new WeakSet();
const recurse = obj => {
	seen.add(obj,true);
	for( let [k, v] of Object.entries(obj)) {
	  if( typeof v === "object" && v !== null) {
		  if(seen.has(v)) delete obj[k];
		  else recurse(v);
	  } else {
		  continue;
	  }
	}
}
recurse(obj);
}