Search code examples
leafletzoomingcenter

R Shiny app with Leaflet map not centering on selected point


I have a leaflet map in an R shiny app and the map will not center and refocus on the selected location. Whats frustrating is this works with census data centroids but doesn't with my data.

I have the code below which works if i use some dummy data from census but when i use my own data (available on Github) it wont work. I am suspecting something with my data but i can't seem to understand what it might be.


#Load libraries
##########################################
library(shiny)    
library(shinyWidgets)
library(tigris)
library(leaflet)
library(rgeos)
library(rgdal)


#Get data from here - https://github.com/JoshRoll/ODOT-Projects/blob/master/Bend_Spatial_Data_2018.gdb.zip

#Count Location spatial information
##############
#Define the location where you unzipped the downloaded file
fgdb <-     "Bend_Spatial_Data_2018.gdb"
# Read the feature class
Count_Location_Info_Sp <-  readOGR(dsn=fgdb,layer= "MMCountLocations")

# Load data- Use census to use as proper spatial transformation from x/y to lat/long (Uses tigris package)
States_Sp <- states( year = "2010")
#Reproject
Count_Location_Info_Sp <-  spTransform(Count_Location_Info_Sp, CRS(proj4string( States_Sp)))  

#Create a data frame from spatial data
Data.. <- Count_Location_Info_Sp@data

#Set up User Interface
######################
ui <- fluidPage(
  titlePanel("LOcation Selector Test"),
  tabsetPanel(
    #Daily Counts Panel
    ##############
    #Hourly Counts Panel
    #######################
    tabPanel("Tab 1",
             #Call plot 
             fluidRow(
               column(3,
                      uiOutput("Location_Selector"))),
             #Location Details 
             fluidRow( 
               column(6,
                      #h4("Selected Location"),
                      leafletOutput("map_plot",height = 500))
               #Close row
             )
             #Close panel
    )
    #Close setPanel
  )
  #Page end   
)

#Set up Server
#---------------------------
server <- shinyServer(function(session,input,output){
  #Location selector
  observe({
    output$Location_Selector <- renderUI({
      selectInput(inputId = "Location_Selector",
                  label = "Select Location", multiple = FALSE,
                  choices = as.character(unique(Data..$Sub_Location_Id)),
                  selected =  unique(Data..$Sub_Location_Id)[1])
    })
  })
  #Set up starting leaflet
  ###############
  output$map_plot <- renderLeaflet({
    leaflet(Count_Location_Info_Sp) %>%
      addTiles() %>%
      addCircles(color = "black" )
    })
  #Set up proxy leaflet for updated selector
  ####################
  observe({
    dat <-  Count_Location_Info_Sp[Count_Location_Info_Sp@data$Sub_Location_Id%in%input$Location_Selector,]
    lat <-  coordinates( dat)[,1]
    long <-  coordinates(dat)[,2]
    leafletProxy("map_plot") %>% 
      clearShapes() %>%
      addTiles() %>%
      addCircles(data =dat ,color = "black" ) %>%
      setView(lng = long, lat = lat, zoom = 14)
   #Close leaflet proxy observe
  })


})
#Run App
shinyApp(ui,server)


Solution

  • The Simple features (sf) package is a lot easier to work with (in my opinion) and is way more feature-rich than using sp. Here is how I would do it,

    All i did was change how the data is read in using the sf package. We transform it to standatd coordinates reference frame (crs). The dataset is using a different coordinate reference frame.

    And then finally, in sf you dont need to index into @data. You can treat you dataframe Count_Location_Info_Sp as a regular old dataframe (albeit with a few additional features).

    #Load libraries
    ##########################################
    library(shiny)    
    library(shinyWidgets)
    library(tigris)
    library(leaflet)
    library(rgeos)
    library(geosphere)
    library(sf)
    
    
    #Get data from here - https://github.com/JoshRoll/ODOT-Projects/blob/master/Bend_Spatial_Data_2018.gdb.zip
    
    #Count Location spatial information
    ##############
    #Define the location where you unzipped the downloaded file
    fgdb <-     "~/Downloads/Bend_Spatial_Data_2018.gdb"
    # Read the feature class
    Count_Location_Info_Sp <-  st_read(dsn=fgdb,layer= "MMCountLocations",stringsAsFactors = FALSE)
    Count_Location_Info_Sp <- st_transform(Count_Location_Info_Sp, crs = "+proj=longlat +datum=WGS84")
    
    
    #Set up User Interface
    ######################
    ui <- fluidPage(
      titlePanel("LOcation Selector Test"),
      tabsetPanel(
        #Daily Counts Panel
        ##############
        #Hourly Counts Panel
        #######################
        tabPanel("Tab 1",
                 #Call plot 
                 fluidRow(
                   column(3,
                          uiOutput("Location_Selector"))),
                 #Location Details 
                 fluidRow( 
                   column(6,
                          #h4("Selected Location"),
                          leafletOutput("map_plot",height = 500))
                   #Close row
                 )
                 #Close panel
        )
        #Close setPanel
      )
      #Page end   
    )
    
    #Set up Server
    #---------------------------
    server <- shinyServer(function(session,input,output){
      #Location selector
      observe({
        output$Location_Selector <- renderUI({
          selectInput(inputId = "Location_Selector",
                      label = "Select Location", multiple = FALSE,
                      choices = as.character(unique(Data..$Sub_Location_Id)),
                      selected =  unique(Data..$Sub_Location_Id)[1])
        })
      })
      #Set up starting leaflet
      ###############
      output$map_plot <- renderLeaflet({
        leaflet(Count_Location_Info_Sp) %>%
          addTiles() %>%
          addCircles(color = "black" )
      })
      #Set up proxy leaflet for updated selector
      ####################
      observe({
        req(input$Location_Selector)
    
        dat <-  Count_Location_Info_Sp[Count_Location_Info_Sp$Sub_Location_Id %in% input$Location_Selector,]
        lat <-  st_coordinates(dat)[[2]]
        long <-  st_coordinates(dat)[[1]]
        leafletProxy("map_plot") %>%
          clearShapes() %>%
          addTiles() %>%
          addCircles(data =dat ,color = "black" ) %>%
          setView(lng = long, lat = lat, zoom = 14)
        #Close leaflet proxy observe
      })
    
    
    })
    #Run App
    shinyApp(ui,server)