LivebookのSmartCellのDBとMapを使ってGPSログデータを可視化してみた

# はじめに
本記事は以下のことを行います
1. 自前で作成したGPSロギングシステムのDBにLivebookからコネクションを貼る
2. コネクションを貼ったDBからSQLクエリでデータを取得
3. SmartCellのMap上に可視化

# Livebookの準備

https://livebook.dev/

こちらからインストールバイナリか

https://github.com/livebook-dev/livebook#installation

docker、livebookリポジトリからcloneお好きな方法で起動してください

日本語記事はこちら

https://qiita.com/nako_sleep_9h/items/585786648d2b7560d010

# SmartCellについて

SmartCellはLivebookののセルの１つで
Elixirを記述するCodeと
Blockにはセクション、マークダウン、図、画像があり
SmartCellには以下があります
- chart -> グラフ描画
- databae connection -> DBに接続
- map -> MapLibreを表示、データを描画
- neural network task -> 画像分類、画像生成、テキスト分類、テキスト生成等を行う
- sql query -> 接続したDBに対してqueryを発行する
- slack message -> 指定したチャンネルにpostする

今回はこの中で database connection, sql query, mapを使います


# 可視化するデータについて
今回は自前のGPSロギングアプリのDBにつないでいきます
データとしては　GPSログ単体をposition,それを束ねたのをrouteとしています
データとしては以下になります

```sql:routes
   Column    |              Type              | Collation | Nullable |              Default               
-------------+--------------------------------+-----------+----------+------------------------------------
 id          | bigint                         |           | not null | nextval('routes_id_seq'::regclass)
 name        | character varying(255)         |           |          | 
 description | character varying(255)         |           |          | 
 user_id     | bigint                         |           |          | 
 inserted_at | timestamp(0) without time zone |           | not null | 
 updated_at  | timestamp(0) without time zone |           | not null | 

```

```sql:positions
   Column    |              Type              | Collation | Nullable |                Default                
-------------+--------------------------------+-----------+----------+---------------------------------------
 id          | bigint                         |           | not null | nextval('positions_id_seq'::regclass)
 lat         | double precision               |           |          | 
 lng         | double precision               |           |          | 
 user_id     | bigint                         |           |          | 
 route_id    | bigint                         |           |          | 
 inserted_at | timestamp(0) without time zone |           | not null | 
 updated_at  | timestamp(0) without time zone |           | not null | 
```

それでは可視化を指定いきます

# DB 接続
`+Smart` をクリックするとセットアップが必要とのことなので実行します
![スクリーンショット 2023-02-22 16.27.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/e2e1a3b1-0c47-225a-a175-0b37bde0fc47.png)

Database connectionを選んで、DBは今回はPostgreSQLなのでそれを選択します
![スクリーンショット 2023-02-22 16.27.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/1245eb70-f2bf-92d4-4a96-2d0301065aae.png)

パッケージの追加が必要と言われるので追加して再起動します
![スクリーンショット 2023-02-22 16.27.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/d3f17ab8-a246-aebe-f2d9-53d6252aee54.png)

再起動が完了すると以下のフォームが出てくるので必要な情報をいれます
![スクリーンショット 2023-02-22 16.29.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/614a9cdf-8d2f-3ee2-4729-49551b74f9ed.png)

コネクションが無事はられると `ASSING TO` で設定してある `conn`に値が入ります
これで完了です

# SQL Queryの実行
`+ Smart`のSQL queryをクリックします

![スクリーンショット 2023-02-22 16.35.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/d4aeec7a-1db3-b564-0e22-6de847706905.png)

すると以下のフォームが出てきます

![スクリーンショット 2023-02-22 16.36.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/e2f4f21c-a3ea-3d1f-0fbc-6fd8e27a2826.png)

可視化可能なrouteを知りたいので全件取得します
table_nameをroutesに変えてlimitを消して実行すると以下の結果が得られました
結果はresultに入ります
![スクリーンショット 2023-02-22 16.38.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/9d7b1048-d33f-ce62-ed26-5995bfbb49f2.png)

次に route id: 13 のpositionを取得します
結果はresult2に入ります

![スクリーンショット 2023-02-22 16.51.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/eaac2f90-8de3-ace1-e073-c92c7a360966.png)

地図上に表示するデータの準備ができたので次はMapを使っていきます

# 地図上に表示

`+ Smart`でMapを選択するとライブラリの追加と再起動を要求されるので実行します
完了すると以下のようなフォームが表示されます

![スクリーンショット 2023-02-22 16.54.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/aa8017bb-fc69-d55d-11bf-c52298f368a7.png)

ヘッダーの青い部分をそれぞれ

- MAP STYLE: default -> street
- CENTER: 130.55,33.32 
- ZOOM: 0 -> 4

ボディの白い箇所をそれぞれ以下に設定します、
sourceをresult2に変えると他のフォームが差し替わります
- Source: Geocoding -> result2
- Coordinates format: Single lng, lat -> Two Columns
- Longitude(lng): lng
- Latitude(lat): lat
- Radius: 5 -> 2

![スクリーンショット 2023-02-22 21.33.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/7e3ac56e-6dbb-6394-2d21-c783d4588194.png)

実行すると以下のように地図上にGPSのログが表示されました！

![スクリーンショット 2023-02-22 21.35.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/c638eb4c-0505-ded9-a103-1f0b9c09750a.png)

# レイヤーの追加
マップ右下の`add layer`を押すと別の設定で他のデータを追加で表示できます
マップのセルの上にqueryのセルを追加して他のrouteのデータを取得し、`result3`とします

![スクリーンショット 2023-02-22 21.37.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/a5643955-2f19-b3d4-d160-f9cd1b5c48d9.png)

sourceをresult3にし、色を赤にして、似たような場所を通ってresult2のデータが見えないのでOpacityを0.1にして下の黒が見えるようにします

![スクリーンショット 2023-02-22 21.40.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/21c3eb80-fd96-ed0f-7fff-c018ad54aad7.png)

２つのデータを可視化できました！

# おまけ１：本番サーバーのGigalixirのDBのデータ
こうやって行った所が全部表示されて徐々に開拓されていく感じがワクワクしますねぇー

![スクリーンショット 2023-02-22 21.48.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/c1798325-a70e-b1cc-9012-1b753dc3bd14.png)

# おまけ２：スマートセルの裏側をみれる
セルをクリックすると右上にいろいろ出てくるので 左端のtoggle sourceをクリックすると実際のコードに変わります

![スクリーンショット 2023-02-22 21.51.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/ba837745-082e-1f64-a65d-93e67b3cb6e1.png)

![スクリーンショット 2023-02-22 21.51.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64198/0dbf87e3-9e72-562f-578e-9580979826d2.png)

２つめのconvert to code cellはチラ見だけじゃなくてコードセルに非可逆的に変更することができます
配布したり、コードブロックで表示したいときはこちらがいいかもしれませんね

# 最後に
Livebookの便利なSmartCellが徐々に増えていっていているので、
どんどんいろんな事ができそうで恐ろしい進化ですねー

KinoをPhoenixのLiveView上で動かすノウハウを得れば色々できそうで楽しみです
本記事は以上になりますありがとうございました！