【问题标题】:Flow map(Travel Path) Using Lat and Long in R在 R 中使用 Lat 和 Long 的流程图(旅行路径)
【发布时间】:2017-11-01 04:47:35
【问题描述】:

我正在尝试绘制流程图(新加坡)。我有入口(纬度,经度)和出口(纬度,经度)。我正在尝试在新加坡地图中绘制从入口到出口的流程。

structure(list(token_id = c(1.12374e+19, 1.12374e+19, 1.81313e+19, 
1.85075e+19, 1.30752e+19, 1.30752e+19, 1.32828e+19, 1.70088e+19, 
1.70088e+19, 1.70088e+19, 1.05536e+19, 1.44818e+19, 1.44736e+19, 
1.44736e+19, 1.44736e+19, 1.44736e+19, 1.89909e+19, 1.15795e+19, 
1.15795e+19, 1.15795e+19, 1.70234e+19, 1.70234e+19, 1.44062e+19, 
1.21512e+19, 1.21512e+19, 1.95909e+19, 1.95909e+19, 1.50179e+19, 
1.50179e+19, 1.24174e+19, 1.36445e+19, 1.98549e+19, 1.92068e+19, 
1.18468e+19, 1.18468e+19, 1.92409e+19, 1.92409e+19, 1.21387e+19, 
1.9162e+19, 1.9162e+19, 1.40385e+19, 1.40385e+19, 1.32996e+19, 
1.32996e+19, 1.69103e+19, 1.69103e+19, 1.57387e+19, 1.40552e+19, 
1.40552e+19, 1.00302e+19), Entry_Station_Lat = c(1.31509, 1.33261, 
1.28425, 1.31812, 1.33858, 1.29287, 1.39692, 1.37773, 1.33858, 
1.33322, 1.28179, 1.30036, 1.43697, 1.39752, 1.27637, 1.39752, 
1.41747, 1.35733, 1.28405, 1.37773, 1.35898, 1.42948, 1.32774, 
1.42948, 1.349, 1.36017, 1.34971, 1.38451, 1.31509, 1.31509, 
1.37002, 1.34971, 1.31231, 1.39169, 1.31812, 1.44909, 1.29341, 
1.41747, 1.33759, 1.44062, 1.31509, 1.38451, 1.29461, 1.32388, 
1.41747, 1.27614, 1.39752, 1.39449, 1.33261, 1.31231), Entry_Station_Long = c(103.76525, 
103.84718, 103.84329, 103.89308, 103.70611, 103.8526, 103.90902, 
103.76339, 103.70611, 103.74217, 103.859, 103.85563, 103.7865, 
103.74745, 103.84596, 103.74745, 103.83298, 103.9884, 103.85152, 
103.76339, 103.75191, 103.83505, 103.67828, 103.83505, 103.74956, 
103.88504, 103.87326, 103.74437, 103.76525, 103.76525, 103.84955, 
103.87326, 103.83793, 103.89548, 103.89308, 103.82004, 103.78479, 
103.83298, 103.69742, 103.80098, 103.76525, 103.74437, 103.80605, 
103.93002, 103.83298, 103.79156, 103.74745, 103.90051, 103.84718, 
103.83793), Exit_Station_Lat = structure(c(48L, 34L, 118L, 60L, 
14L, 54L, 10L, 49L, 49L, 74L, 71L, 65L, 102L, 5L, 102L, 119L, 
116L, 10L, 13L, 88L, 117L, 66L, 40L, 62L, 117L, 37L, 67L, 34L, 
85L, 44L, 102L, 44L, 115L, 29L, 92L, 17L, 121L, 70L, 120L, 52L, 
85L, 34L, 42L, 11L, 4L, 115L, 62L, 48L, 92L, 14L), .Label = c("1.27082", 
"1.27091", "1.27236", "1.27614", "1.27637", "1.27646", "1.27935", 
"1.28221", "1.28247", "1.28405", "1.28621", "1.28819", "1.28932", 
"1.29287", "1.29309", "1.29338", "1.29341", "1.29461", "1.29694", 
"1.29959", "1.29974", "1.30034", "1.30252", "1.30287", "1.30392", 
"1.30394", "1.30619", "1.30736", "1.30842", "1.31139", "1.3115", 
"1.31167", "1.31188", "1.31509", "1.31654", "1.31756", "1.31913", 
"1.31977", "1.32008", "1.3205", "1.32104", "1.32388", "1.32573", 
"1.32725", "1.32774", "1.33119", "1.33155", "1.33261", "1.33322", 
"1.33474", "1.33554", "1.33759", "1.33764", "1.33858", "1.33921", 
"1.34037", "1.34225", "1.34293", "1.3432", "1.34426", "1.34857", 
"1.349", "1.34905", "1.35158", "1.35733", "1.35898", "1.36017", 
"1.3625", "1.36849", "1.37002", "1.37121", "1.37304", "1.37666", 
"1.37775", "1.3786", "1.37862", "1.38001", "1.38029", "1.3803", 
"1.38178", "1.38269", "1.38295", "1.38399", "1.38423", "1.38451", 
"1.38671", "1.38672", "1.38777", "1.38814", "1.3894", "1.39147", 
"1.39169", "1.39189", "1.39208", "1.39389", "1.39449", "1.39452", 
"1.39628", "1.39692", "1.39717", "1.39732", "1.39752", "1.39821", 
"1.39928", "1.39962", "1.4023", "1.40455", "1.40511", "1.40524", 
"1.40843", "1.40961", "1.41184", "1.41588", "1.41685", "1.41747", 
"1.42526", "1.42948", "1.43256", "1.43697", "1.44062", "1.44909"
), class = "factor"), Exit_Station_Long = structure(c(59L, 19L, 
27L, 4L, 65L, 3L, 63L, 6L, 6L, 21L, 93L, 121L, 9L, 56L, 9L, 32L, 
16L, 63L, 44L, 23L, 50L, 12L, 54L, 11L, 50L, 71L, 87L, 19L, 7L, 
118L, 9L, 118L, 49L, 90L, 96L, 31L, 45L, 61L, 38L, 2L, 7L, 19L, 
117L, 47L, 34L, 49L, 11L, 59L, 96L, 65L), .Label = c("103.67828", 
"103.69742", "103.70611", "103.72092", "103.73274", "103.74217", 
"103.74437", "103.74529", "103.74745", "103.74905", "103.74956", 
"103.75191", "103.7537", "103.75803", "103.76011", "103.76215", 
"103.76237", "103.76449", "103.76525", "103.76648", "103.76667", 
"103.76893", "103.7696", "103.77082", "103.77145", "103.77266", 
"103.774", "103.77866", "103.78185", "103.78425", "103.78479", 
"103.7865", "103.78744", "103.79156", "103.79631", "103.79654", 
"103.79836", "103.80098", "103.803", "103.80605", "103.80745", 
"103.80781", "103.80978", "103.81703", "103.82004", "103.82592", 
"103.82695", "103.83216", "103.83298", "103.83505", "103.83918", 
"103.83953", "103.83974", "103.84387", "103.84496", "103.84596", 
"103.84673", "103.84674", "103.84718", "103.84823", "103.84955", 
"103.85092", "103.85152", "103.85226", "103.8526", "103.85267", 
"103.85436", "103.85446", "103.85452", "103.86088", "103.86149", 
"103.86275", "103.86291", "103.86395", "103.86405", "103.86896", 
"103.87087", "103.87135", "103.87534", "103.87563", "103.8763", 
"103.87971", "103.88003", "103.88126", "103.88243", "103.88296", 
"103.88504", "103.8858", "103.88816", "103.8886", "103.88934", 
"103.89054", "103.89237", "103.89313", "103.8938", "103.89548", 
"103.89719", "103.89723", "103.89854", "103.9003", "103.90051", 
"103.90208", "103.90214", "103.9031", "103.90484", "103.90537", 
"103.90597", "103.90599", "103.90663", "103.9086", "103.90902", 
"103.9126", "103.9127", "103.91296", "103.91616", "103.9165", 
"103.93002", "103.94638", "103.94929", "103.95337", "103.9884"
), class = "factor")), .Names = c("token_id", "Entry_Station_Lat", 
"Entry_Station_Long", "Exit_Station_Lat", "Exit_Station_Long"
), row.names = c(10807L, 10808L, 10810L, 10815L, 10817L, 10818L, 
10819L, 10820L, 10823L, 10824L, 10826L, 10827L, 10829L, 10831L, 
10832L, 10833L, 10834L, 10835L, 10836L, 10838L, 10840L, 10841L, 
10843L, 10847L, 10850L, 10852L, 10854L, 10855L, 10859L, 10861L, 
10869L, 10872L, 10883L, 10886L, 10891L, 10895L, 10896L, 10897L, 
10900L, 10902L, 10903L, 10906L, 10910L, 10911L, 10912L, 10913L, 
10915L, 10920L, 10921L, 10924L), class = "data.frame")

