1

I've just recently started attempting to build mapping apps with leaflet and shiny in R. I'm currently stumped by an issue with projecting polygons inside shiny.

Here is the shapefile to reproduce my code, and here's the stripped down code:

library(shiny)
library(leaflet) #MUST INSTALL DEVELOPMENT VERSION WITH:  devtools::install_github('rstudio/leaflet')
library(sp)
library(rgeos)
library(rgdal)


#pull in full rock country shapefile, set WGS84 CRS
countries <- readOGR("D:/NaturalEarth/HIF", layer = "ctry_hif", 
                     stringsAsFactors = F, encoding = "UTF-8")
countries <- spTransform(countries, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))

#run shiny app
shinyApp(
  ui = fluidPage(leafletOutput('myMap', width = "80%", height = 500),
                 absolutePanel(width = "20%", top = 10, right = 5, 
                               selectInput(inputId = "location",
                                           label = "Country", 
                                           choices = c("", countries@data$sovereignt), 
                                           selected = "")
                 )
  ),     #END UI

  server <- function(input, output, session) {

    #observe click event; zooms to administrative units for the country that is clicked on
    observeEvent(input$location, {

      #subset countries shapefile by dropdown selection country
      selected <- countries[countries@data$sovereignt == input$location,]

      # selected <- spTransform(selected, CRS("+proj=moll +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"))
      # selected <- gBuffer(selected, width = -.2)
      # selected <- spTransform(selected, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))

      #plot leaflet output
      output$myMap <- renderLeaflet({
        leaflet() %>%
          addTiles() %>%
          addPolygons(data = selected)
      })    #END TOP LEAFLET OUTPUT
    }) #END OBSERVE EVENT 
  } #END SERVER
) #END SHINYAPP

Running this code as is works fine--the map updates with whichever country the user selects from the dropdown menu.

The problem occurs when I try to change the projection of the selected polygon within the Shiny observeEvent. The ultimate goal is to be able place the country level polygon over a regional-level polygon with the rgeos function over and update the map with regions rather than countries. I have achieved this within Shiny to create a perfectly functional app. But when I try to use that same exact code within this app, no dice. I've narrowed the problem down to the following lines of code (which are commented out above):

selected <- spTransform(selected, CRS("+proj=moll +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"))
selected <- gBuffer(selected, width = -.2)
selected <- spTransform(selected, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))

When I uncomment those lines of code, the app breaks and gives me the following error:

Warning: Error in [[: subscript out of bounds Stack trace (innermost first): 74: slot 73: .spTransform_Polygons 72: spTransform 71: spTransform 70: spTransform 69: spTransform 68: observeEventHandler [#19] 4: 3: do.call 2: print.shiny.appobj 1: ERROR: [on_request_read] connection reset by peer

When I take the code out of Shiny and run it with a country string in place of input$location, it works perfectly fine. And again, I've gotten the same exact code to run in a different app with a click event. But the projection change breaks this one.

Does anyone have any insight why this spTransform breaks my Shiny app?

3

I just add an if statement to your code to filter the first automatic selection when the app starts: "".

Note 1: I selected a bigger width option in the gBuffer function to see how it changed!

#observe click event; zooms to administrative units for the country that is clicked on

observeEvent(input$location, {

      #subset countries shapefile by dropdown selection country

      selected <- countries[countries@data$sovereignt == input$location,]

      if(input$location != "") {

        selected <- spTransform(selected, CRS("+proj=moll +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"))
        selected <- gBuffer(selected, width = -100000)
        selected <- spTransform(selected, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))

      }

      #plot leaflet output
      output$myMap <- renderLeaflet({
        leaflet() %>%
          addTiles() %>%
          addPolygons(data = selected)

      })    #END TOP LEAFLET OUTPUT

    })

If you want that when the app start all the countries have the gBuffer effect applied you can use this code:

#observe click event; zooms to administrative units for the country that is clicked on
observeEvent(input$location, {

  #subset countries shapefile by dropdown selection country

  if(input$location == "" ) {

    selected <- countries

  } else {

    selected <- countries[countries@data$sovereignt == input$location,]

  }

  selected <- spTransform(selected, CRS("+proj=moll +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"))
  selected <- gBuffer(selected, width = -10000)
  selected <- spTransform(selected, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"))

  #plot leaflet output
  output$myMap <- renderLeaflet({
    leaflet() %>%
      addTiles() %>%
      addPolygons(data = selected)

  })    #END TOP LEAFLET OUTPUT

}) #END OBSERVE EVENT

Note 2: At the begining you don't need to transform your spatial object because it has the projection you desired from the ctry_hif.prj file. See below:

#pull in full rock country shapefile, set WGS84 CRS
countries <- readOGR(dsn = "D:/NaturalEarth/HIF", layer = "ctry_hif", stringsAsFactors = F, encoding = "UTF-8")

proj4string(countries)

# Output:
[1] "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"

# countries <- spTransform(countries, CRS("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")) # You don't need this
  • THANK YOU! Any idea why this works? It's the most bizarre thing because it works outside of a conditional statement in a different app. And thanks for the additional notes as well. Projection and buffer width were two fields I was playing around with to try to troubleshoot my problem, so they were relics of troubleshooting. But it's always nice to trim down code! – Lauren Nov 8 '16 at 15:11
  • 1
    You are welcome! I think the main problem was in this line of code: countries[countries@data$sovereignt == input$location,] because the default input$location when your app started was this "" (see your selectInput default selection: selected = ""). If you query your spatial object like this: countries[countries@data$sovereignt == "",] you get 0 features. And then you wanted to apply a transformation to a 0 feature spatial object and son on. – Guzmán Nov 8 '16 at 15:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.