Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

leaflet add multiple polylines

Tags:

r

leaflet

I have seen similar questions but so far none that fit my needs (at least to the extent I understand them) so I will apologize in advance if this has already been answered. I am also kind of an R novice.

I have a data frame containing two sets of Lat/Lon in each row. The actual data contains hundreds of rows and many columns of related data. I am plotting the points for both sets of Lat/Lon and want to draw lines connecting each pair as a separate line. Here is an example of what the results should look like.

[![enter image description here][1]][1]

Here is a simplified example of the data. There will be duplicate Event and Location values.

Event_lat   Event_lon   Event   Location    Location_latitude   Location_longitude
40.791151   -124.054008 704832643   60005   40.790961   -124.1825609
38.900882   -122.660353 704653051   60009   38.873889   -122.709722
38.921488   -122.600049 704681147   60011   38.85111099 -122.593333
38.921488   -122.600049 704681147   60011   38.85111099 -122.593333
39.141877   -123.044724 706777142   60012   39.22794396 -123.064722
38.928113   -122.611386 708644013   60016   38.98950003 -122.7695828
39.02361    -122.72195  708582623   60016   38.98950003 -122.7695828
38.87586    -122.842684 708336092   60016   38.98950003 -122.7695828
39.239926   -123.145497 709020144   60017   39.24138798 -123.2163878
39.3307 -123.221674 708875205   60017   39.24138798 -123.2163878

Here is a simplified sample of the code to map the points:

library(leaflet)
myData <-read.csv("Book1.csv",header=TRUE, sep=",")
leaflet()%>%
  addTiles() %>%
  addCircles(myData,lng = myData$lsr_lon,lat = myData$lsr_lat, radius=20, color = "red",group = "events") %>% 
  addCircles(myData,lng = myData$site_longitude,lat = myData$site_latitude, radius=20, color = "blue",group = 'Locations')
like image 225
David Wilkes Avatar asked Jan 27 '23 22:01

David Wilkes


2 Answers

I propose a solution using library(sf) and library(data.table), where sf has superseeded sp, and data.table is used for efficient reshaping of data.

I am using the data provided by Wimpel in their solution.

Reshaping

Creating an sf object is fairly straight forward. We need to create a LINESTRING for each row of your data (as an sfg object), then convert to sf

library(sf)
library(data.table)

setDT(df)   

## create an 'id' / index value. This assumes each row of your data is a separate line. 
df[, idx := .I]

## create an `sfc` column (where each row is an `sfg` object)
sf <- df[
    , {
        geometry <- sf::st_linestring(x = matrix(c(Event_lon, Event_lat, Location_longitude, Location_latitude), ncol = 2, byrow = T))
        geometry <- sf::st_sfc(geometry)
        geometry <- sf::st_sf(geometry = geometry)
    }
    , by = idx
]

## convert to sf
sf <- sf::st_as_sf(sf)

Plotting

With this sf object you can now plot in leaflet (using similar code to Wimpel)

library(leaflet)

leaflet() %>%
    addTiles() %>%
    addPolylines(data = sf) %>%
    addCircles(data = df, lng = ~Event_lon, lat = ~Event_lat, radius=20, color = "red", group = "events") %>% 
    addCircles(data = df, lng = ~Location_longitude, lat = ~Location_latitude, radius=20, color = "blue", group = 'Locations') 

enter image description here

like image 106
SymbolixAU Avatar answered Feb 11 '23 00:02

SymbolixAU


I myself am just starting with geographic use of R and leaflet, so this probably is not the most efficient way to approach this problem.. Nevertheless it is working fine for me... Feedback is always welcome!

result

result

sample data

