0

I am new in shiny, at the moment I am trying to set up a code where I can calculate activity clusters (through DBSCAN package) based on input variables: "eps" (minimum distances between points to be part of a cluster), "minpts" (minimum number of points to certain categories as Health), "maxpts" (minimum number of points for general categories as pubs, restaurants etc).

I did a test only through leaflet (without shiny) and the code runs smoothly, but once I bring-in shiny, I'm not able to make it work

the idea is that the user can modify these 3 variables on the side panel, and click an action button in order to trigger the calculation.

   #----------LIBRARIES----------#

library(plyr)
library(geosphere)
library(dbscan)
library(osmdata)
library(sf)
library(tidyr)
library(sp)
library(rgdal)
library(leaflet)
library(shiny)

#-------LOAD FILES-------#

OSM_merged <- read.csv(file = "C:\\Users\\jsainz\\Documents\\R\\Shiny_test\\OSM_merged.csv")

OSM_points <- OSM_merged

OSM_points$color <- OSM_points$category

OSM_points$color <- str_replace_all(OSM_points$color, "Culture", "#3073A")
OSM_points$color <- str_replace_all(OSM_points$color, "Educational", "# 887CAF")
OSM_points$color <- str_replace_all(OSM_points$color,"Financial", "#540002")
OSM_points$color <- str_replace_all(OSM_points$color,"Health", "#D6E899")
OSM_points$color <- str_replace_all(OSM_points$color,"Leisure", "#D2D68D")
OSM_points$color <- str_replace_all(OSM_points$color,"Office", "#D3696C")
OSM_points$color <- str_replace_all(OSM_points$color,"Shop", "#AA9739")
OSM_points$color <- str_replace_all(OSM_points$color,"Sport", "#378B2E")
OSM_points$color <- str_replace_all(OSM_points$color,"Sustain", "#554600")
OSM_points$color <- str_replace_all(OSM_points$color,"Toursim", "#5FAE57")

xy <- OSM_points[,c(2,3)]
OSM_points <- SpatialPointsDataFrame(coords = xy, data = OSM_points,proj4string = CRS("+proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"))

#-------FUNCTIONS-------#

assign_clusters <- function(poi_df, minPts = NA) {
  if(is.na(minPts)) {
    if(poi_df[1, "category"] %in% c("Culture", "Leisure", "Education", "Health", "Financial")) {
      minPts <- "minpts"
    } else minPts <- "maxpts"
  }

  eps <- "epsilon"

  poi_df[c("lng", "lat")] %>% 
    distm(fun = distHaversine) %>%
    as.dist() %>% 
    dbscan(eps = eps, minPts = minPts) %>% 
    .[["cluster"]] %>% 
    cbind(poi_df, cluster = .)
}

get_hull<- function(df) {

  cbind(df$lng, df$lat) %>% 
    as.matrix() %>%
    st_multipoint() %>% 
    st_convex_hull() %>% 
    st_sfc(crs = 4326) %>% 
    {st_sf(category = df$category[1], cluster = df$cluster[1], geom = .)}
}

hulls <- function(df) {

  df %>%
    split(.$cluster) %>% 
    map(get_hull)

}

#----------SHINY CODE----------#

ui <- fluidPage(

  titlePanel("Jorge_Test"),

  sidebarPanel(
  numericInput(inputId = "epsilon", label = "distance in meters to calculate activity clusters", 200),
  numericInput(inputId = "minpts", label = "minimum points to calculate clusters", 5),
  numericInput(inputId = "maxpts", label = "maximum points to calculate clusters", 10),
  actionButton("run", "Run Calculation"),
  actionButton("view", "generate plan"),
  width = 2),

  mainPanel(
  leafletOutput("mymap", width = 1550, height = 850)
  )
)

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

  output$mymap <- renderLeaflet({
    leaflet("mymap")%>%
      setView(lng = 0.0982, lat = 51.7674, zoom = 15)%>%
      addProviderTiles(providers$CartoDB.Positron, options = providerTileOptions(noWrap = TRUE))%>%
      addCircleMarkers(data = OSM_points,
                       radius = .7,
                       popup = ~category,
                       color = ~color)})

  oberveEvent(input$run, {

  updateNumericInput(session, "epsilon")
  updateNumericInput(session, "minpts")
  updateNumericInput(session, "maxpts")

  })

  Clean_data <- OSM_merged %>%
    split(OSM_merged$category) %>%  
    map_df(assign_clusters)

  hulls_cat <- Clean_data %>%
    group_by(category) %>%
    summarise()

  map_cluster_hulls <- Clean_data %>%
    filter(cluster != 0) %>%
    select(lng, lat, category, cluster) %>% 
    split(.$category) %>% 
    map(hulls)

  mdata <- melt(map_cluster_hulls, id = c("category", "cluster", "geom"))
  mch <- data.frame(mdata$category, mdata$cluster, mdata$geom)

  observeEvent(input$view, {
    leafletProxy("mymap", session) %>%
    addPolygons(data = mch$geom,
                fill = NA,
                fillOpacity = .01,
                weight = 2,
                color = "red",
                opacity = .8)
  }
 )

}

shinyApp(ui, server)

any idea of how to solve it?

here is a link to the OSM_merged.csv file: https://www.dropbox.com/s/5ok9frcvx8oj16y/OSM_merged.csv?dl=0

jorge
  • 3
  • 2
  • (1) I'm confused about something: you call `updateNumericInput` a few times but update nothing; are you hiding code from us or are you intentionally running no-op code? (2) You define a function *every time* within your `eventReactive`, why clobber things? Keep that outside of the `server` declaration. Simplifying the amount of code in a reactive is very useful. (3) You call `summarise()` with no arguments so you effectively get `unique(Clean_data$category)`, is that what you intend to use? (4) You define `mch` but only use `mch$geometry`, why not just use `mdata$geom`? – r2evans May 06 '20 at 17:09
  • Welcome to SO, jorge! This is mostly a good question, good effort! Nobody can test this code, though, without having representative sample data. Normally I recommend using `dput(head(x))`, but I understand `dbscan` and know that it will have a hard time with *small* data (and pasting lots of data in a question does not always go well). Perhaps you can produce random data programmatically (`set.seed(2)`, then some `sample`, `runif`, `rnorm`, whatever into a `data.frame`) in order to give us something to play with. – r2evans May 06 '20 at 17:13
  • Another thought/request: you load `tidyverse` *and* packages that are already loaded when you do that. If you know which packages are being used, I encourage you to *not* `library(tidyverse)`, instead picking individual packages needed. (For example, I don't have `tidyverse` loaded though I have most of its imports available and use them regularly. I would need to comment out `tidyverse` and try this repeatedly, finding errors for missing functions, and finding their package, etc.) – r2evans May 06 '20 at 17:15
  • And lastly, do you *know* you need `plyr`? On first glance I see none of its functions being used, and it easily causes collisions with `dplyr` (subject to the load order ... this is the preferred load order, so you're okay). I also see no use of `data.table` or `rbenchmark`. (Providing a *minimal* working example is highly valued on SO. This is far from "minimal", though I understand you do not know where the issue is, so reducing might be extremely difficult.) – r2evans May 06 '20 at 17:18
  • sorry, all the libraries were inherited from the original code, where I run all the calculations without shiny and was more extensive, I will make an update of the code and provide some sample data – jorge May 06 '20 at 17:49
  • I included a link to the OSM_merged csv and updated the code, I must admit I am quite lost in shiny, so most likely there are some gross mistake over there, any help will be appreciated, thanks – jorge May 06 '20 at 18:09

0 Answers0