Power BI で表現可能なR, Pythonの地理情報可視化

本記事は@yugoes1021王子による [Power BI Advent Calendar 2019](https://qiita.com/advent-calendar/2019/powerbi)に参加しています。

# もうネタが無いので

Power BIで以下のような地理関連のシリーズを各種書いてきましたが、単に地図上に可視化するという観点では、もうあまりネタが無いので、どうしても重箱の隅をつつくような記事になりがちです。（とはいえ、Web版とかEmbeddedとかを触るリソース、時間がない orz）

[Power BI で地理的解析（基礎編）](https://qiita.com/Masutani/items/d91361db4d59d6721d09)
[Power BI で地理的解析（応用編１）](https://qiita.com/Masutani/items/34cad3287fba9ba44ff4)
[Power BI で地理的解析（応用編２）](https://qiita.com/Masutani/items/513ed61afbf0f316c936)
[Power BIで米マップ](https://qiita.com/Masutani/items/70d93ec60fa109a93cb8) 2017 Advent Calendar
[PowerBIで地理的解析（2018まとめ編）](https://qiita.com/Masutani/items/9e03974cbd4b02fbeaa5) 2018 Advent Calendar

なので、残る可能性としてはPower BI Desktop上でRやPythonを使った地図だろうということに落ち着きました。
R, Pythonでの拡張は各所で紹介されているので、ここではオフィシャルのリンクだけにしておきます。


[R を使用した Power BI ビジュアルの作成](https://docs.microsoft.com/ja-jp/power-bi/desktop-r-visuals)
[Power BI Desktop で Python スクリプトを実行する](https://docs.microsoft.com/ja-jp/power-bi/desktop-python-scripts)

課題としては、ポイントデータの可視化という今までベンチマークとして使ってきたものをそのまま使います。
前と同じUberのオープンデータを使っての評価をしています。サンフランシスコのタクシープローブデータです。

基本的に、単純に表示することを目的として、Power BIでのR,Pythonの呼び方、各ライブラリでのpointデータの表示方法、表示範囲のダイナミックな変更方法などに絞っています。
各ライブラリでかなり思想が違うので、その辺も伝わればいいのですが、この程度のサイズでは無理ですね。。。

# R

Rの方がバリエーションがあります。Power BIではPythonより歴史があります。
若干躓きやすいのが、PowerBIが使うRのバージョン、インストール場所です。
以下のオプションページで設定できますので、自分の使いたい、いつも使っているRインタープリタを指定しましょう。
そうすることで、libraryのインストールの手間が省けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/7f4ef32f-293f-4372-390d-91b6b122785a.png)

ただし、同じインタープリタでも環境をユーザーフォルダに保存する場合もあるので、その場合はグローバルなインタープリタ環境でインストールする必要があるでしょう。


## library(maps)

古めのライブラリです。基本的には各種の白地図を表示して、その上にデータを表示するものです。
（コード中のggmapはバウンディングボックスを得る便利関数のためだけに使います）
with関数でポイントを重畳できます。

```R
library(maps)
library(ggmap)
sbbox <- make_bbox(lon = dataset$longitude, lat = dataset$latitude, f = 0)
map('usa', col = "grey", fill = TRUE, bg = "white", border = 0, 
　　xlim = c(sbbox[1], sbbox[3]), ylim = c(sbbox[2], sbbox[4]))
with(dataset, points(longitude, latitude, pch = 1, col = 'blue', cex = .2))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/25e6f766-60ed-67e9-44bf-037f2e4bb90e.png)



## library(sf)

空間データを適切に扱うためのライブラリです。一度sf形式のデータフレームに変換する必要があります。
なんとデータフレームを直接plotできます。

```R
library(sf)
library(sp)
dfsf <- dataset %>% st_as_sf(coords = c('longitude', 'latitude'), crs = 4236)
plot(dfsf, col = "blue", pch = 21)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/689690ae-c928-afd1-8e17-088508f6d282.png)

## library(tmap)

比較的容易にいろいろな主題図を描くことができるライブラリです。
通常のplotモードとLeafletビューアが立ち上がるviewモードを切り替えられ、便利です。
他もそうですが、Leafletの外部画面をブラウザを立ち上げるような行為は、さすがにPowerBIからはできませんでした。
ですが、以下をみてわかるように、plotモードではベースマップが貼り付けられません。残念。

```R
library(tmap)
library(dplyr)
library(sf)
library(sp)
dfsf <- dataset %>% st_as_sf(coords = c('longitude', 'latitude'), crs = 4236)
tmap_mode("plot")
map <- tm_shape(dfsf, name = "uber") +
    tm_symbols(shape = 21, col = "blue", size = 0.05) +
    tm_basemap("Stamen.Watercolor")
map
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/a7552baf-7484-ba06-11ac-3e9814e0a7db.png)


## library(ggplot2)

ggplotにマップを描く機能が統合されています。おそらく、一般的なデータ処理を行う人は、通常はこれを使うのが一番しっくりくるのではないでしょうか？

```R
library(ggplot2)
library(mapproj)
library(ggmap)
sbbox <- make_bbox(lon = dataset$longitude, lat = dataset$latitude, f = 0)
usmap <- map_data("state") 
ggplot() +
    geom_polygon(data = usmap, aes(x = long, y = lat, group = group), fill = "grey", alpha = 0.5) +
    geom_point(data = dataset, aes(x = longitude, y = latitude)) +
    theme_void() + coord_map(xlim = c(sbbox[1], sbbox[3]), ylim = c(sbbox[2], sbbox[4]))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/7a2193ad-4254-3502-a50d-e1b6b90cd57b.png)


## library(ggmap)

やはり背景地図をもっと細かいものが欲しいとなると、これです。
どうもGoogle Maps APIの制限がきつくなったせいか、API Keyの登録が必要です。
また、便利な登録用関数がある以下の開発版を入手するようにしましょう。

自分のＲ環境で以下の方法で最新版をインストールすると、register_googleというキー設定が可能な関数が入ってきますので、アップグレードしておきます。

```R
devtools::install_github("dkahle/ggmap")
```

```R
library(ggplot2)
library(mapproj)
library(ggmap)
register_google(key = "YOUR_API_KEY")
sbbox <- make_bbox(lon = dataset$longitude, lat = dataset$latitude, f = 0)
map <- get_stamenmap(bbox = sbbox, zoom = 13, maptype = "toner-lite")
ggmap(map) +
    geom_point(aes(x = longitude, y = latitude), color = "blue" ,data = dataset, alpha = .5)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/387ffc84-4422-659e-d1fc-25283a7e6e53.png)

# Python

Folium, ShapelyなどPythonには本格的な地図系可視化ライブラリや、非常に扱いやすいgeo pandasなど地理データ処理ライブラリがそろっているのですが、Power BI上で試そうとしたところ、なかなか動いてくれませんでした。
同じくFoliumを動かそうという人がいたのですが、以下のように、そもそも現状のPower BIでは限られたライブラリしか動かないらしく、素直にあきらめることにしました。。。

[Help to implement Python Script - Microsoft Power BI Community](https://community.powerbi.com/t5/Desktop/Help-to-implement-Python-Script/td-p/646780)


>The following Python packages (non-Intel MKL) are currently supported for use in your Power BI reports. Reference: Python packages and versions

> * Matplotlib
* numpy
* pandas
* scikit-learn
* scipy
* seaborn
* statsmodels

Pythonもインタープリタを以下で設定します。Anacondaになると思いますが、たとえ新しいライブラリをインストールしても、Power BIでは使えないので、ご了承ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/ceaa97bf-420b-bf2e-0a6e-b19dc1eba273.png)


## Matplotlib

その中でもMatplotlibにはmpl_toolkits:basemapというライブラリが存在するようです。
Matplotlib標準ではなく、インストールする必要があります。現在はpipインストールはサポートしておらずcondaなどを使います。

conda install -c anaconda basemap

でインストールするとAnaconda環境で使えるようになりました。

``` Python
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
m = Basemap(llcrnrlon=BBox[0],llcrnrlat=BBox[2],urcrnrlon=BBox[1],urcrnrlat=BBox[3])
m.drawcoastlines()
x, y = m(dataset.longitude, dataset.latitude)
m.plot(x, y, 'o')
plt.show()
```
VSCodeでの結果：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/2cf7fa3d-44d7-ceda-590f-13a2f0308ec0.png)

が、そもそもMatplotlib以外のライブラリだめなので、PowerBIでは動きませんでした。orz


# 恒例の性能評価

以前と同じデータを使っているので、標準ライブラリとの比較をしてみましょう。
クエリエディタであらかじめレコード数を絞れるようにして試しました。
Pythonはお茶を濁して単に２次元グラフを表示しています。

## 1,000レコード
標準マップ含めて、問題なく表示されます。あくまで表示された数の話ですが。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/b3b9cce1-01a1-d662-a89c-440af59db1b1.png)

## 10,000レコード
標準マップはすべての点が表示されない旨のメッセージが出ます。
他も見た感じ、大きな欠落は無い模様です。スピードについてもどれもそれほど変わりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/72b79b0e-5c74-5889-f47b-3f00c35e7ac9.png)

## 100,000レコード

ArcGISはかけ始めました。標準マップはどうもランダムサンプリングをするようになっており、見た目の範囲はそれほど変わっていません。
他のライブラリは、PowerBIで動いているとは知らず、全部表示できているようです。（ほんと？）
tmapとggmapが少し遅いかなという以外は、それほど変わりません。1分も待たされることはありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/8fecdbf2-13a4-1cbc-4cb8-1e2a553532da.png)


## 1,000,000レコード

ここまでくると、Rビジュアルについても、データの間引きが行われているようです。
また、Uberデータの中に、ラスベガスまで行っている車があるので、全体を表示するのにggmapは時間がかかります（地図の拡大率の調整が必要）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/af5497d3-57fd-a0ac-63bd-a45ee75a3d7a.png)

# まとめ

このような単純なマップではわざわざRのコードを使って可視化する意味は薄いのですが、特殊な描画や演算が必要な場合は、Rでしっかりとライブラリ化したものを埋め込んで使うようにすれば、出番もあるのではと思いました。