我正在尝试得到这样的东西:Map Flow

【问题讨论】:

  • 那么,你的问题是什么?这里没有问题......
  • token_id是分组变量吗?
  • 是的,token id 是分组变量
  • 如果我理解正确,您有不同的用户,例如,他们购买了一日票并多次乘坐。游乐设施是否已在原始数据集中订购。我的代码假设。
  • 是的,他们每天使用同一张卡通勤。这是一个子集。数据集未排序。但我有一个日期变量。我通常希望看到他们旅行的模式。并找出最拥挤的路线

标签: r ggplot2 leaflet gis r-leaflet


【解决方案1】:

我还编写了 mapdeck 库以使这样的可视化更具吸引力*

library(mapdeck)

set_token("MAPBOX_TOKEN")  ## set your mapbox token here

df$Exit_Station_Lat <- as.numeric(as.character(df$Exit_Station_Lat))
df$Exit_Station_Long <- as.numeric(as.character(df$Exit_Station_Long))

mapdeck(
  style = mapdeck_style('dark')
  , location = c(104, 1)
  , zoom = 8
  , pitch = 45
) %>%
  add_arc(
    data = df
    , origin = c("Entry_Station_Long", "Entry_Station_Lat")
    , destination = c("Exit_Station_Long", "Exit_Station_Lat")
    , layer_id = 'arcs'
    , stroke_from_opacity = 100
    , stroke_to_opacity = 100
    , stroke_width = 3
    , stroke_from = "#ccffff"
    , stroke_to = "#ccffff"
  )

