2017-05-31 234 views
2

我想繪製流程圖(對於新加坡)。我有Entry(Lat,Long)和Exit(Lat,long)。我試圖在新加坡地圖上顯示從入口到出口的流量。在R中使用緯度和長度的流程圖(旅行路徑)

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

+0

那麼,你有什麼問題?這裏有沒有問題...... –

+0

是'token_id'the分組變量? – CMichael

+0

是的,令牌ID是分組變量 – RUser

回答

2
使用 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 

備選答案,當我提到之前沒有任何geosphering在這樣一個小地方的路徑的方式 - 大圓是有效直線。如果您爲了美觀而需要圓形邊緣,您可能需要使用我的其他答案中所述的geom_curve方式。

enter image description here

4

就明白了,原來解決方案全光照geom_path比必要的更加複雜。 geom_segment作品而不改變數據:

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

enter image description here

使用一些現有數據角力一個長數據格式的溶液的下方。它也使用直線代替上面的曲線。

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) 

enter image description here

+0

感謝您的建議,我正在尋找傳單方法。儘管如此,它對我來說是一個很好的開始和學習。 – RUser

+0

我更新了一個更簡單的解決方案。 – CMichael

1

我想離開的另一種方法適合你。你可以做的是重組你的數據。現在你有兩列入口站,另外兩列出站。您可以通過梳理這些列來創建一個長列,另一個列爲拉特。訣竅是使用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 

最後,你畫一張地圖。關鍵是要在geom_path()aes中使用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() 

enter image description here

+0

清除。任何方式與傳單。 – RUser

+0

@RUser看看[這個問題](https://stackoverflow.com/questions/32275213/how-do-i-connect-two-coordinates-with-a-line-using-leaflet-in-r/ 32281435#32281435) – jazzurro

+0

謝謝,會看看。 – RUser

1

如果你想繪製它在實際的谷歌地圖,並重新創建你的鏈接圖的風格,您可以使用使用谷歌的地圖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") 

enter image description here


注意,使用飛行數據來重新創建地圖,看到?add_polylines


給出的例子中,你也可以顯示其他類型的路線,例如,通過使用Google的路線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") 

enter image description here

+0

這看起來不錯。我需要我的可視化來看看什麼東西(入口和出口應該表示爲一個點,線條應該是彎曲的,更具視覺吸引力)。 – RUser

相關問題