R Shiny app with Leaflet map not centering on selected point - leaflet

I have a leaflet map in an R shiny app and the map will not center and refocus on the selected location. Whats frustrating is this works with census data centroids but doesn't with my data.
I have the code below which works if i use some dummy data from census but when i use my own data (available on Github) it wont work. I am suspecting something with my data but i can't seem to understand what it might be.
#Load libraries
##########################################
library(shiny)
library(shinyWidgets)
library(tigris)
library(leaflet)
library(rgeos)
library(rgdal)
#Get data from here - https://github.com/JoshRoll/ODOT-Projects/blob/master/Bend_Spatial_Data_2018.gdb.zip
#Count Location spatial information
##############
#Define the location where you unzipped the downloaded file
fgdb <- "Bend_Spatial_Data_2018.gdb"
# Read the feature class
Count_Location_Info_Sp <- readOGR(dsn=fgdb,layer= "MMCountLocations")
# Load data- Use census to use as proper spatial transformation from x/y to lat/long (Uses tigris package)
States_Sp <- states( year = "2010")
#Reproject
Count_Location_Info_Sp <- spTransform(Count_Location_Info_Sp, CRS(proj4string( States_Sp)))
#Create a data frame from spatial data
Data.. <- Count_Location_Info_Sp#data
#Set up User Interface
######################
ui <- fluidPage(
titlePanel("LOcation Selector Test"),
tabsetPanel(
#Daily Counts Panel
##############
#Hourly Counts Panel
#######################
tabPanel("Tab 1",
#Call plot
fluidRow(
column(3,
uiOutput("Location_Selector"))),
#Location Details
fluidRow(
column(6,
#h4("Selected Location"),
leafletOutput("map_plot",height = 500))
#Close row
)
#Close panel
)
#Close setPanel
)
#Page end
)
#Set up Server
#---------------------------
server <- shinyServer(function(session,input,output){
#Location selector
observe({
output$Location_Selector <- renderUI({
selectInput(inputId = "Location_Selector",
label = "Select Location", multiple = FALSE,
choices = as.character(unique(Data..$Sub_Location_Id)),
selected = unique(Data..$Sub_Location_Id)[1])
})
})
#Set up starting leaflet
###############
output$map_plot <- renderLeaflet({
leaflet(Count_Location_Info_Sp) %>%
addTiles() %>%
addCircles(color = "black" )
})
#Set up proxy leaflet for updated selector
####################
observe({
dat <- Count_Location_Info_Sp[Count_Location_Info_Sp#data$Sub_Location_Id%in%input$Location_Selector,]
lat <- coordinates( dat)[,1]
long <- coordinates(dat)[,2]
leafletProxy("map_plot") %>%
clearShapes() %>%
addTiles() %>%
addCircles(data =dat ,color = "black" ) %>%
setView(lng = long, lat = lat, zoom = 14)
#Close leaflet proxy observe
})
})
#Run App
shinyApp(ui,server)

The Simple features (sf) package is a lot easier to work with (in my opinion) and is way more feature-rich than using sp. Here is how I would do it,
All i did was change how the data is read in using the sf package. We transform it to standatd coordinates reference frame (crs). The dataset is using a different coordinate reference frame.
And then finally, in sf you dont need to index into #data. You can treat you dataframe Count_Location_Info_Sp as a regular old dataframe (albeit with a few additional features).
#Load libraries
##########################################
library(shiny)
library(shinyWidgets)
library(tigris)
library(leaflet)
library(rgeos)
library(geosphere)
library(sf)
#Get data from here - https://github.com/JoshRoll/ODOT-Projects/blob/master/Bend_Spatial_Data_2018.gdb.zip
#Count Location spatial information
##############
#Define the location where you unzipped the downloaded file
fgdb <- "~/Downloads/Bend_Spatial_Data_2018.gdb"
# Read the feature class
Count_Location_Info_Sp <- st_read(dsn=fgdb,layer= "MMCountLocations",stringsAsFactors = FALSE)
Count_Location_Info_Sp <- st_transform(Count_Location_Info_Sp, crs = "+proj=longlat +datum=WGS84")
#Set up User Interface
######################
ui <- fluidPage(
titlePanel("LOcation Selector Test"),
tabsetPanel(
#Daily Counts Panel
##############
#Hourly Counts Panel
#######################
tabPanel("Tab 1",
#Call plot
fluidRow(
column(3,
uiOutput("Location_Selector"))),
#Location Details
fluidRow(
column(6,
#h4("Selected Location"),
leafletOutput("map_plot",height = 500))
#Close row
)
#Close panel
)
#Close setPanel
)
#Page end
)
#Set up Server
#---------------------------
server <- shinyServer(function(session,input,output){
#Location selector
observe({
output$Location_Selector <- renderUI({
selectInput(inputId = "Location_Selector",
label = "Select Location", multiple = FALSE,
choices = as.character(unique(Data..$Sub_Location_Id)),
selected = unique(Data..$Sub_Location_Id)[1])
})
})
#Set up starting leaflet
###############
output$map_plot <- renderLeaflet({
leaflet(Count_Location_Info_Sp) %>%
addTiles() %>%
addCircles(color = "black" )
})
#Set up proxy leaflet for updated selector
####################
observe({
req(input$Location_Selector)
dat <- Count_Location_Info_Sp[Count_Location_Info_Sp$Sub_Location_Id %in% input$Location_Selector,]
lat <- st_coordinates(dat)[[2]]
long <- st_coordinates(dat)[[1]]
leafletProxy("map_plot") %>%
clearShapes() %>%
addTiles() %>%
addCircles(data =dat ,color = "black" ) %>%
setView(lng = long, lat = lat, zoom = 14)
#Close leaflet proxy observe
})
})
#Run App
shinyApp(ui,server)

Related

Is there a way to add percentage to tbl_regression add_nevent?

I've just discovered that add_nevent in gtsummary can have the option location = "level". I am rapt! But I would like it to have a percentage as well. I've tried adding statistic = "{n}({p}%)" but nothing changes.
Here is my code:
tbl_regression(glm(rellife ~ age + gender, data = df, family = "binomial"), exponentiate = TRUE) %>%
add_nevent(location = "level", statistic = "{n}/{N}%") %>% # add number of events of the outcome
add_n(location = "level")
And the table:
I would like to have 1601 (93.6%) in the column Event N for Age and so on.
Any help would be appreciated.
Thanks
After adding the N and N event, you can use the modify_table_body() function to calculate the event rate. Example below!
library(gtsummary)
#> #BlackLivesMatter
packageVersion("gtsummary")
#> [1] '1.5.2'
tbl <-
glm(response ~ age + grade, trial, family = binomial) %>%
tbl_regression(exponentiate = TRUE) %>%
add_nevent(location = "level") %>%
add_n(location = "level") %>%
# adding event rate
modify_table_body(
~ .x %>%
dplyr::mutate(
stat_nevent_rate =
ifelse(
!is.na(stat_nevent),
paste0(style_sigfig(stat_nevent / stat_n, scale = 100), "%"),
NA
),
.after = stat_nevent
)
) %>%
# merge the colums into a single column
modify_cols_merge(
pattern = "{stat_nevent} / {stat_n} ({stat_nevent_rate})",
rows = !is.na(stat_nevent)
) %>%
# update header to event rate
modify_header(stat_nevent = "**Event Rate**")
Created on 2022-03-21 by the reprex package (v2.0.1)

Interaction terms in tbl_regression in R

How do I include coefficient of interaction between age and stage
glm(response~age+grade, family=binomial(link=logit),
data=trial) %>%
tbl_regression(
exponentiate = TRUE,
pvalue_fun = ~style_pvalue(.x, digits = 2)
)
The tbl_regression() functions provides a summary of the model results. To include an interaction in the summary table, the interaction must first be added to the model. Example below.
library(gtsummary)
packageVersion("gtsummary")
#> [1] '1.5.2'
tbl <-
glm(response ~ age * grade, family = binomial, data=trial) %>%
tbl_regression(
exponentiate = TRUE,
pvalue_fun = ~style_pvalue(.x, digits = 2)
)
Created on 2022-02-03 by the reprex package (v2.0.1)

How do you remove the row_labels text in an expss table?

I like to pipe my expss tables into kable to get access to some additional formatting options. That sometimes requires some tweaking, and I'm looking for a tweak here to get rid of the row_labels text in the first column of the header in the example below.
Simple reprex:
df <- data.frame(x=rbinom(100,1,0.5), y=rnorm(100,1,0.6),
z=rnorm(100,1,0.2), grp = rep(1:5,20))
var_lab(df$grp) = ""
df %>%
tab_cells(x,y,z) %>%
tab_cols(grp) %>%
tab_stat_mean (label = "") %>%
tab_pivot %>%
kable(caption= "Title",
digits = c(0,rep(3,5))) %>%
kable_styling(full_width=F, position="center",
bootstrap_options = c("striped"))%>%
add_header_above(c("", "Group" = 5))
Generates this:
Thanks!
It's better to use 'htmlTable' or 'huxtable' for output expss tables. It is because they are both support complex multilevel and multinested headers.
However, if you want to use 'kable' you can set first column name to empty string just after 'tab_pivot':
library(expss)
library(knitr)
library(kableExtra)
# function which remove first column name
remove_first_name = function(x){
setNames(x, c("", names(x)[-1]))
}
df <- data.frame(x=rbinom(100,1,0.5), y=rnorm(100,1,0.6),
z=rnorm(100,1,0.2), grp = rep(1:5,20))
var_lab(df$grp) = ""
df %>%
tab_cells(x,y,z) %>%
tab_cols(grp) %>%
tab_stat_mean (label = "") %>%
tab_pivot %>%
remove_first_name %>% # remove 'row_labels'
kable(caption= "Title",
digits = c(0,rep(3,5))) %>%
kable_styling(full_width=F, position="center",
bootstrap_options = c("striped"))%>%
add_header_above(c("", "Group" = 5))

How to add hyperlink into a popup in leaflet? (urls stored in table)

I have a table in which one of the columns is website urls, how do I add hyperlink with these urls in a popup in leaflet?
here is my code:
content <- paste(sep = "\n",
my_table$names,
my_table$websites)
my_map <- leaflet(my_table) %>%
setView(lng = -98.583, lat = 39.833, zoom = 4) %>%
addTiles() %>%
addProviderTiles(providers$Wikimedia) %>%
addMarkers(
clusterOptions = markerClusterOptions(),
popup = htmlEscape(content),
icon = my_icon
)
I changed the way you are calling the content object a bit to paste the html code for creating a hyperlink, with quotes, around the columns in your dataframe.
content <- yourDataframe %>%
mutate(popup = paste0('<a href =', websites, '>', names, '</a>'))
my_map <- leaflet(my_table) %>%
setView(lng = -98.583, lat = 39.833, zoom = 4) %>%
addTiles() %>%
addProviderTiles(providers$Wikimedia) %>%
addMarkers(lng = content $longitude,
lat = content $latitude,
clusterOptions = markerClusterOptions(),
popup = content$popup)

Total distance of route using Leaflet routing machine in rMaps/rCharts

I would like to produce a shiny app that asks for two addresses, maps an efficient route, and calculates the total distance of the route. This can be done using the Leaflet Routing Machine using the javascript library, however I would like to do a bunch of further calculations with the distance of the route and have it all embedded in a shiny app.
You can produce the map using rMaps by following this demo by Ramnathv here. But I'm not able to pull out the total distance travelled even though I can see that it has been calculated in the legend or controller. There exists another discussion on how to do this using the javascript library - see here. They discuss using this javascript code:
alert('Distance: ' + routes[0].summary.totalDistance);
Here is my working code for the rMap. If anyone has any ideas for how to pull out the total distance of a route and store it, I would be very grateful. Thank you!
# INSTALL DEPENDENCIES IF YOU HAVEN'T ALREADY DONE SO
library(devtools)
install_github("ramnathv/rCharts#dev")
install_github("ramnathv/rMaps")
# CREATE FUNCTION to convert address to coordinates
library(RCurl)
library(RJSONIO)
construct.geocode.url <- function(address, return.call = "json", sensor = "false") {
root <- "http://maps.google.com/maps/api/geocode/"
u <- paste(root, return.call, "?address=", address, "&sensor=", sensor, sep = "")
return(URLencode(u))
}
gGeoCode <- function(address,verbose=FALSE) {
if(verbose) cat(address,"\n")
u <- construct.geocode.url(address)
doc <- getURL(u)
x <- fromJSON(doc)
if(x$status=="OK") {
lat <- x$results[[1]]$geometry$location$lat
lng <- x$results[[1]]$geometry$location$lng
return(c(lat, lng))
} else {
return(c(NA,NA))
}
}
# GET COORDINATES
x <- gGeoCode("Vancouver, BC")
way1 <- gGeoCode("645 East Hastings Street, Vancouver, BC")
way2 <- gGeoCode("2095 Commercial Drive, Vancouver, BC")
# PRODUCE MAP
library(rMaps)
map = Leaflet$new()
map$setView(c(x[1], x[2]), 16)
map$tileLayer(provider = 'Stamen.TonerLite')
mywaypoints = list(c(way1[1], way1[2]), c(way2[1], way2[2]))
map$addAssets(
css = "http://www.liedman.net/leaflet-routing-machine/dist/leaflet-routing-machine.css",
jshead = "http://www.liedman.net/leaflet-routing-machine/dist/leaflet-routing-machine.js"
)
routingTemplate = "
<script>
var mywaypoints = %s
L.Routing.control({
waypoints: [
L.latLng.apply(null, mywaypoints[0]),
L.latLng.apply(null, mywaypoints[1])
]
}).addTo(map);
</script>"
map$setTemplate(
afterScript = sprintf(routingTemplate, RJSONIO::toJSON(mywaypoints))
)
# map$set(width = 800, height = 800)
map
You can easily create a route via the google maps api. The returned data frame will have distance info. Just sum up the legs for total distance.
library(ggmap)
x <- gGeoCode("Vancouver, BC")
way1txt <- "645 East Hastings Street, Vancouver, BC"
way2txt <- "2095 Commercial Drive, Vancouver, BC"
route_df <- route(way1txt, way2txt, structure = 'route')
dist<-sum(route_df[,1],na.rm=T) # total distance in meters
#
qmap(c(x[2],x[1]), zoom = 12) +
geom_path(aes(x = lon, y = lat), colour = 'red', size = 1.5, data = route_df, lineend = 'round')