df <- read.table( text = "Event_lat   Event_lon   Event   Location    Location_latitude   Location_longitude
40.791151   -124.054008 704832643   60005   40.790961   -124.1825609
38.900882   -122.660353 704653051   60009   38.873889   -122.709722
38.921488   -122.600049 704681147   60011   38.85111099 -122.593333
38.921488   -122.600049 704681147   60011   38.85111099 -122.593333
39.141877   -123.044724 706777142   60012   39.22794396 -123.064722
38.928113   -122.611386 708644013   60016   38.98950003 -122.7695828
39.02361    -122.72195  708582623   60016   38.98950003 -122.7695828
38.87586    -122.842684 708336092   60016   38.98950003 -122.7695828
39.239926   -123.145497 709020144   60017   39.24138798 -123.2163878
39.3307 -123.221674 708875205   60017   39.24138798 -123.2163878", header = TRUE)

code

I want to create a spatiallines-object, that I can draw in leaflet with addPolylines.

First, i want to create a data.frame with lat/lon only, with a unique id per combination of event-location.

library(tidyverse)
#craete a column with unique id's per event-location combination
df <- df %>% mutate( id = row_number() )
#create a temporaty df with events
events.df <- df %>% 
  select( id, Event_lat, Event_lon) %>% 
  rename( latitude = Event_lat, longitude = Event_lon)
#create a temporaty df with locations
locations.df <- df %>% 
  select( id, Location_latitude, Location_longitude) %>%
  rename( latitude = Location_latitude, longitude = Location_longitude)
#merge the two temp.df's together
df.sp <- bind_rows( events.df, locations.df )

#    id latitude longitude
# 1   1 40.79115 -124.0540
# 2   2 38.90088 -122.6604
# 3   3 38.92149 -122.6000
# 4   4 38.92149 -122.6000
# 5   5 39.14188 -123.0447
# 6   6 38.92811 -122.6114
# 7   7 39.02361 -122.7220
# 8   8 38.87586 -122.8427
# 9   9 39.23993 -123.1455
# 10 10 39.33070 -123.2217
# 11  1 40.79096 -124.1826
# 12  2 38.87389 -122.7097
# 13  3 38.85111 -122.5933
# 14  4 38.85111 -122.5933
# 15  5 39.22794 -123.0647
# 16  6 38.98950 -122.7696
# 17  7 38.98950 -122.7696
# 18  8 38.98950 -122.7696
# 19  9 39.24139 -123.2164
# 20 10 39.24139 -123.2164

Now to create the spatialLines-object

library(maptools)
library(sp)
#make df.sp a spatialdataframe
coordinates( df.sp ) <- c( "longitude", "latitude" )

#create a list per id
id.list <- sp::split( df.sp, df.sp[["id"]] )

#initialisation of counter
id <- 1

#for each id, create a line that connects all points with that id
for ( i in id.list ) {
  event.lines <- SpatialLines( list( Lines( Line( i[1]@coords ), ID = id ) ),
                               proj4string = CRS( "+init=epsg:4326" ) )
  if ( id == 1 ) {
    sp_lines  <- event.lines
  } else {
    sp_lines  <- spRbind( sp_lines, event.lines )
  }
  id <- id + 1
}

check.

head(sp_lines,1)

# An object of class "SpatialLines"
# Slot "lines":
#   [[1]]
# An object of class "Lines"
# Slot "Lines":
#   [[1]]
# An object of class "Line"
# Slot "coords":
#   longitude latitude
# [1,] -124.0540 40.79115
# [2,] -124.1826 40.79096
# 
# Slot "ID":
#   [1] "1"
# 
# Slot "bbox":
#   min        max
# x -124.18256 -124.05401
# y   40.79096   40.79115
# 
# Slot "proj4string":
#   CRS arguments:
#   +init=epsg:4326 +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 

Now, draw the points and the polylines in leaflet

library(leaflet)
leaflet()%>%
  addTiles() %>%
  addCircles(df,lng = df$Event_lon, lat = df$Event_lat, radius=20, color = "red", group = "events") %>% 
  addCircles(df,lng = df$Location_longitude, lat = df$Location_latitude, radius=20, color = "blue", group = 'Locations') %>%
  addPolylines( data = sp_lines )
like image 26
Wimpel Avatar answered Feb 10 '23 22:02

Wimpel