Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

GoogleのLocation History(Timeline)を可視化

Google Map に Timeline を見る機能がついていて、過去の位置情報の履歴をすべて参照することができることは有名だが、実はこのデータはダウンロードすることもできる。

support.google.com

昔、このデータを元に 1log(イチログ) へデータをインポートするアプリを書いた。

github.com

しかし、 1log は 10 年分の位置データのデータ量に耐えうることができず重くて利用不能になってしまったため、 1log で自分の過去の位置情報を見ることは諦めた。それならばと思い立ち、今度は自前でこのデータを可視化してみることにした。

Google から Takeout できるデータには、 Records.jsonSemantic Location History がある。(おそらく)前者が生データで、後者が Google 側で予測をした詳細データと思われる。ひとまず、簡単でデータ量も少ない Records.json を使ってみることにする。

地図情報は、ひとまず静的な可視化ができれば十分なので、 staticmap - Rust というクレートを使ってみた。まずは、経度緯度やズームなどを指定し、 StaticMapインスタンスを作成する。それを Visitor に渡してやる。簡単のため、 JSON のデシリアライザの deserialize_locations 内で直接地図を吐くことにした。

fn deserialize_locations<'de, D>(deserializer: D) -> Result<ConversionResult, D::Error>
where
    D: Deserializer<'de>,
{
    struct LocVisitor<'vis>(&'vis mut StaticMap);

    impl<'de, 'vis> Visitor<'de> for LocVisitor<'vis> {
        ..snip..
    }

    let mut map = StaticMapBuilder::default()
        // Tokyo
        .lat_center(35.586533759675454)
        .lon_center(139.6296830270391)
        .zoom(11)
        .width(10000)
        .height(10000)
        //.padding((10, 0))
        .build()
        .map_err(Error::custom)?;

    let visitor = LocVisitor(&mut map);
    let result = deserializer.deserialize_seq(visitor);
    map.save_png("line.png").map_err(Error::custom)?;
    result

LocVisitorStaticMap の参照を渡せるようにしたので、この中で出現する緯度経度をすべて plot する。古い情報は青色、新しい情報は赤色で描画するようにした。

        fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
        where
            S: SeqAccess<'de>,
        {
            ..snip..

            while let Some(l) = seq.next_element::<quicktype::LocationRecord>()? {
                ..snip..
                if let (Some(lat), Some(lon)) = (l.latitude_e7, l.longitude_e7) {
                    let t = count as f64 / 2961678.0;
                    let color =
                        Color::new(false, (t * 255.0) as u8, 0, ((1.0 - t) * 255.0) as u8, 64);
                    let circle = CircleBuilder::default()
                        .lat_coordinate(lat as f64 / 10000000.0)
                        .lon_coordinate(lon as f64 / 10000000.0)
                        .radius(4.)
                        .color(color)
                        .build()
                        .map_err(Error::custom)?;
                    self.0.add_tool(circle);
                }
            }
        }

こんな雑な作りにはなったが、 --releaseコンパイルしてから実行完了までに約 35 秒。雑に書いても Rust は速くて良い。

結果はこんな感じ。まず、全体的に真っ赤なのは、おそらく古い順に描画しているせいで青い点が消されているものだと思われる。それに加えて、自転車に乗るようになってからスマートウォッチでの GPS 計測をしているが、 GPS 計測中の計測間隔が通常時の計測間隔より短いため、まばらにプロットされている青い点と比較して、最近の赤い点はすべて線になって繋がってしまっているのが要因だろう。

StaticMap(1)

出来上がった地図を眺めると、まず、久里浜港から金谷港へ青と赤の点が伸びていることがわかる。これは、東京湾フェリーを昔から(自転車に乗る前から)よく利用していたことを意味する。次に、画像の左側の方に、秦野から北側へ向かって伸びる赤い線がある。これはヤビツに登ったときのものだ。同じく、厚木市を囲むように赤い線があるが、こちらは宮ヶ瀬湖へ行ったときのものである。

hiratara.hatenadiary.jp

もう少し北側に目を向けると、都民の森~奥多摩湖を走ったときの記録が残っている。それとは別に、鉄道に沿って青い点を観測することができ、過去に何度か旅行などで使っていることが見受けられる。

StaticMap(2)

最後に、茨城方面を見てみよう。土浦市付近には、霞ヶ浦を一周して 1 りんりんロードを走った記録がきれいに残っている。埼玉方面には、江戸川を通って五霞町で露頭に迷って引き換えした痕跡が残っている。埼玉県内で輪になっているところは、 菓子工房オークウッド|埼玉県春日部市のケーキと焼き菓子のお店 へ行った 2 ときのものである。そして、全体的に青や赤の点として公共交通機関場に残っている点は、自転車ではなく交通機関で移動した痕跡であろう。

StaticMap(3)

この可視化はとても面白く満足しているのだが、自転車に乗る前の過去の記録がかなり蔑ろにされているように思える。その理由は、

  • ワークアウトの計測時と比較して GPS の計測間隔がまばらであり、点の数が少ないこと
  • 古い点は新しい点に上書きされて、隠されてしまっていること

の 2 点によるものであろう。後者は描画順をランダムにするなど、どうにでもなる気はするのだが、前者についてはなかなか難しい問題だ。 GPS の 1 点あたりの時間まで考慮をして重み付けする(観測間隔が長い場合に 1 点のウェイトを重くする)か、 Semantic Location History の方のデータを使えばまた違う結果が得られるのかもしれない。


  1. そして、ロングではなくショートコースだったこと。
  2. そして、激混みで店には入れなかった。