O. Keller
O. Keller

Reputation: 31

How to subset a dataframe and plot with leaflet depending on inputselect

I am trying to make a shiny app that produces leaflet outputs.

I am using one dataframe with tracks of different individuals from which I want to subset and plot the track of one animal in response to inputselection.

Sample:

WhaleID     lat       long
gm08_150c   68,4276   16,5192
gm08_150c   68,4337   16,5263
gm08_150c   68,4327   16,5198
gm08_154d   68,4295   16,5243
gm08_154d   68,4313   16,5314
gm08_154d   68,4281   16,5191

The choices in the input selection are the exact names used in the .csv file, in the column WhaleID, so I would like the subset all rows with that WhaleID from the main dataframe.

After this subset I want to subset only the "long" and "lat" columns from the previously subsetted dataframe. This dataframe is then read by leaflet.

The final step is plotting these "long"and "lat" positions on a map.

Unfortunately I keep getting an error message:

Warning: Error in $: object of type 'closure' is not subsettable
Stack trace (innermost first):
    82: inherits
    81: resolveFormula
    80: derivePolygons
    79: addPolylines
    78: function_list[[i]]
    77: freduce
    76: _fseq
    75: eval
    74: eval
    73: withVisible
    72: %>%
    71: func [#15]
    70: output$map
     4: <Anonymous>
     3: do.call
     2: print.shiny.appobj
     1: <Promise>

The script I am using:

    require(shiny)
    require(leaflet)
    
    ##Main dataframe I want to subset depending on inputselection    
    dataframe <-read.csv2("PW_with_speedbearingturn.csv") 
    
    
    ui <- bootstrapPage( 
      tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
      absolutePanel(top = 10, right = 10,
      selectInput(inputId = "whaleID", 
                  label = "Select a whale", 
                  choices = c("gm08_150c","gm08_154d"))),
      leafletOutput(outputId = "map", width = "100%", height = "700")
    ) 
    
    server <- function(input, output, session){ 
      
      #?observeEvent  
      #observeEvent(input$whaleID, )
      Start <- makeIcon(
        iconUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Dark_Green_Arrow_Down.svg/480px-Dark_Green_Arrow_Down.svg.png",
        iconWidth = 22, iconHeight = 20,
        iconAnchorX = 11, iconAnchorY = 20)
      
      eventReactive(input$whaleID,{
                    df<-subset(dataframe, WhaleID == "input$whaleID") ## "input$whaleID" should become the WhaleID that is selected from the inputselect.

                    df<-subset(df, select = c("long", "lat")) 
      })                
      output$map <- renderLeaflet({
      leaflet() %>%
      addTiles() %>%
      addPolylines(df, lng = df$long, lat = df$lat, col = "grey", opacity = 1)%>%
      addMarkers(df, lng = first(df$long), lat = first(df$lat), icon = Start, popup = "Start")
      })
    } 
    
    shinyApp(ui = ui, server = server)

I believe it has to do with the eventreactive section and the subsetting part within. It has to be updated each time in response to what choice is selected from the inputselection. Unfortunately I could not find any existing solutions to this question.

Do you have any advice on how to solve this issue?

Upvotes: 3

Views: 2774

Answers (2)

SeGa
SeGa

Reputation: 9809

A little late, but for completeness and to illustrate how to do it with an eventReactive. You have to assign a name to it and then call the eventReactive (df()), otherwise it will never run.

Also if you put input$whaleID in parenthesis, it will subset the dataframe column for "input$whaleID" which is not in the dataframe i suppose. Therefore you want it without parenthesis, so it takes the selected argument from the selectInput.

You can also put the Icon outside of the server, as it doesnt have to be reactive.

require(shiny)
require(leaflet)
require(dplyr)

##Main dataframe I want to subset depending on inputselection    
dataframe <- read.csv2("PW_with_speedbearingturn.csv")

Start <- makeIcon(
  iconUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Dark_Green_Arrow_Down.svg/480px-Dark_Green_Arrow_Down.svg.png",
  iconWidth = 22, iconHeight = 20,
  iconAnchorX = 11, iconAnchorY = 20)

ui <- bootstrapPage( 
  tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
  absolutePanel(top = 10, right = 10,
                selectInput(inputId = "whaleID", 
                            label = "Select a whale", 
                            choices = c("gm08_150c","gm08_154d"))),
  leafletOutput(outputId = "map", width = "100%", height = "700")
)

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

  df <- eventReactive(input$whaleID,{
    daf <- subset(dataframe, WhaleID == input$whaleID) 
    subset(daf, select = c("long", "lat")) 
  })  

  output$map <- renderLeaflet({
    leaflet() %>%
      addTiles() %>%
      addPolylines( lng = df()$long, lat = df()$lat, col = "red", opacity = 1)%>%
      addMarkers( lng = first(df()$long), lat = first(df()$lat), icon = Start, 
                  popup = "Start")
  })
} 

shinyApp(ui = ui, server = server)

Upvotes: 0

timelyportfolio
timelyportfolio

Reputation: 6579

I think you can avoid the eventReactive entirely since the renderLeaflet will be reactive on changes to input. Here is an adapted example since I don't have your data. Let me know if it does not make sense.

require(shiny)
require(leaflet)

##Main dataframe I want to subset depending on inputselection    
dataframe <- data.frame(
  abb = state.abb,
  x = state.center$x,
  y = state.center$y,
  stringsAsFactors = FALSE
)


ui <- bootstrapPage( 
  tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
  absolutePanel(top = 10, right = 10,
                selectInput(inputId = "whaleID", 
                            label = "Select a state", 
                            choices = dataframe[["abb"]])),
  leafletOutput(outputId = "map", width = "100%", height = "700")
)

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

  Start <- makeIcon(
    iconUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/fe/Dark_Green_Arrow_Down.svg/480px-Dark_Green_Arrow_Down.svg.png",
    iconWidth = 22, iconHeight = 20,
    iconAnchorX = 11, iconAnchorY = 20)


  output$map <- renderLeaflet({
    df <- subset(dataframe, abb == input$whaleID)
    leaflet() %>%
      addTiles() %>%
      #addPolylines(df, lng = df$long, lat = df$lat, col = "grey", opacity = 1)%>%
      addMarkers(data = df, lng = ~x, lat = ~y, icon = Start, popup = "Start")
  })
} 

shinyApp(ui = ui, server = server)

Upvotes: 3

Related Questions