I am attempting to use the Shiny package for R to plot points on a map as they appear at different points throughout the day.
An unexpected problem arises when the Shiny server is told to take the coordinates (lon and lat) of a subsetted dataframe:
coordinates(selected.tweet.points.spdf) <- ~ lon + lat
The interesting thing is that this works outside of Shiny, but is not working for me within Shiny.
The error message displayed in the Shiny window is:
Error: cannot derive coordinates from non-numeric matrix
This is the same error message that would appear if you were to call coordinates()
on an object that is not a spatial object without telling it what to consider coordinates, like so:
coordinates(selected.tweet.points.spdf)
Here is a minimally reproducible example (sans the actual plotting):
library(shiny)
library(tigris)
library(dplyr)
library(leaflet)
library(sp)
library(ggmap)
library(maptools)
library(broom)
library(httr)
library(rgdal)
library(tidyr)
nyc.neighborhoods.url <- GET('http://data.beta.nyc//dataset/0ff93d2d-90ba-457c-9f7e-39e47bf2ac5f/resource/35dd04fb-81b3-479b-a074-a27a37888ce7/download/d085e2f8d0b54d4590b1e7d1f35594c1pediacitiesnycneighborhoods.geojson')
nyc.neighborhoods.spdf <- readOGR(content(nyc.neighborhoods.url, 'text'), 'OGRGeoJSON', verbose = F)
nyc.neighborhoods.df <- tidy(nyc.neighborhoods.spdf)
tweet.points.df <- data.frame(class = c("Not Private", "Not Private", "Private", "Private", "Private", "Private"),
lat = c(40.65514, 40.65514, 42.74662, 42.74662, 40.65514, 40.57238),
lon = c(-73.94878, -73.94878, -75.77004, -75.77004, -73.94878, -74.15395),
time = c("14:00", "14:00", "14:30", "14:30", "14:30", "14:30"))
shinyApp(
# User interface
ui = fluidPage(
titlePanel("Social Media Post Privacy Classifier"),
sidebarLayout(
sidebarPanel(
sliderInput("time", "Time of day (by half hour)",
min = as.POSIXlt("2017-01-01 00:00:00", tz = "GMT"),
max = as.POSIXlt("2017-01-01 23:30:00", tz = "GMT"),
value = as.POSIXct("2017-01-01 00:00:00", tz = "GMT"),
timeFormat="%H:%M", timezone = "+0000", step = 60 * 30, animate = T)
),
mainPanel(
textOutput("out")
)
)
),
# Server
server = function(input, output) {
choropleth.selection <- reactive({
selected.time <- format(input$time, '%H:%M')
selected.tweet.points.df <- tweet.points.df[tweet.points.df$time == selected.time, ]
selected.tweet.points.spdf <- selected.tweet.points.df
coordinates(selected.tweet.points.spdf) <- ~ lon + lat
proj4string(selected.tweet.points.spdf) <- proj4string(nyc.neighborhoods.spdf)
selected.tweet.points.df.matches <- over(selected.tweet.points.spdf, nyc.neighborhoods.spdf)
selected.tweet.points.df <- cbind(selected.tweet.points.df, selected.tweet.points.df.matches)
selected.tweet.points.df <- selected.tweet.points.df %>% drop_na()
print(selected.tweet.points.df$class)
})
output$out <- renderPrint({ choropleth.selection() })
}
)
This is an example that proves that the same technique works outside of Shiny:
selected.time <- "14:30"
points.df <- data.frame(class = c("Not Private", "Not Private", "Private", "Private", "Private", "Private"),
lat = c(40.65514, 40.65514, 42.74662, 42.74662, 40.65514, 40.57238),
lon = c(-73.94878, -73.94878, -75.77004, -75.77004, -73.94878, -74.15395),
time = c("14:00", "14:00", "14:30", "14:30", "14:30", "14:30"))
points.df <- data.frame(points.df[points.df$time == selected.time, ])
coordinates(points.df) <- ~ lon + lat
The error arises when selected.tweet.points.spdf
is empty, ie when there's no matching time. This is the case in the initial run, when selected.time
is 00:00
- there's no matching tweet.points.df$time
for that.
One possible solution would be to change your server function like this:
server = function(input, output) {
choropleth.selection <- reactive({
selected.time <- format(input$time, '%H:%M')
selected.tweet.points.df <- tweet.points.df[tweet.points.df$time == selected.time, ]
selected.tweet.points.spdf <- selected.tweet.points.df
validate(need(nrow(selected.tweet.points.df)>0, "No match")) # <=======
coordinates(selected.tweet.points.spdf) <- ~ lon + lat
proj4string(selected.tweet.points.spdf) <- proj4string(nyc.neighborhoods.spdf)
selected.tweet.points.df.matches <- over(selected.tweet.points.spdf, nyc.neighborhoods.spdf)
selected.tweet.points.df <- cbind(selected.tweet.points.df, selected.tweet.points.df.matches)
selected.tweet.points.df <- selected.tweet.points.df %>% drop_na()
print(selected.tweet.points.df$class)
})
output$out <- renderPrint({ choropleth.selection() })
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.