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

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')

Related

plotly r sankey add_trace

i am reading the document https://plotly.com/r/reference/sankey/, and want to change the links color for a sankey chart. But i can't quite understand the parameters in add_trace() function
where should i specify the color value?
add_trace(p,type='sankey', color=????)
You haven't provided a minimal reproducible example, so I can't jump right into your code. But I think I can point you in the right direction.
In the documentation you screenshotted, it's saying that the color argument is one key of the list link that defines links in the plot. Using this example from the R plotly documentation for adding links, let's take a look at where that goes:
library(plotly)
library(rjson)
json_file <- "https://raw.githubusercontent.com/plotly/plotly.js/master/test/image/mocks/sankey_energy.json"
json_data <- fromJSON(paste(readLines(json_file), collapse=""))
fig <- plot_ly(
type = "sankey",
domain = list(
x = c(0,1),
y = c(0,1)
),
orientation = "h",
valueformat = ".0f",
valuesuffix = "TWh",
node = list(
label = json_data$data[[1]]$node$label,
color = json_data$data[[1]]$node$color,
pad = 15,
thickness = 15,
line = list(
color = "black",
width = 0.5
)
),
link = list(
source = json_data$data[[1]]$link$source,
target = json_data$data[[1]]$link$target,
value = json_data$data[[1]]$link$value,
label = json_data$data[[1]]$link$label,
#### Color goes here! ####
color = "yellow"
)
)
fig <- fig %>% layout(
title = "Energy forecast for 2050<br>Source: Department of Energy & Climate Change, Tom Counsell via <a href='https://bost.ocks.org/mike/sankey/'>Mike Bostock</a>",
font = list(
size = 10
),
xaxis = list(showgrid = F, zeroline = F),
yaxis = list(showgrid = F, zeroline = F)
)
fig
The plotly documentation can be a bit opaque at times. I have found it helpful to sometimes review the documentation for python. For example, this part of the python documentation does give some more guidance about changing link colors.

I have trouble getting depth information from the DEPTH16 format with the Camera2 API using ToF on P30 pro

I am currently testing options for depth measurement with the smartphone and wanted to create a depth image initially for testing. I am using the Camera2Basic example as a basis for this. (https://github.com/android/camera-samples/tree/main/Camera2Basic) Using Depth16 I get a relatively sharp "depth image" back. But the millimetres are not correct. They are in a range around from 3600mm to 5000mm for an object like a wall that is about 500mm or 800mm away from the camera.
But what puzzles me the most is that the image does not transmit any information in the dark. If Android is really targeting the ToF sensor for DEPTH16, it shouldn't be affected in the dark, should it? Or do I have to use AR-Core or Huawei's HMS core to get a real ToF image?
I am using a Huawei P30 Pro and the code for extracting the depth information looks like this. And yes performance wise it is bullshit but it is only for testing purposes:)
private Map<String, PixelData> parseDepth16IntoDistanceMap(Image image) {
Map<String, PixelData> map = new HashMap();
Image.Plane plane = image.getPlanes()[0];
// using asShortBuffer() like in the documentation leads to a wrong format (for me) but does not help getting better values
ByteBuffer depthBuffer = plane.getBuffer().order(ByteOrder.nativeOrder());
int stride = plane.getRowStride();
int offset = 0;
int i = 0;
for (short y = 0; y < image.getHeight(); y++) {
for (short x = 0; x < image.getWidth(); x++) {
short depthSample = depthBuffer.getShort( (y / 2) * stride + x);
short depthSampleShort = (short) depthSample;
short depthRange = (short) (depthSampleShort & 0x1FFF);
short depthConfidence = (short) ((depthSampleShort >> 13) & 0x7);
float depthPercentage = depthConfidence == 0 ? 1.f : (depthConfidence - 1) / 7.f;
maxz = depthRange;
sum = sum + depthRange;
numPoints++;
listOfRanges.add((float) depthRange);
if (depthRange < minz && depthRange > 0) {
minz = depthRange;
}
map.put(x + "_" + y, new PixelData(x, y, depthRange, depthPercentage));
i++;
}
}
return map;
}
In any case, it would help a lot to know if you can get the data this way at all, so I know if I'm already doing something fundamentally wrong. Otherwise I will change to one of the ar systems. Either way, many thanks for your efforts
If you want to extract a depth map where you can see the distance to an object you might use ARCORE Depth API.
https://developers.google.com/ar/develop/java/depth/overview
Or you can follow the codelab where shows you how to get the data in millimeters.
https://codelabs.developers.google.com/codelabs/arcore-depth#0

R Shiny app with Leaflet map not centering on selected point

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)

How to implement a Slope graph in R for two variables

