台風21号の猛威を可視化してみたかった話

# 目的

先日の台風21号関連の動画がTL上に流れてくるのを眺めていてふと思った。

「それぞれどこらへんの位置の動画なのだろう？」

**わからなければ地図で可視化してみればいい。**

ちょうど先日TwitterのAPIのストリーミングの仕様が変わったとかいうニュースもみかけていたので
久々にTwitterAPIも触ってみるかということで
Twitter上の台風関連の動画を地図上にポイント化してみる
ということを目的にスタートしてみる。
※いつものようにイメージはあるものの明確なゴールはない状態でスタート。

# 関連動画に対するTweetとその位置情報を集める

まずは[#台風21号]に動画がくっついているものを抽出してみる。
※おそらくニュースの動画とかが添付されていているものやパクツイとかもあるんだろうけどとりあえず何も考えずにピックアップしてみる。

仕様が変わってなければTwitterのSearchAPIは一週間ぐらい前までしか取得できないので、さっさと取得しておく必要があるので昔作った処理を流用するためにC#でやることにした。

    public long GetTweet(long max_id)
    {
        var API_Key = "xxxxxxxxxxxx";
        var API_Secret = "xxxxxxxxxxxx";
        var Access_Token = "xxxxxxxxxxxx";
        var Access_Token_Secret = "xxxxxxxxxxxx";

        var tokens = CoreTweet.Tokens.Create(API_Key, API_Secret, Access_Token, Access_Token_Secret);

        var parm = new Dictionary<string, object>();
        parm["count"] = 100;
        parm["q"] = "\"#台風21号\" -RT";
        parm["result_type"] = "mixed";
        parm["max_id"] = max_id;
        parm["f"] = "video";

        var tweets = tokens.Search.Tweets(parm);
        var setId = max_id;

        foreach (var tweet in tweets)
        {
            if (setId > tweet.Id) setId = tweet.Id;
            if (tweet.RetweetCount == 0) continue;
            if (tweet.Entities.Media != null && tweet.Entities.Media.Length != 0)
            {
                var tw_data = new TweetData();
                tw_data.CreatedAt_DateTime = tweet.CreatedAt.DateTime;
                tw_data.DisplayUrl = tweet.Entities.Media[0].ExpandedUrl;

                if (tweet.Place != null)
                {
                    if (tweet.Place.Geometry != null)
                    {
                        tw_data.Place_Geometry_Latitude = tweet.Place.Geometry.Latitude;
                        tw_data.Place_Geometry_Longitude = tweet.Place.Geometry.Longitude;
                    }
                    else
                    {
                        tw_data.Place_FullName = tweet.Place.FullName;
                    }
                    list_tweet_data.Add(tw_data);
                }
                else
                {
                    if (tw_data.DisplayUrl.Contains("photo"))
                    {
                        list_tweet_data_no_geoinfo_photo.Add(tw_data);
                    }
                    else
                    {
                        list_tweet_data_no_geoinfo_video.Add(tw_data);
                    }
                }
            }
        }
        return setId;
    }

※MaxIDを指定してそこから100件ずつ戻っていく形式になってます。

※SearchAPIのオプション
https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets.html

結構な量になることは予想されたので、できるだけ取得対象を減らしたかった(APIのCALL回数の上限もあるため)ので以下のような条件にした。

	parm["count"] = 100;
	parm["q"] = "\"#台風21号\" -RT";
	parm["result_type"] = "mixed";
	parm["f"] = "video";


本当は近畿地方だけを取得しようと思い、
geocodeのオプションが使ってみたのだが、全く取得できなかったので止めた。
こんな感じのオプション：geocode:34.733165,-135.500214,100km
座標は新大阪駅(WGS1984)
※この時点で位置情報が付いているTweetはほぼないということを察するべきだったのかもしれない。


取得できた結果のうち、RetweetCountが0のものは別にいらないだろうという判断で取得後に除外。
※メディアがついていないものも取得後に除外。parm["f"] = "video"をつけているはずなのについてきてるものがあったため。画像も取得されていたのでこのオプションそのものが有効に働いてなかったのかもしれない。。

## 実行結果
15分に180Callしかできないのでここの取得処理に本当に時間がかかった。

で、なんやかんやで取得できたのが421件。
結論からいうと緯度経度が設定されていたTweetは一件もなかった。
みんなリテラシー高いな。

この段階で企画終了になりそうだったのだが、住所？的なものが設定されているのはいくつかあったのでせっかくなのでそれを可視化してみることにした。
ただ、緯度経度じゃないのでジオコーディングが必要。

ちなみに位置情報が未設定のものも含めた総数としては10000件弱。
せっかくなのでそれだけのページも作ってみたがこの作業が一番疲れた。
・[#台風21号 の画像/動画Tweet（位置情報）動画編(その１)](http://www.riosnest.co.uk/2018/09/post-330/)
・[#台風21号 の画像/動画Tweet（位置情報）画像編(その１)](http://www.riosnest.co.uk/2018/09/post-318/)
※動画はその５まで、画像に至ってはその１３まである始末だ。

Tweetの系列順には並んでいるはずなので、備忘録としては割とありだなとは思ったが超めんどくさかった。
今回の企画でできあがるものよりも、こっちのサイトの方がたぶん見てて楽しいはずだ。

# 緯度経度取得
緯度経度をダイレクトに取得できたものは一件もなかった代わりにいくつか住所？っぽいものが取れたものがあるので
そこから緯度経度を取得してみる。
この辺のAPIを使うことにする。
https://developers.arcgis.com/rest/geocode/api-reference/geocoding-find-address-candidates.htm


ここでも厳密さは求めていないのでとりあえず最初に取れたものを信用してしまうことにする。
取れないものもあるが、その場合はとりあえずさっき調べた新大阪駅(34.733165,135.500214)にでもくっつけておく。

こんな感じでCSVにしてしまう

    # ファイル読み込み
    df = pd.read_table(r'tweet_data.tsv')

    url = 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?f=json&outFields=location&maxLocations=1&singleLine="{}"'
    for index, row in df.iterrows():
        # 住所取得
        single_address = row['address']

        # 緯度経度取得
        res = requests.get(url.format(single_address)).json()

        if(len(res["candidates"])==0):
            # 取れなかった場合はとりあえず新大阪駅にでも紐づけておく
            df.at[index, 'x'] = 135.500214
            df.at[index, 'y'] = 34.733165
            continue 

        dic_location = res["candidates"][0]["location"]

        # 取得した値で元のDataFrameを更新
        df.at[index, 'x'] = dic_location["x"]
        df.at[index, 'y'] = dic_location["y"]

    # CSVファイルとして出力する:indexはいらない。ヘッダーは必要
    df.to_csv(r'tweet_data.csv', index=False)

簡単である。

# TweetをGISへ
取得できた緯度経度を使って取得したTweetをGISへ流し込む。
CSVファイルをアップロードして[前に作っていたArcGIS](https://qiita.com/ryo_naka/items/cede1f4ce3dce0aed350#%E9%80%A3%E6%90%BA%E5%85%88arcgis%E3%82%92%E4%BD%9C%E6%88%90)へ。
今回はヘッダ付きのCSVでアップロードしているので特にややこしい各項目の設定は不要。

<img width="763" alt="01_AGOL_01.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/106639/c0edaca2-40b7-b1b6-14fc-e407c605e28f.png">
<img width="682" alt="01_AGOL_02.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/106639/4095cc63-7dbc-5936-adee-1e974ddd16a1.png">
<img width="654" alt="01_AGOL_03.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/106639/96a414d1-c6c4-7e30-7768-98b495d869ed.png">
<img width="665" alt="01_AGOL_04.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/106639/756e42d0-2c0e-bbab-55cd-42107ac0993c.png">
<img width="656" alt="01_AGOL_05.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/106639/d57f9065-1732-2909-f705-d41558695c8b.png">

ということで出来上がりである。
なぜか変なところに設定されているものもいくつかある。
住所が日本語になっているものをURLエンコードしなかったからか？

<img width="655" alt="01_AGOL_06.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/106639/4670e558-9039-0a0f-8adb-62e27318c0ae.png">

位置を直すのはたぶん結構めんどくさいので今回はやらない。
代わりにもう少しかっこよく表示できないかどうかを試してみる。
<img width="953" alt="01_AGOL_07.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/106639/31c0c69f-4a31-58ab-3988-94b7948c66b2.png">

実物は[こんな感じ](https://www.arcgis.com/apps/opsdashboard/index.html#/d674e41dfac2438cb9f7632a5cb5daab)

いろいろとやってみたかったがいくつか挫折。
以下は反省点や挫折点

- Fav数やRT数も一緒にデータとして保持しておけばよかった。
日時だけだと画像/動画を見に行くときの参考情報が少なすぎる

- 可能であればその画面上でTweetのカード表示させたかったができなかった。

- Cots&Configだけだと任意のJSは流せない？
ポップアップ内にblockquoteは設定できるから
`<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>`
を流せればカード化すると思うんだけどな。

- 日時表記をなじみのある形式にしたかった

# まとめ
- とりあえずやりたかったことはできたので満足。
- Twitterの新しいAPIはCoreTweetを使っている限りは意識しなくても問題なし？
- もうちょっといろいろとやりたいこと/できそうなことはあるが、これ以上は自分のやる気が続かないのでおしまい。
- Tweetの画像/動画を時系列で並べるということの方がちょっと面白かった。
- ArcGIS Online上でTweetのカードが参照できればもうちょっと使いやすそうなものになるとは思うんだけどな。
ただ、Tweetする人がみな位置情報をくっつけてないので地図上で可視化する意味がほぼない。