libreria - ¿Cómo conecto dos coordenadas con una línea usando Leaflet en R?
leaflet() (5)
Estoy tratando de usar Leaflet package en R para dibujar un amplificador y conectar los marcadores dada la información de latitud y longitud en la tabla a continuación.
| Observation | InitialLat | InitialLong | NewLat | NewLong | |-------------|------------|-------------|-----------|-----------| | A | 62.469722 | 6.187194 | 51.4749 | -0.221619 | | B | 48.0975 | 16.3108 | 51.4882 | -0.302621 | | C | 36.84 | -2.435278 | 50.861822 | -0.083278 | | D | 50.834194 | 4.298361 | 54.9756 | -1.62179 | | E | 50.834194 | 4.298361 | 54.9756 | -1.62179 | | F | 50.834194 | 4.298361 | 51.4882 | -0.302621 | | G | 47.460427 | -0.530804 | 51.44 | -2.62021 | | H | 51.5549 | -0.108436 | 53.4281 | -1.36172 | | I | 51.5549 | -0.108436 | 52.9399 | -1.13258 | | J | 51.5549 | -0.108436 | 51.889839 | -0.193608 | | | 51.5549 | -0.108436 | 52.0544 | 1.14554 |
Quiero dibujar líneas desde un punto inicial dado por las coordenadas en las columnas InitialLat
y InitialLong
hasta un punto final dado por las columnas NewLat
y NewLong
.
Aquí está mi código R actual que solo dibuja los marcadores en el mapa.
library(leaflet) map3 = leaflet(data) %>% addTiles() map3 %>% addMarkers(~InitialLong,~InitialLat, popup=~Observation)
Aquí hay una forma alternativa utilizando el paquete de leaflet
. Acabo de tomar dos puntos de datos en sus datos para fines de demostración.
mydf <- data.frame(Observation = c("A", "B"),
InitialLat = c(62.469722,48.0975),
InitialLong = c(6.187194, 16.3108),
NewLat = c(51.4749, 51.4882),
NewLong = c(-0.221619, -0.302621),
stringsAsFactors = FALSE)
Cambié el formato de mydf
y mydf
un nuevo marco de datos para el folleto. Puedes remodelar tus datos de varias maneras.
mydf2 <- data.frame(group = c("A", "B"),
lat = c(mydf$InitialLat, mydf$NewLat),
long = c(mydf$InitialLong, mydf$NewLong))
# group lat long
#1 A 62.46972 6.187194
#2 B 48.09750 16.310800
#3 A 51.47490 -0.221619
#4 B 51.48820 -0.302621
library(leaflet)
library(magrittr)
leaflet()%>%
addTiles() %>%
addPolylines(data = mydf2, lng = ~long, lat = ~lat, group = ~group)
Recorté el mapa interactivo que obtuve. Por favor vea el mapa de abajo. Aunque dos líneas están conectadas en esta imagen, están separadas. Si ejecuta el código y amplía, verá que las dos líneas están separadas.
Dependiendo de cuál sea el propósito de las líneas, otra gran opción es gcIntermediate (). Produce un objeto CURVED SpatialLines, basado en la curvatura de la tierra. Aunque no es genial para las direcciones. Los objetos de clase SpatialLines funcionan muy bien con Leaflet. Vea here para un excelente ejemplo. He publicado un formulario modificado, que comienza con el marco de datos de Paul Reiners.
library(leaflet)
library(geosphere)
mydf <- data.frame(InitialLat = c(62.469722,48.0975), # initial df
InitialLong = c(6.187194, 16.3108),
NewLat = c(51.4749, 51.4882),
NewLong = c(-0.221619, -0.302621))
p1 <- as.matrix(mydf[,c(2,1)]) # it''s important to list lng before lat here
p2 <- as.matrix(mydf[,c(4,3)]) # and here
gcIntermediate(p1, p2,
n=100,
addStartEnd=TRUE,
sp=TRUE) %>%
leaflet() %>%
addTiles() %>%
addPolylines()
El folleto puede agregar líneas usando la función addPolylines
. El problema con esto es que asume que todas las líneas están conectadas, las tendrá todas vinculadas.
La mejor manera de solucionar esto (AFAIK) es usar un bucle:
library(leaflet)
map3 = leaflet(data) %>% addTiles()
map3 <- map3 %>% addMarkers(~InitialLong,~InitialLat, popup=~Observation)
for(i in 1:nrow(data)){
map3 <- addPolylines(map3, lat = as.numeric(data[i, c(2, 4)]),
lng = as.numeric(data[i, c(3, 5)]))
}
map3
EDITAR: También hay una forma más fácil de usar la función points_to_line de Kyle Walker (consulte la parte inferior para obtener una copia pegada del código).
Primero reformule los datos, de modo que los comienzos y finales estén en las mismas columnas:
library(tidyr)
library(dplyr)
z <- gather(dta, measure, val, -Observation) %>% group_by(Observation) %>%
do(data.frame( lat=c(.[["val"]][.[["measure"]]=="InitialLat"],
.[["val"]][.[["measure"]]=="NewLat"]),
long = c(.[["val"]][.[["measure"]]=="InitialLong"],
.[["val"]][.[["measure"]]=="NewLong"])))
Entonces llama a points_to_line
z <- as.data.frame(z)
y <- points_to_line(z, "long", "lat", "Observation")
Ahora trama:
map3 = leaflet(data) %>% addTiles()
map3 %>% addMarkers(~InitialLong, ~InitialLat, popup = ~Observation) %>%
addPolylines(data = y)
Fuente de points_to_line por Kyle Walker:
library(sp)
library(maptools)
points_to_line <- function(data, long, lat, id_field = NULL, sort_field = NULL) {
# Convert to SpatialPointsDataFrame
coordinates(data) <- c(long, lat)
# If there is a sort field...
if (!is.null(sort_field)) {
if (!is.null(id_field)) {
data <- data[order(data[[id_field]], data[[sort_field]]), ]
} else {
data <- data[order(data[[sort_field]]), ]
}
}
# If there is only one path...
if (is.null(id_field)) {
lines <- SpatialLines(list(Lines(list(Line(data)), "id")))
return(lines)
# Now, if we have multiple lines...
} else if (!is.null(id_field)) {
# Split into a list by ID field
paths <- sp::split(data, data[[id_field]])
sp_lines <- SpatialLines(list(Lines(list(Line(paths[[1]])), "line1")))
# I like for loops, what can I say...
for (p in 2:length(paths)) {
id <- paste0("line", as.character(p))
l <- SpatialLines(list(Lines(list(Line(paths[[p]])), id)))
sp_lines <- spRbind(sp_lines, l)
}
return(sp_lines)
}
}
Piensa que esto es lo que quieres:
install.packages("leaflet")
library(leaflet)
mydf <- data.frame(Observation = c("A", "B","C","D","E"),
InitialLat = c(62.469722,48.0975,36.84,50.834194,50.834194),
InitialLong = c(6.187194, 16.3108,-2.435278,4.298361,4.298361),
NewLat = c(51.4749, 51.4882,50.861822,54.9756,54.9756),
NewLong = c(-0.221619, -0.302621,-0.083278,-1.62179,-1.62179),
stringsAsFactors = FALSE)
mydf
Observation InitialLat InitialLong NewLat NewLong
1 A 62.46972 6.187194 51.47490 -0.221619
2 B 48.09750 16.310800 51.48820 -0.302621
3 C 36.84000 -2.435278 50.86182 -0.083278
4 D 50.83419 4.298361 54.97560 -1.621790
5 E 50.83419 4.298361 54.97560 -1.621790
m<-leaflet(data=mydf)%>%addTiles
for (i in 1:nrow(mydf))
m<-m%>%addPolylines(lat=c(mydf[i,]$InitialLat,mydf[i,]$NewLat),lng=c(mydf[i,]$InitialLong,mydf[i,]$NewLong))
Y se muestra: Conexión de red utilizando Folleto.
Sé que esto se solicitó hace un año, pero tenía la misma pregunta y descubrí cómo hacerlo en un folleto.
Primero tendrá que ajustar su marco de datos porque addPolyline simplemente conecta todas las coordenadas en una secuencia. Haré un marco de datos con 4 ubicaciones finales diferentes para el propósito de esta demostración.
dest_df <- data.frame (lat = c(41.82, 46.88, 41.48, 39.14),
lon = c(-88.32, -124.10, -88.33, -114.90)
)
A continuación, voy a crear un marco de datos con la ubicación central del mismo tamaño (4 en este ejemplo) de las ubicaciones de destino. Explicaré por qué estoy haciendo esto pronto.
orig_df <- data.frame (lat = c(rep.int(40.75, nrow(dest_df))),
long = c(rep.int(-73.99,nrow(dest_df)))
)
La razón por la que estoy haciendo esto es porque la función addPolylines conectará todas las coordenadas en una secuencia. La forma de evitar esto para crear la imagen que describió es comenzar en el punto de inicio, luego ir al punto de destino, y luego volver al punto de inicio, y luego al siguiente punto de destino. Para crear el marco de datos para hacer esto, tendremos que entrelazar los dos marcos de datos colocando filas como tales:
punto de partida - punto de destino 1 - punto de partida - punto de destino 2 - y así sucesivamente ...
La forma en que lo haré es crear una clave para ambos marcos de datos. Para el marco de datos de origen, comenzaré en 1 y aumentaré en 2 (por ejemplo, 1 3 5 7). Para el marco de datos de destino, comenzaré en 2 y aumentaré en 2 (por ejemplo, 2, 4, 6, 8). Luego combinaré los 2 marcos de datos usando un UNION all. Luego ordenaré según mi secuencia para que cada fila sea el punto de partida. Voy a usar sqldf para esto porque eso es con lo que me siento cómodo. Puede haber una forma más eficiente.
orig_df$sequence <- c(sequence = seq(1, length.out = nrow(orig_df), by=2))
dest_df$sequence <- c(sequence = seq(2, length.out = nrow(orig_df), by=2))
library("sqldf")
q <- "
SELECT * FROM orig_df
UNION ALL
SELECT * FROM dest_df
ORDER BY sequence
"
poly_df <- sqldf(q)
El nuevo marco de datos tiene este aspecto. Observe cómo las ubicaciones de origen se entrelazan entre el destino.
Y finalmente, puedes hacer tu mapa:
library("leaflet")
leaflet() %>%
addTiles() %>%
addPolylines(
data = poly_df,
lng = ~lon,
lat = ~lat,
weight = 3,
opacity = 3
)
Y, finalmente, debería tener este aspecto . Espero que esto ayude a cualquiera que esté buscando hacer algo como esto en el futuro.