How to add geo-spatial connections on a ggplot map

2020-02-11 12:40发布

Using this as a reference, I'm trying to plot a map of the lower forty-eight and add layers to visualize flow between states.

library(ggplot2)
library(maps)
library(geosphere) # to inter-polate a given pair of (lat,long) on the globe

# load map data for the US
all_states <- map_data("state")

# plot state map
p <- ggplot() + geom_polygon( data=all_states, 
                       aes(x=long, y=lat, group = group),
                       colour="white", fill="grey10" )

# sample origin - destination lat,long pairs
geo <- structure(list(orig_lat = c(36.17, 36.17, 36.17), 
orig_lon = c(-119.7462, -119.7462, -119.7462), dest_lat = c(33.7712, 36.17, 39.0646), 
    dest_lon = c(-111.3877, -119.7462, -105.3272)), .Names = c("orig_lat", 
"orig_lon", "dest_lat", "dest_lon"), row.names = c(NA, 3L), class = "data.frame")

#> geo
#  orig_lat  orig_lon dest_lat  dest_lon
#1    36.17 -119.7462  33.7712 -111.3877
#2    36.17 -119.7462  36.1700 -119.7462
#3    36.17 -119.7462  39.0646 -105.3272

# list to hold a dataframe of interpolated points for each origin-destination pair
list_lines <- list()

# use the geosphere package's gcIntermediate function to generate 50 interpolated  
# points for each origin-destination pair
for (i in 1:3) {
  inter <- as.data.frame(gcIntermediate(c(geo[i,]$orig_lon, geo[i,]$orig_lat), 
                                        c(geo[i,]$dest_lon, geo[i,]$dest_lat), 
                                        n=50, addStartEnd=TRUE))
  list_lines[i] <- list(inter)
  p <- p + geom_line( data = list_lines[[i]], aes(x = lon, y = lat), color = '#FFFFFF')
}
p

Here is what I get when I try to print the plot

p
Error in eval(expr, envir, enclos) : object 'lon' not found

I tried to debug this and found that this works

p + geom_line( data = list_lines[[1]], aes(x = lon, y = lat), color = '#FFFFFF')

but adding another layer for the second list element breaks it, but that's as far as I could get with my limited knowledge of both R and ggplot!

3条回答
ゆ 、 Hurt°
2楼-- · 2020-02-11 13:17

There is a really simple solution using ggplot2. There is simple tutorial of how to plot flow maps in R using ggplot2, here.

p + 
  geom_segment(data = geo, aes(x = orig_lon,    y = orig_lat, 
                               xend = dest_lon, yend = dest_lat,
                               color="#FFFFFF")) +  coord_equal()

enter image description here

查看更多
女痞
3楼-- · 2020-02-11 13:23

What strikes me as odd is that you refer to the longitude in two different ways: long in the beginning of the script, and lon in the end. You need to get these names consistent if you expect multiple geom's to work together.

In addition, adding identical geom's with for loops is almost never needed. Just add a single geom_line and use the color aesthetic to draw multiple lines.

查看更多
你好瞎i
4楼-- · 2020-02-11 13:24

gcIntermediate returns different column names (since origin and destination is identical for i=2):

for (i in 1:3) {
  inter <- as.data.frame(gcIntermediate(c(geo[i,]$orig_lon, geo[i,]$orig_lat), 
                                        c(geo[i,]$dest_lon, geo[i,]$dest_lat), 
                                        n=50, addStartEnd=TRUE))
  print(head(inter, n=2))
}
     lon   lat
1 -119.7 36.17
2 -119.6 36.13
      V1    V2
1 -119.7 36.17
2 -119.7 36.17
     lon   lat
1 -119.7 36.17
2 -119.5 36.24

The following lines should work:

for (i in 1:3) {
  inter <- as.data.frame(gcIntermediate(c(geo[i,]$orig_lon, geo[i,]$orig_lat), 
                                        c(geo[i,]$dest_lon, geo[i,]$dest_lat), 
                                        n=50, addStartEnd=TRUE))
  names(inter) <- c("lon", "lat")
  p <- p + geom_line(data=inter, aes(x=lon, y=lat), color='#FFFFFF')
}
查看更多
登录 后发表回答