この資料に至るまでの経緯はこちら
DiagrammeRパッケージを用いてグラフを描いている(DOT言語を利用)
他にもmermaid.jsを使った方法やデータフレームから変換する方法がある
データフレームからグラフに変換する概説で良い日本語記事が出ていたのでそちらを参照のこと
library("DiagrammeR")
grViz("
digraph G{
graph [rankdir = LR]
// nodeの属性を指定
node [shape = oval,
color = black]
菊竹清訓; 伊東豊雄
node [shape = box,
color = red]
妹島和世
// 構造を指定
菊竹清訓 -> 伊東豊雄 -> 妹島和世
}",
width=800, height=200)
あらかじめ作っておいた妹島和世の都内建築物リストを読み込む
data.tableのfread関数はdata.table=FALSEと指定するとdata.frameで読み込んでくれる
library("data.table")
data_sejima <- fread("https://raw.githubusercontent.com/dichika/mydata/master/sejima.csv",
data.table=FALSE)
library("DT")
datatable(data_sejima)
library("dplyr")
data_sejima <- bind_rows(data_sejima,
data_frame(year = 2015,
name = "ブルーボトルコーヒー",
address = "東京都港区南青山3-13-14",
memo = "お茶")
)
data_sejima <- bind_rows(data_sejima,
data_frame(year = 1914,
name = "東京駅",
address = "千代田区丸の内1-9-1",
memo = "スタート地点")
)
google geocodingを利用(1日のAPI使用回数とAPI使用間隔に制限あり)
ggmapパッケージのgeocode関数を使うというのもありかも
bind_colsはdplyrの関数でcbindに該当
# ジオコーディング
getLocation <- function(x){
require("httr")
tmp <- content(GET(x), "parsed")
res <- data_frame(
lat=tmp$results[[1]]$geometry$location$lat,
lng=tmp$results[[1]]$geometry$location$lng
)
}
adds <- data_sejima$address
qs <- paste0("http://maps.googleapis.com/maps/api/geocode/json?address=", adds)
locs <- NULL
for(q in qs){
locs <- bind_rows(locs, getLocation(q))
Sys.sleep(1) # 使用制限にひっかからないように1秒待つ
}
data_sejima <- bind_cols(data_sejima, locs)
まずleafletでleafletオブジェクトを作りそこに層やポイントを追加していくイメージ
addCircleMarkersは地点の可視化
addPopupsはポップアップ(吹き出し)を追加
addTilesでバックグラウンドの地図が追加される
library("leaflet")
leaflet() %>%
addCircleMarkers(data =data_sejima,
lat = ~lat,
lng = ~lng,
radius = 10) %>%
addPopups(data=data_sejima,
lat= ~lat,
lng= ~lng,
popup=data_sejima$name,
options=popupOptions(minWidth=10)
) %>%
addTiles()
—-
ETSPでユークリッド距離を計算し、その結果をsolve_TSPに渡すことで経路探索できる
http://www.slideshare.net/sleipnir002/tsp-and-geocoding-on-r
なお、insertion関係のmethodはスタート地点の指定にバグがあるので今回は使わない
library("TSP")
data_dist <- ETSP(data_sejima[,c("lat","lng")])
res <- NULL
for(m in c("identity", "random",
#nearest_insertion","cheapest_insertion","farthest_insertion","arbitrary_insertion"",
"nn", "repetitive_nn", "two_opt")){
tmp <- solve_TSP(data_dist,
method = m,
control=list(start=9)) # start地点の行を指定
res <- bind_rows(res, data_frame(method=attr(tmp, "method"),
tour_length=attr(tmp, "tour_length")))
}
datatable(res)
res_nn <- solve_TSP(data_dist,
method = "nn",
control=list(start=9))
data_order <- as.integer(res_nn) # 回る順番
data_sejima <- data_sejima[data_order,] # 並べ替え
経路(path)の可視化は地点の可視化より少し面倒(発表時点ではそう思っていた)
かと思いきやそんなことは無かったぜ(kazutanさんありがとうございます)
以下の関数は今回の用途では不要だが一応メモ
points_to_line <- function(data, long, lat, id_field = NULL, sort_field = NULL) {
require("sp")
require("maptools")
# 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)
}
}
経路順に並んでいれば緯度経度をaddPolylinesに指定するだけで経路を描ける
ポップアップはスタート地点とゴール地点のみに限定する
library("leaflet")
leaflet(data = data_sejima) %>%
addCircleMarkers(lat = ~lat,
lng = ~lng,
popup= ~name,
radius = 10) %>%
addPolylines(lat = ~lat,
lng = ~lng) %>%
addPopups(data=data_sejima[range(seq(nrow(data_sejima))),],
lat= ~lat,
lng= ~lng,
popup=data_sejima$name[range(seq(nrow(data_sejima)))],
options=popupOptions(minWidth=10)
) %>%
addTiles()
htmlwidgets関連パッケージは、R presentationやRmarkdownから作るスライドとの連携が現段階でうまくいっていない印象
Rmarkdownからhtmlを作成する際、ページ区切り(“—”)の上下は空行にしておかないとレイアウトがぐちゃぐちゃになる