1
votes

I want to create a reactive shiny world map with r using a spatial polygons data frame. The idea is to have a slider with different years, which can be moved and is used as an input for coloring the countries. My problem is in making the data reactive, when I run the code that is attached below the slider input values are taken (e.g for all the countries the value is 2004) and the error message "Warning in pal(input$year) : Some values were outside the color scale and will be treated as NA" pops up. When making the application 'static' (writing sp_Suicide$2004 instead of input$year) the map is correctly displayed. How do I link the input of the slider in a way that it accesses the data for each country and does not simply take the year as an input? Thank you very much in advance for any responses!

library(shiny)
library(leaflet)
library(data.table)
library(sp)

#read data in (data table)
Suicide<-fread("Final_Suicide_Data.csv", header=T)

#read shapefile in
world<-readOGR(dsn=".", layer="TM_WORLD_BORDERS-0.3")

#Merge Suicide data to shapefile
sp_Suicide<-sp::merge(world, Suicide, all.x=T, by.x='UN', by.y='un') #SpatialPolygonDataFrame

#make shiny application
ui <- fluidPage(

   # Application title
   titlePanel("Suicide"),

   # Sidebar with a slider input for number of bins 
   sidebarLayout(
     leafletOutput("suicidemap"),
      sidebarPanel(
         sliderInput("year",
                     "Year:",
                     min = 2004,
                     max = 2015,
                     value = 11,
                     sep="")

      )
   )
)



server <- function(input, output, session) {
  output$suicidemap<-renderLeaflet({
    leaflet(data=sp_Suicide)%>%
      addProviderTiles("CartoDB.Positron")%>%
      addPolygons(fillColor=~pal(input$year),
                  fillOpacity = 0.7,
                  color="#BDBDC3",
                  weight=1) %>%
      addLegend("bottomleft",
                pal=pal,
                values=~input$year,
                title="")   

  })
}

# Run the application 
shinyApp(ui = ui, server = server)

UPDATE: Thank you very much for the extensive answer :) In the following I recreated a sample of how the data looks that I'm using.

UN<-c(4,8,12)
Country<-c('Afghanistan', 'Albania', 'Algeria')
`2004`<-c(6.68, 7.69, 4.84)
`2005`<-c(6.68, 7.7, 4.84)
`2006`<-c(6.74, 7.15, 4.56)
`2007`<-c(6.81, 6.61, 4.27)
`2008`<-c(6.87, 6.07, 3.97)
`2009`<-c(6.93, 5.54, 3.69)
`2010`<-c(7, 5, 3.4)
`2011`<-c(7.02, 4.76, 3.34)
`2012`<-c(7.04, 4.52, 3.28)
`2013`<-c(7.06, 4.28, 3.22)
`2014`<-c(7.08, 4.04, 3.16)
`2015`<-c(7.1, 3.8, 3.1)
SuicideData<-data.frame(UN, Country, `2004`, `2005`, `2006`, `2007`, `2008`,    `2009`, `2010`, `2011`, `2012`, `2013`, `2014`, `2015`)
names(SuicideData)<-c("UN", "Country", "2004", "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015")

Additionally, this is the shapefile that I'm (trying) to use: Link to shapefile.

I tried running your code, but it still does not work. Is it possible that the data that I use as an input must be formatted differently? I'm trying to continue with your interesting approach of merging only the input data with the shapefile!

1
couldn't test it as you did not provide a reproducible example but maybe fillColor=~pal(input$year()) and values=~input$year() in the server part?CER

1 Answers

0
votes

It is difficult to provide a proper answer without a reproducible example. But, if I understand correctly what you're trying to do, you seem to be missing several steps. I'm posting some sample code below and hopefully it will help as a template and guide.

Let's say we have a dataset (suidata) of aggregated yearly suicides (sum_suicides) by year (year) and a shapefile (worldshap) with a common identifier in each of these for country (such as "ID") that we can use for the merge. One way of going about this would then be:

ui <- fluidPage(

  # Application title
  titlePanel("Suicide"),

  # Sidebar with a slider input for number of bins 
  sidebarLayout(
    leafletOutput("suicidemap"),
    sidebarPanel(
      sliderInput("year",
                  "Year:",
                  min = 2004,
                  max = 2015,
                  value = 2011, #value is the starting value so should be value within date range
                  sep="",
                  ticks = FALSE)))) # False for aesthetics because otherwise displays irregular tick intervals

We first need to select the data we want (based on the slider input) in a reactive function (notice we have not merged anything at this stage unlike in your example above):

server <- function(input, output, session) {
selected <- reactive({
suidata <- filter(suidata,
year == input$year)
suidata
})

Here, we are just passing to a function selected a subset of data that depends upon what the slider input has been set to. If 2011, for example, the data sent to render the leaflet map below will just be a subset of data for 2011. Before that, though, we want to set a basemap. This contains all the elements of the Leaflet map that we want---e.g., tiles from CartoDB, a specified long, lat, and zoom (i.e. you have to replace these values) as well as a legend. My assumption is that the error thrown up is because you don't define the palette correctly. My advice would be to set the palette in the global section (i.e., outside of the shiny app and do this across the entire range of the data). I give an example at the end for how to do this.

output$suicidemap <- renderLeaflet({
  leaflet() %>% 
    addTiles("CartoDB.Positron") %>% 
    setView(long, lat, zoom= x)%>%
    addLegend("bottomright", pal=pal, values=suidata$sum_suicides, title = "Title of legend")
})

In a a reactive observer we then merge the shapefile with the selected data (note the important brackets after selected (because technically it's a function we're calling). This will then call up the specified year's data and plot it.

observe({
  if(!is.null(input$year)){
      shapefile@data <- left_join(shapefile@data, selected(), by="ID")
      leafletProxy("suicidemap", data = shapefile) %>%
        addTiles() %>% 
        clearShapes() %>% 
        addPolygons(data = shapefile, fillColor = ~pal(sum_suicides), fillOpacity = 0.7, 
                    color = "white", weight = 2)
    }})

}

# Run the application 
shinyApp(ui, server)

Defining the palette---say we want a legend to be constant on the map displaying the highest and lowest theoretical values then we'd need to define a palette over this range. If we are looking at yearly aggregates, the highest value will be the country with the highest number of yearly suicides and the lowest the country with the lowest number of yearly suicides. Thus, we define our global palette as:

pal <- colorBin("YlOrRd", suidata$sum_suicides, bins=5, na.color = "#bdbdbd")

I hope this is of some use :)