*主观来说

【讨论】:

  • 干得真好
【解决方案2】:

如果您想在实际的 Google 地图上绘制它,并重新创建链接地图的样式,您可以使用我的使用 Google 地图 API 的 googleway 包。您需要 API 密钥才能使用他们的地图

library(googleway)

df$Exit_Station_Lat <- as.numeric(as.character(df$Exit_Station_Lat))
df$Exit_Station_Long <- as.numeric(as.character(df$Exit_Station_Long))

df$polyline <- apply(df, 1, function(x) {
    lat <- c(x['Entry_Station_Lat'], x['Exit_Station_Lat'])
    lon <- c(x['Entry_Station_Long'], x['Exit_Station_Long'])
    encode_pl(lat = lat, lon = lon)
})

mapKey <- 'your_api_key'

style <- '[ { "stylers": [{ "visibility": "simplified"}]},{"stylers": [{"color": "#131314"}]},{"featureType": "water","stylers": [{"color": "#131313"},{"lightness": 7}]},{"elementType": "labels.text.fill","stylers": [{"visibility": "on"},{"lightness": 25}]}]'

google_map(key = mapKey, style = style) %>%
    add_polylines(data = df, 
      polyline = "polyline", 
      mouse_over_group = "Entry_Station_Lat",
      stroke_weight = 0.7,  
      stroke_opacity = 0.5, 
      stroke_colour = "#ccffff")


