新型コロナ感染者数マップ
新型コロナ感染者数を地図を使って検索するアプリを作ります
このアプリは実用的でGoogle Playで公開できるレベルのアプリです。ただし、新型コロナ関係のアプリはGoogle Playが受け付けないので、このアプリはこのままでは公開できません。
更新履歴
- 初版 2/11/2021
使用しているテクニック
ソースコード(aiaファイル)のダウンロード(有料)
チュートリアルを読んで手でアプリを入力すれば動くものが作れますが、入力する時間がもったいないという人のためにソースコードを2980円で販売しています。下の購入ボタンをクリックしてメールアドレス、クレジットカード番号、有効期限、CVCを入力すると、ダウンロードリンクがメールで送付されます。コンピュータにソースコードをダウンロードしてからApp Inventorを開き、[ プロジェクト ]をクリックして[ローカルコンピュータからプロジェクト(.aia)をインポート]を選択し、ソースコードを選択してインポートしてください。売り上げ金はプロジェクトの運営に必要なクラウドコンピュータ使用料金、テスト用スマホ購入費用、人件費などに当てられます。プロジェクトの発展のためにご協力ください。
プログラムの構造(流れ)
スポンサー企業のTM Software, Inc.ではアメリカ合衆国のジョンズ・ホプキンス大学が公開している全世界の新型コロナ感染者数のデータをデータベースに取り込み、1日の新規感染者数と人口10万人あたりの新規感染者数の7日間移動平均を計算し、RESTful APIを使用してデータを自由にダウンロードできるようにしています。このアプリではこのAPIを利用して1)最新の全国コロナ感染者数データを取得して新規感染者数の7日間移動平均の上位20都道府県にマークを表示、2)表示されている地図をクリックするとその場所の新規感染者数と累積感染者数を表示、3)地名を入力するとその場所にマップをズームしてその場所の新規感染者数と累積感染者数を表示、4)GPSを利用して現在地の新規感染者数と累積感染者数を表示、します。
APIの呼び方と返される値
緯度と経度からその都道府県のコロナ感染者数の時系列データを取得
呼び方
https://covid19api.tmsoftwareinc.com/api/v1/latlngs?lat=35.685750628984465&long=139.75407754498727
返される値:JSONリスト
[{“country":"Japan","state":"Tokyo","county":"","city":"","cases":49539,"newcases":822,"7rate":4.19,"deaths":532,"date":"2020-12-18″},
{“country":"Japan","state":"Tokyo","county":"","city":"","cases":48717,"newcases":678,"7rate":3.95,"deaths":532,"date":"2020-12-17″},
{“country":"Japan","state":"Tokyo","county":"","city":"","cases":48039,"newcases":460,"7rate":3.84,"deaths":522,"date":"2020-12-16″},
{“country":"Japan","state":"Tokyo","county":"","city":"","cases":47579,"newcases":305,"7rate":3.73,"deaths":513,"date":"2020-12-15″},
地名から緯度と経度を取得
呼び方
https://covid19api.tmsoftwareinc.com/v1/geos?location=東京
返される値:JSON
{“lat":35.6803997,"lng":139.7690174}
最新の全国コロナ感染者数データを取得
呼び方
https://covid19api.tmsoftwareinc.com/api/v1/jabounds
返される値:JSONリスト
[{“state":"Aichi","county":"","city":null,"lat":35.035551,"lng":137.211621,"cases":13535,"newcases":238,"date":"2020-12-18″,"sevenrate":2.67},
{“state":"Akita","county":"","city":null,"lat":39.748679,"lng":140.408228,"cases":94,"newcases":0,"date":"2020-12-18″,"sevenrate":0.06},
{“state":"Aomori","county":"","city":null,"lat":40.781541,"lng":140.828896,"cases":390,"newcases":7,"date":"2020-12-18″,"sevenrate":0.35},
{“state":"Chiba","county":"","city":null,"lat":35.510141,"lng":140.198917,"cases":8663,"newcases":148,"date":"2020-12-18″,"sevenrate":1.88},
{“state":"Ehime","county":"","city":null,"lat":33.624835,"lng":132.856842,"cases":372,"newcases":2,"date":"2020-12-18″,"sevenrate":0.19},
{“state":"Fukui","county":"","city":null,"lat":35.846614,"lng":136.224654,"cases":337,"newcases":0,"date":"2020-12-18″,"sevenrate":0.11},
使用しているテクニックの詳細
RESTful API呼び出し方法
接続パレットにあるWebコンポーネントを使います。下のようにAPI呼び出しURLに必要な引数を結合してからWebコンポーネントのURLに設定し、WebコンポーネントのGetメソッドを呼び出します。
Getメソッドは非同期で呼び出されるので、下の「いつもテキストに受け取ったら」を使って別途受け取る結果の処理を行います。
JSONリストの扱い方法
「いつもテキストに受け取ったら」で受け取る「レスポンスコンテント」をWebコンポーネントのJsonTextDecodeWithDictionariesメソッドに渡して、連想配列(dictionary)のリストに変換します。
リスト内の要素を一つ取り出すときは「リスト内の順番の要素を取得」を、ループで全ての要素を取り出すときは「それぞれの項目リスト内の」を使います。
取り出した要素は連想配列(dictionary)なので、キーを指定して値を取得します。
JSONリストのクイックソート方法
リストをQuick Sortアルゴリズムを使ってソートします。Dataにはソートするリストをleftにはソートするリストの最初の順番(通常は1)をrightにはソートするリストの最後の順番(通常はリストの要素数)をcolumnにはキーを指定します。
以下がQuick Sortを行う手続きです。これは https://appinventorplus.wordpress.com/2017/04/12/quicksort-routine-for-your-app-inventor-apps/ 掲載の手続きを少し変更した物です。オリジナルの手続きはMIT App Inventor Galleryのここにあります。
GPS
GPSによる現在地の取得にはApp Inventor 2のセンサー関連パレットにある位置センサーコンポーネントを利用します。詳細はこちらを見てください。
マップ
マップはApp Inventor 2のマップ関連パレットにあるコンポーネントです。詳細はこちらを見てください。
TinyDB
TinyDBはApp Inventor 2のストレージパレットにあるコンポーネントです。詳細はこちらを見てください。
プロジェクトを作成
[プロジェクト]メニューから[プロジェクトを新規作成]を選択し、”casemap”と名前を付けます。
デザイン編集
レイアウトとコンポーネントの配置
下図のようにレイアウトとコンポーネントを配置します。
- 使用するイメージファイルを2個メディアにアップロードします。ファイルはCaseMapIcon.pngとcaution-4-01.pngです。それぞれをクリックしてダウンロードしてください。CaseMapIcon.pngはScreen1のプロパティのアイコンに選びます。Screen1のプロパティのアプリ名は「新型コロナ感染者数マップ」、タイトルは「新型コロナ感染者数マップ」にします。
- 見えないコンポーネントとして接続パレットにあるWebを3個(ドラッグアンドドロップすると自動的にWeb1, Web2, Web3という名前になります)、センサーパレットにある位置センサー、ストレージパレットにあるTinyDBをドラッグアンドドロップします。
- 縦並びレイアウトを配置し「縦並び外側」と名前を変更したあと、その中に上から順番に横並び日付、縦並び内側、横並びヘルプ、マップ関連パレットからマップ1、横並びボタン、横並び状況、横並びデータソースを配置します。
- 次に順番にレイアウトの中にコンポーネントを配置していきます。横並び日付の中には日付という名前でラベルを、縦並び内側の中には横並び現在地(中に現在地という名前でラベル)、横並び感染率(中に感染率ラベル、感染率という名前で2個のラベル)、横並び新規(中に新規ラベル、新規感染者数という名前で2個のラベル)、横並び累積(中に累積ラベル、累積感染者数という名前で2個のラベル)を配置します。各ラベルのテキストは上の図の値にしてください。
- 横並びヘルプの中には注意イメージという名前でイメージと、ヘルプという名前でラベルを配置します。注意イメージの画像ファイルはcaution-4-01.pngを選びます。そのままだと大きいので、高さと幅は16ピクセルにします。ヘルプのテキストは「感染者数を知りたい場所で長押ししてください」にします。
- マップ1の中にはマップ関連パレットからマーカー1を配置します。マップ1の中心の緯度、経度は35.685750628984465, 139.75407754498727にすると皇居が中心になります。マーカー1の緯度、軽度も同じ値にしてください。
- 横並びボタンの中には場所テキストボックス、場所検索ボタン、現在地ボタン、全国ボタンを配置します。場所検索ボタン、現在地ボタン、全国ボタンのテキストは上の図の値にしてください。
- 横並び状況の中には状況ラベルを、横並びデータソースの中にはデータソースラベルを配置します。データソースラベルのテキストは「ジョンズ・ホプキンス大学のデータを使用しています」にします。
ブロック編集機能を使用したプログラミング
グローバル変数定義
- コロナAPI: 緯度と経度からその都道府県のコロナ感染者数の時系列データを取得するAPIのURL https://covid19api.tmsoftwareinc.com/v1/latlngs?
- コロナAPI2: 地名から緯度と経度を取得するAPIのURL https://covid19api.tmsoftwareinc.com/v1/geos?
- コロナAPI3: 最新の全国コロナ感染者数データを取得するAPIのURL https://covid19.tmsoftwareinc.com/api/v1/jabounds
- 初期状況メッセージ: 状況ラベルの初期値
- 全国緯度: 全国表示する際のマップの中心緯度
- 全国経度: 全国表示する際のマップの中心経度
- 全国ズーム: 全国表示する際のマップのズームレベル
- 初期緯度: マップの中心緯度の初期値
- 初期経度: マップの中心経度の初期値
- 初期ズーム: マップのズームレベルの初期値
- 初期住所: 現在地ラベルの初期値
- データ無し: データがない時のメッセージ
- ヘルプ: ヘルプラベルの初期値=「は新規感染者数/10万人が高い都道府県を示していて、タップするとその数値を表示します。地名を入力して場所検索ボタンをクリックするとその場所に移動して感染者情報を表示します。感染者数を知りたい場所で長押しても感染者数情報を表示できます。」
- 新規感染者数: 新規感染者数
- 感染率: 感染率
- マーカーリスト: 全国表示の際に感染率の高い場所に表示するマップ内マーカーのリスト
- 感染率マーカー: 全国表示の際に感染率の高い場所に表示するマップ内マーカーの一時的な格納変数
- 緯度: マップの現在の中心緯度
- 経度: マップの現在の中心経度
- 地図ズーム: マップの現在のズームレベル
- JSONリスト: APIから取得したJSONリストの格納変数
- JSON要素: JSONリストから取り出したJSON要素の格納変数
- JSONリスト2: APIから取得したJSONリストの格納変数2
- JSON要素2: JSONリスト2から取り出したJSON要素の格納変数
都道府県名翻訳用連想配列定義
APIから返される都道府県名は英語なので、それを日本語に翻訳するために連想配列を定義してグローバル変数に格納しています。
手続き
繰り返し使用するコードや複雑なコードは手続きで定義します。
- JSONリストのクイックソート:こちらを見てください。
- 感染者取得:緯度と経度からその都道府県のコロナ感染者数の時系列データを取得します。
- 全マーカー表示、全マーカー非表示:マップ内マーカーをすべて表示したり、非表示したりします。
スクリーン初期化に伴う作業など
- ヘルプラベル、状況ラベル、現在地ラベルを初期化します。
- TinyDBから前回使用した緯度、経度、ズームレベルを取得しグローバル変数の緯度、経度、ズームに設定します。初回起動時はグローバル変数の全国緯度、全国経度、全国ズームを使用します。
- グローバル変数の緯度、経度、地図ズームでマップをパンします。
- 緯度と全国緯度が等しくない場合は初回起動ではないので、マーカーは現在地に表示し感染者取得手続きを呼び出します。そうでない場合は初回起動なのでマーカーを非表示にし、縦並び内側も非表示にして都道府県ごとの感染者数情報を表示しません。
- 最新の全国コロナ感染者数データを取得するAPIを呼び出します。
緯度と経度からその都道府県のコロナ感染者数の時系列データを取得した時の処理
感染者数の時系列データの取得にはWeb1コンポーネントを使用してAPIを呼び出しています。結果は非同期で返ってくるので、その際の処理を定義します。
- 返ってきた結果をグローバル変数のJSONリストに格納します。
- もしリストの長さが0ならば、縦並び内側を非表示にして都道府県ごとの感染者数情報を表示しません。状況ラベルにはデータ無しと表示します。
- そうでなければ、縦並び内側を表示にして状況ラベルは空白にします。引き続き以下の手順を実行します。
- JSONリストの最初の要素をJSON要素に格納します。
- もしJSON要素のcountryキーの値がJapanでは無いならば現在地ラベルにcountry+state+cityを結合した文字を、countryキーの値がJapanならばstateを都道府県名翻訳用連想配列を使って日本語に翻訳して現在地ラベルに表示します。
- JSON要素のdateキーの値を日付ラベルに表示します。
- もしJSON要素の7rate(新規感染者数の7日間移動平均)キーの値が-1(未定義)で無いならばグローバル変数の感染率にその値を格納し、そうでなければ「不明」を格納します。引き続き感染率ラベルにグローバル変数の感染率を表示します。
- もしJSON要素のnewcases(新規感染者数)キーの値が-1(未定義)で無いならばグローバル変数の新規感染者数にその値を格納し、そうでなければ「不明」を格納します。引き続き新規感染者数ラベルにグローバル変数の新規感染者数を表示します。
- 累積感染者数ラベルにJSON要素のcases(累積感染者数)を表示します。
- TinyDBに緯度、経度、ズームレベルを格納します。
地名から緯度と経度を取得した時の処理
地名からの緯度と経度の取得にはWeb2コンポーネントを使用してAPIを呼び出しています。結果は非同期で返ってくるので、その際の処理を定義します。
- 返ってきた結果はリストでは無いのでグローバル変数のJSON要素に格納します。
- もしJSON要素のlatキーの値がnot foundで無いならばグローバル変数の緯度、経度にlatキーの値、lngキーの値を設定するとともにグローバル変数の地図ズームに初期ズームの値を設定し、グローバル変数の緯度、経度、地図ズームでマップをパンします。引き続きマーカー1を緯度、経度の場所に表示し、感染者数取得手続きを呼び出します。
- そうでなければ状況ラベルに「この場所は見つかりませんでした」と表示します。
最新の全国コロナ感染者数データを取得した時の処理
最新の全国コロナ感染者数データの取得にはWeb3コンポーネントを使用してAPIを呼び出しています。結果は非同期で返ってくるので、その際の処理を定義します。
- 返ってきた結果をグローバル変数のJSONリスト2に格納します。
- もしリストの長さが0ならば、縦並び内側を非表示にして都道府県ごとの感染者数情報を表示しません。状況ラベルにはデータ無しと表示します。
- そうでなければ、JSONリスト2をsevenrate(新規感染者数の7日間移動平均)で降順にクイックソートします。
- JSONリスト2の1番目から20番目まで以下の通りループ処理します。
- ローカル変数のJSON項目にJSONリスト2の現在の要素を設定します。
- JSON項目のdateキーの値を日付ラベルに表示します。
- JSON項目のlatキーの値、lngキーの値の位置にマーカーを作成してグローバル変数の感染率マーカーに格納し、マーカーのイメージをcaution-4-01.pngに設定し、マーカーのタイトルにstateキーの値を都道府県名翻訳用連想配列を使って日本語に翻訳したものとsevenrateキーの値を結合した文字列を設定します。そしてマーカーの情報ボックスを有効にします。
- もしも1番目(新規感染者数の7日間移動平均が国内最大)ならばマーカーの情報ボックスを表示します。
- 作成したマーカーを上書きして消さないようにグローバル変数のマーカーリストに感染率マーカーを追加します。
マップ関連の処理
マップ1が長押しされたら緯度、経度をグローバル変数の緯度、経度に格納し、マーカー1をその場所に移動して感染者数取得手続きを呼び出します。
マップ1の境界が変わったら(ドラッグ、パン、ズームされたら)状況ラベルに初期状況メッセージを表示します。
ボタンクリック処理
場所検索ボタン
- 入力された地名から緯度、経度を取得するAPIを呼び出します。
現在地ボタン
- 位置センサーの緯度が0でなければ(位置情報が取れていれば)位置センサーの緯度、経度をグローバル変数の緯度、経度に、グローバル変数の地図ズームに初期ズームの値を設定し、グローバル変数の緯度、経度、地図ズームでマップをパンします。引き続きマーカー1を緯度、経度の場所に表示し、感染者数取得手続きを呼び出します。
- そうでなければ状況ラベルに「GPS準備中」と表示します。
全国表示ボタン
- グローバル変数の全国緯度、全国経度、全国ズームでマップをパンした後、全マーカーを表示し、1番目(新規感染者数の7日間移動平均が国内最大)のマーカーの情報ボックスを表示します。