I'm analyzing how many users have used a particular hashtag and how they have contributed to the total number of tweets. My results are:
Data:
20.68% of tweets related to #HashtagX are created by 20 users. Now, these 20 users only represent 0.001% of the total of 14,432 users who have ever used the hashtag #HashtagX.
What happens if we take the top 100 users by number of tweets? 44% of tweets are created by the top 100 users.
If we extend to the top 500 users by number of users we see that 72% of tweets is created by the top 500.
I am wondering how to implement a slope graph because I think that is a good way to show the relationship between both variables, but it is not a default graph provides for any library.
One of the ways to show the relationship between both variables ("Users" vs "Tweets") is a Slope Chart.
Visualization obtained (solved graph for the question):
Slope Chart
1) Libraries
library(ggplot2)
library(scales)
library(ggrepel)
theme_set(theme_classic())
2) Data example
Country = c('20 accounts', '50 accounts', '100 accounts','200 accounts','300 accounts',
'500 accounts','1000 accounts','14.443 accounts')
January = c(0.14, 0.34, 0.69,1.38,2.07,3.46,6.92,100)
April = c(20.68, 33.61, 44.94, 57.49,64.11,72,80,100)
Tweets_N = c(26797, 43547, 58211, 74472,83052,93259,103898,129529)
a = data.frame(Country, January, April)
left_label <- paste(a$Country, paste0(a$January,"%"),sep=" | ")
right_label <- paste(paste0(round(a$April),"%"),paste0(Tweets_N," tweets"),sep=" | ")
a$color_class <- "green"
3) Plot
p <- ggplot(a) + geom_segment(aes(x=1, xend=2, y=January, yend=April, col=color_class), size=.25, show.legend=F) +
geom_vline(xintercept=1, linetype="dashed", size=.1) +
geom_vline(xintercept=2, linetype="dashed", size=.1) +
scale_color_manual(labels = c("Up", "Down"),
values = c("blue", "red")) +
labs(
x="", y = "Percentage") +
xlim(.5, 2.5) + ylim(0,(1.1*(max(a$January, a$April)))) # X and Y axis limits
# Add texts
p <- p + geom_text_repel(label=left_label, y=a$January, x=rep(1, NROW(a)), hjust=1.1, size=3.5,direction = "y")
p <- p + geom_text(label=right_label, y=a$April, x=rep(2, NROW(a)), hjust=-0.1, size=3.5)
p <- p + geom_text(label="Accounts", x=1, y=1.1*(max(a$January, a$April)), hjust=1.2, size=4, check_overlap = TRUE) # title
p <- p + geom_text(label="Tweeets (% of Total)", x=2, y=1.1*(max(a$January, a$April)), hjust=-0.1, size=4, check_overlap = TRUE)
# title
# Minify theme
p + theme(panel.background = element_blank(),
panel.grid = element_blank(),
axis.ticks = element_blank(),
axis.text.x = element_blank(),
panel.border = element_blank(),
plot.margin = unit(c(1,2,1,2), "cm"))

Tableau Address Geocoding

I want to build a dashboard where I can search by any address in the U.S., have it geocoded by Tableau, and then filter a dataset based on a 1-5 mile radius from that address. Does Tableau have the capability to do this, or do I need a third party app to accomodate the address search feature / geocoding.
Unfortunately, Tableau's built-in logic only supports the identification of things like cities and zip codes. If you want more granular location visuals (street addresses and such), you will need geocode yourself prior to building your datasource.
onlinehelp.tableau.com
In the past, I've done this with some simple python code and ArcGIS:
import pandas as pd
import numpy as np
import geopy
from geopy.geocoders import ArcGIS
#csv with street addresses, cities, states, and zip
file_loc = "C:/Documents/data.csv"
df = pd.read_csv(file_loc, na_values=None,
dtype = {'STREET': object, 'CITY': object, 'STATE': object, 'ZIP': object})
df = df.fillna('')
street = df['STREET'].map(str)
city = df['CITY'].map(str)
state = df['STATE'].map(str)
zip = df['ZIP'].map(str)
addr = street + ' ' + city + ' ' + state + ' ' + zip
df['ADDRESS'] = addr
addresses = df['ADDRESS'].unique()
geolocator = ArcGIS()
addr_list = []
for a in addresses:
temp_dict = {}
loc = geolocator.geocode(a,timeout = 5)
if loc:
temp_dict['LAT'] = loc.latitude
temp_dict['LONG'] = loc.longitude
temp_dict['ADDR'] = loc.address
temp_dict['ADDRESS'] = a
else:
temp_dict['LAT'] = None
temp_dict['LONG'] = None
temp_dict['ADDR'] = None
temp_dict['ADDRESS'] = a
addr_list.append(temp_dict)
addr_df = pd.DataFrame(addr_list)
df = df.merge(addr_df, on='ADDRESS', how='left')
writer = pd.ExcelWriter('outdate.xlsx')
df.to_excel(writer,'Sheet1',index=False)
writer.save()