注意,要使用航班数据重新创建地图,请参阅?add_polylines 中给出的示例


您还可以显示其他类型的路线,例如,通过使用 Google 的 Directions API 对行驶路线进行编码,在不同地点之间行驶。

df$drivingRoute <- lst_directions <- apply(df, 1, function(x){
    orig <- as.numeric(c(x['Entry_Station_Lat'], x['Entry_Station_Long']))
    dest <- as.numeric(c(x['Exit_Station_Lat'], x['Exit_Station_Long']))

    dir <- google_directions(origin = orig, destination = dest, key = apiKey)
    dir$routes$overview_polyline$points
})


google_map(key = mapKey, style = style) %>%
    add_polylines(data = df, 
      polyline = "drivingRoute", 
      mouse_over_group = "Entry_Station_Lat",
      stroke_weight = 0.7,  
      stroke_opacity = 0.5, 
      stroke_colour = "#ccffff")

【讨论】:

  • 这看起来不错。我需要我的可视化来查看一些东西(入口和出口应该指示为一个点,线条应该是弯曲的。更具视觉吸引力。)
【解决方案3】:

使用leafletgeosphere 的替代答案

#get Packages
require(leaflet)
require(geosphere)

#format data
a$Entry_Station_Long = as.numeric(as.character(a$Entry_Station_Long))
a$Entry_Station_Lat = as.numeric(as.character(a$Entry_Station_Lat))
a$Exit_Station_Long = as.numeric(as.character(a$Exit_Station_Long))
a$Exit_Station_Lat = as.numeric(as.character(a$Exit_Station_Lat))
a$id = as.factor(as.numeric(as.factor(a$token_id)))

#create some colors
factpal <- colorFactor(heat.colors(30), pathList$id)

#create a list of interpolated paths
pathList = NULL
for(i in 1:nrow(a))
{
tmp = gcIntermediate(c(a$Entry_Station_Long[i],
                 a$Entry_Station_Lat[i]),
               c(a$Exit_Station_Long[i],
                 a$Exit_Station_Lat[i]),n = 25,
               addStartEnd=TRUE)
tmp = data.frame(tmp)
tmp$id = a[i,]$id
tmp$color = factpal(a[i,]$id)
pathList = c(pathList,list(tmp))
}

#create empty base leaflet object
leaflet() %>% addTiles() -> lf

#add each entry of pathlist to the leaflet object
for (path in pathList)
{
  lf %>% addPolylines(data = path,
                      lng = ~lon, 
                      lat = ~lat,
                      color = ~color) -> lf

}
#show output
lf

请注意,正如我之前提到的,没有办法在如此小的地方对路径进行地理球化 - 大圆圈实际上是直线。如果您为了美观而想要圆形边缘,您可能必须使用我的其他答案中描述的 geom_curve 方式。

