3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

近隣の市町村の新型コロナ発生状況を可視化する

Last updated at Posted at 2021-02-13

今回もオープンデータの活用その2です。
過去記事: 自分の町の避難所情報をGoogle Mapsに表示する

緊急事態宣言中で外出もままならない日々を過ごしていると思いますが、それでも最低限買い物には行かなければ生活はできません。そんなある日、家族から「近所の小郡イオンと甘木イオンどっちが感染のリスクが少ないの?」と聞かれました。うーんどっちだろう?
というわけでオープンデータから近隣の新型コロナ発生状況を可視化して判断してみようと思います。

最初に断っておきますが、私は医者でも感染症の専門家でもないので、この結果を踏まえて何かを訴えたり警鐘を鳴らす意図はありません。

オープンデータの取得

まず、新型コロナの発生状況のデータを取得します。

リンク:福岡県新型コロナウイルス感染症陽性者発表情報
ここからcsv形式のデータがダウンロードできます。

しかし、このままだとデータの一覧に過ぎないので集計を行ってきます。

集計と加工

今回、Rubyを使って簡易的にデータの集計と加工を行います。

まずは、古いデータを参考にしても仕方がないので過去一か月分のみを参考にします。
「公表_年月日」が本日の一か月前より新しいものを絞り込みます。空のデータも存在していたのでエラーにならないように一工夫しています。

次に「居住地」でグループ分けし件数を集計していきます。閾値として件数が1件のみの居住地は除外しています。

ここで作業は終わりなのですが、ついでにその居住区がどの座標にあるのかGeocoding APIで緯度経度を事前に取得しておきます。最初はグーグルマップ表示時にリアルタイムで処理していたのですが、あまりにも重たくAPIの料金も気になるので先に処理するようにしてみました。

csv2json.rb
require 'csv'
require 'json'
require 'geocoder'

Geocoder.configure(language: :ja, units: :km, lookup: :google, api_key: '*********************')

table = CSV.read(ARGV[0], headers: true)
from = Date.today << 1
targets = table.select{ Date.parse(_1['公表_年月日'] || '1970/01/01') > from }
groups = targets.group_by{ _1['居住地'] }.select {|k, v| v.count > 1 }
json = groups.map do |k, v|
  results = Geocoder.search(k)
  {
    city: k,
    count: v.count,
    location: results.first.coordinates
  }
end
File.open("covid19.json", 'w') do |file|
  JSON.dump(json, file)
end

集計結果は後で自分の扱いやすいような形式で出力しておきます。

実行
$ ruby csv2json.rb ダウンロードしたCSVファイル

Googleマップに表示

ここまでできたら後は加工後のデータを好きなように表示するだけです。今回はGoogle MapのCircle描画を使って新型コロナの発生数を円の大きさとして描画していきます。

Circleはradius(半径)を引数指定する必要があるので、円の面積から半径を求めます

r = \sqrt{\frac{S}{\pi}} \\
covid19.html
<!DOCTYPE html>
<html>
  <head>
    <title>covid-19</title>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=*************&callback=initMap&libraries=&v=weekly"
      defer
    ></script>
    <style type="text/css">
      #map {
        height: 100%;
      }
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script>
      function initMap() {
        var currentPos = { lat: 33.3881, lng: 130.6127 };
        const map = new google.maps.Map(document.getElementById("map"), {
          zoom: 10,
          center: currentPos,
        });

        fetch('./covid19.json')
        .then((response) => response.json())
        .then((jsonData) => {
          console.log(jsonData)
          for (const city of jsonData) {
            new google.maps.Circle({
              map: map,
              center: {lat: city.location[0], lng: city.location[1]},
              radius: Math.sqrt(city.count / Math.PI) * 500,
              strokeWeight: 1,
              strokeColor: '#ff0000',
              strokeOpacity: 0.2,
              fillColor: '#ff0000',
              fillOpacity: 0.2
            });
          }
        });
      }
    </script>
  </head>
  <body>
    <div id="map"></div>
  </body>
</html>

表示結果

2021年1月31日の発生状況
covid-19 - Google Chrome 2021_01_31 19_51_15.png

こうやって見ると都市部とその周辺がやばいことになってますが、人口に比例するので当然の結果とも考えられます。市町村の人口データも取得して発生比率を円の色で表してみると面白いかもしれません。
ちなみに朝倉市の方が若干少なそうなので買い物先は甘木イオン(朝倉市)に行くことにしました。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?