SymbolixAU / mapdeck

R interface to Deck.gl and Mapbox
https://symbolixau.github.io/mapdeck/articles/mapdeck.html
362 stars 40 forks source link

Discrepancy between point ID and indexing #352

Open bdbmax opened 2 years ago

bdbmax commented 2 years ago

Describe the bug Within shiny, when a point is clicked on a scatterplot, it retrieves the wrong id supplied through add_scatterplot. It seems it is retrieving the row number -1.

To Reproduce

library(mapdeck)
library(shiny)

# Retrieving df used in add_scatterplot examples
df <- read.csv(paste0(
  'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/',
  'examples/3d-heatmap/heatmap-data.csv'
))
df <- df[ !is.na(df$lng), ]
df <- cbind(df, ID = 1:nrow(df))
# df <- cbind(df, ID = "a"): the tooltip shows the "a" but the id retrieved is the row number -1.
# df <- cbind(df, ID = 0:(nrow(df)-1)):  has no discrepency between the ID and the point clicked on.

ui <- fluidPage(
  mapdeckOutput("map"),
  htmlOutput("selection")
)

server <- function(input, output, session) {
  # Map
  output$map <- renderMapdeck(mapdeck() |> 
                                add_scatterplot(
                                  data = df,
                                  radius = 500,
                                  tooltip = "ID",
                                  id = "ID"
                                ))

  # Selection
  select_id <- eventReactive(input$map_scatterplot_click, {
    jsonlite::fromJSON(input$map_scatterplot_click)$index
  })

  output$selection <- renderText(paste("Selected output: ", select_id()))

}

shinyApp(ui = ui, server = server)

Expected behaviour That the jsonlite::fromJSON(input$map_scatterplot_click)$index returns the supplied id (in add_scatterplot) of the point clicked on.

Screenshots image

Versions 0.3.4

dcooley commented 2 years ago

Technically this is the intended behaviour as the index is used/returned in the onClick functions from here

var eventInfo = {
    index: info.index,
    color: info.color,
    object: info.object,
    layerId: info.layer_id,
    lat: info.coordinate[1], // deck.gl 8.4 - https://deck.gl/docs/upgrade-guide#upgrading-from-deckgl-v83-to-v84
    lon: info.coordinate[0]
  };

  eventInfo = JSON.stringify( eventInfo );
  Shiny.onInputChange(map_id + "_" + layer + "_click", eventInfo);

I think the actual issue is the id argument in the R functions; I'm not sure they do anything and may be left over from a very early iteration of this library.


But thanks for bringing this up; the documentation certainly needs to be clearer.

bdbmax commented 2 years ago

Good, interesting. I got mixed up between the different output of the onClick event depending on the layers used. add_polygon offers the possibility to retrieve the supplied ID (from the id argument in the R function) from a click through jsonlite::fromJSON(input$map_polygon_click)$object$properties$id, which is a great feature we highly rely on.

library(mapdeck)
library(shiny)

sf <- geojsonsf::geojson_sf("https://symbolixau.github.io/data/geojson/SA2_2016_VIC.json")

ui <- fluidPage(
  mapdeckOutput("map"),
  htmlOutput("selection")
)

server <- function(input, output, session) {
  # Map
  output$map <- renderMapdeck(mapdeck() |> 
                                add_polygon(
                                  data = sf,
                                  id = "SA2_MAIN16", 
                                  tooltip = "SA2_MAIN16"))

  # Selection
  select_id <- eventReactive(input$map_polygon_click, {
    jsonlite::fromJSON(input$map_polygon_click)$object$properties$id
  })

  output$selection <- renderText(paste("Selected output: ", select_id()))

}

shinyApp(ui = ui, server = server)

A click on any polygon return its id (its SA2_MAIN16 value in this example). Reclicking on the same polygon then returns NULL, signaling a deselection.

The same functionality would be interesting for point data!

dcooley commented 2 years ago

Oh that's interesting; the scatterplot object returned from deck.gl does not contain the object, (first console.log() in the screenshot), whereas the object returned for the polygon does contain the object, which is why you get the Id returned.

Screenshot 2022-01-21 at 9 12 49 am