【讨论】:

    【解决方案4】:

    刚刚意识到使用geom_path 的原始解决方案比必要的复杂。 geom_segmentworks 不改变数据:

    require(ggplot2)
    require(ggmap)
    basemap <- get_map("Singapore",
                       source = "stamen",
                       maptype = "toner",
                       zoom = 11)
    
    g = ggplot(a)
    map = ggmap(basemap, base_layer = g)
    map = map + coord_cartesian() +
          geom_curve(size = 1.3,
                     aes(x=as.numeric(Entry_Station_Long),
                         y=as.numeric(Entry_Station_Lat),
                         xend=as.numeric(as.character(Exit_Station_Long)),
                         yend=as.numeric(as.character(Exit_Station_Lat)),
                         color=as.factor(token_id)))
    map
    

    此解决方案利用Draw curved lines in ggmap, geom_curve not working 在地图上实现曲线。

    ggmaps 用于简单性 - 对于更雄心勃勃的项目,我会推荐 leaflet

    下面的解决方案使用长数据格式和一些先前的数据整理。它还使用直线而不是上面的曲线。

    a %>%
      mutate(path = row_number()) -> a
    
    origin = select(a,token_id,Entry_Station_Lat,Entry_Station_Long,path)
    origin$type = "origin"
    dest = select(a,token_id,Exit_Station_Lat,Exit_Station_Long,path)
    dest$type = "dest"
    
    colnames(origin) = c("id","lat","long","path","type")
    colnames(dest) = c("id","lat","long","path","type")
    complete = rbind(origin,dest)
    complete %>% arrange(path,type) -> complete
    
    require(ggmap)
    basemap <- get_map("Singapore",
                       source = "stamen",
                       maptype = "toner",
                       zoom = 11)
    
    g = ggplot(complete, aes(x=as.numeric(long),
                             y=as.numeric(lat)))
    map = ggmap(basemap, base_layer = g)
    
    map + geom_path(aes(color = as.factor(id)),
                    size = 1.1)
    

    【讨论】:

    • 感谢您的建议,我正在寻找传单方法。尽管如此,这对我来说是一个很好的开始和学习。
    【解决方案5】:

    我想为您留下另一种方法。您可以做的是重构您的数据。现在,您有两列用于入口站,另外两列用于出口站。您可以通过组合这些列来创建一列 long 和另一列 lat。诀窍是使用rbind()c()

    让我们看一下这个简单的例子。

    x <- c(1, 3, 5)
    y <- c(2, 4, 6)
    c(rbind(x, y))
    
    #[1] 1 2 3 4 5 6
    

    假设 x 代表入口站,y 代表出口站。 1 是起点的经度。 2 是第一次旅程结束的经度。据我从您的示例数据中可以看出,3 似乎是相同的 2。您可以删除每个 token_id 的重复数据点。如果您有大量数据,也许这是您要考虑的事情。回到重点,您可以结合这两个函数,按照您想要的顺序创建一个带有经度的列。既然您说您有日期信息,请确保按日期订购数据。然后,每个旅程的顺序以正确的方式出现在tmp。你也想在纬度上做到这一点。

    现在我们调查您的样本数据。似乎Exit_Station_LatExit_Station_Long 是因素。第一个操作是将它们转换为数字。然后,您应用上述方法并创建一个数据框。我打电话给你的数据mydf

    library(dplyr)
    library(ggplot2)
    library(ggalt)
    library(ggthemes)
    library(raster)
    
    mydf %>%
    mutate_at(vars(Exit_Station_Lat: Exit_Station_Long),
              funs(as.numeric(as.character(.)))) -> mydf
    
    group_by(mydf, token_id) %>%
    do(data.frame(long = c(rbind(.$Entry_Station_Long,.$Exit_Station_Long)),
                  lat = c(rbind(.$Entry_Station_Lat, .$Exit_Station_Lat))
                 )
       ) -> tmp
    

    现在让我们从 GADM 获取地图数据。您可以使用raster 包下载数据。

    getData(name = "GADM", country = "singapore", level = 0) %>%
    fortify -> singapore
    

    最后,你画了一张地图。关键是在aesgeom_path() 中使用group。我希望这会让你继续前进。

    ggplot() +
    geom_cartogram(data = singapore,
                   aes(x = long, y = lat, map_id = id),
                   map = singapore) +
    geom_path(data = tmp,
              aes(x = long, y = lat, group = token_id,
              color = as.character(token_id)),
              show.legend = FALSE) +
    theme_map() 
    

    【讨论】:

    • 清除。任何带有传单的方法。
    • @RUser 看看this question
    • 谢谢,去看看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多