💻

日本版 Google COVID-19 Forecast データを取得する Go パッケージを作ってみた

2021/02/14に公開

週末の余暇を利用して日本版 Google COVID-19 Forecast データを取得するコマンドライン・ツールを作ってみたのだが

https://github.com/spiegel-im-spiegel/cov19jpn

これ自体は Go で書いているのでパッケージとしても利用できる。リポジトリの sample ディレクトリにいくつかコード例を置いているので参考にして欲しい。

たとえば

// +build run

package main

import (
    "bytes"
    "context"
    "fmt"
    "io"
    "net/http"
    "os"

    "github.com/spiegel-im-spiegel/cov19jpn/entity"
    "github.com/spiegel-im-spiegel/cov19jpn/fetch"
    "github.com/spiegel-im-spiegel/cov19jpn/filter"
    "github.com/spiegel-im-spiegel/cov19jpn/values/prefcodejpn"
)

func main() {
    r, err := fetch.Web(context.Background(), &http.Client{})
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    defer r.Close()
    es, err := fetch.Import(
        r,
        filter.New(
            prefcodejpn.TOTTORI,
            prefcodejpn.SHIMANE,
            prefcodejpn.OKAYAMA,
            prefcodejpn.HIROSHIMA,
            prefcodejpn.YAMAGUCHI,
        ),
    )
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    list := entity.NewList(es)
    list.Sort()
    _, _ = io.Copy(os.Stdout, bytes.NewReader(list.EncodeCSV()))
}

などとすれば中国5県のデータを抽出できる。

既にローカルにダウンロードした CSV ファイルを使うのであれば

r, err := fetch.Web(context.Background(), &http.Client{})

の代わりに

r, err := fetch.File("./forecast_JAPAN_PREFECTURE_28.csv")

としてもOK。

fetch.Import() 関数の結果は

package entity

import (
    "encoding/json"

    "github.com/spiegel-im-spiegel/cov19jpn/values/date"
    "github.com/spiegel-im-spiegel/cov19jpn/values/prefcodejpn"
)

type Entity struct {
    JapanPrefectureCode             prefcodejpn.Code `json:"japan_prefecture_code"`
    PrefectureName                  string           `json:"prefecture_name"`
    TargetPredictionDate            date.Date        `json:"target_prediction_date"`
    CumulativeConfirmed             *json.Number     `json:"cumulative_confirmed,omitempty"`
    CumulativeConfirmedQ0025        *json.Number     `json:"cumulative_confirmed_q0025,omitempty"`
    CumulativeConfirmedQ0975        *json.Number     `json:"cumulative_confirmed_q0975,omitempty"`
    CumulativeDeaths                *json.Number     `json:"cumulative_deaths,omitempty"`
    CumulativeDeathsQ0025           *json.Number     `json:"cumulative_deaths_q0025,omitempty"`
    CumulativeDeathsQ0975           *json.Number     `json:"cumulative_deaths_q0975,omitempty"`
    HospitalizedPatients            *json.Number     `json:"hospitalized_patients,omitempty"`
    HospitalizedPatientsQ0025       *json.Number     `json:"hospitalized_patients_q0025,omitempty"`
    HospitalizedPatientsQ0975       *json.Number     `json:"hospitalized_patients_q0975,omitempty"`
    Recovered                       *json.Number     `json:"recovered,omitempty"`
    RecoveredQ0025                  *json.Number     `json:"recovered_q0025,omitempty"`
    RecoveredQ0975                  *json.Number     `json:"recovered_q0975,omitempty"`
    CumulativeConfirmedGroundTruth  *json.Number     `json:"cumulative_confirmed_ground_truth,omitempty"`
    CumulativeDeathsGroundTruth     *json.Number     `json:"cumulative_deaths_ground_truth,omitempty"`
    HospitalizedPatientsGroundTruth *json.Number     `json:"hospitalized_patients_ground_truth,omitempty"`
    RecoveredGroundTruth            *json.Number     `json:"recovered_ground_truth,omitempty"`
    ForecastDate                    date.Date        `json:"forecast_date"`
    NewDeaths                       *json.Number     `json:"new_deaths,omitempty"`
    NewConfirmed                    *json.Number     `json:"new_confirmed,omitempty"`
    NewDeathsGroundTruth            *json.Number     `json:"new_deaths_ground_truth,omitempty"`
    NewConfirmedGroundTruth         *json.Number     `json:"new_confirmed_ground_truth,omitempty"`
    PrefectureNameKanji             string           `json:"prefecture_name_kanji,omitempty"`
}

で定義される構造体の配列として返されるので,そのまま JSON 形式に encode することも可能である。また entity.NewList() 関数で entity.EntityList 型にラッピングすればソートやデータの絞り込みや CSV への encode 等が楽にできるようになる。

棒グラフについては

// +build run

package main

import (
    "context"
    "fmt"
    "net/http"
    "os"

    "github.com/spiegel-im-spiegel/cov19jpn/chart"
    "github.com/spiegel-im-spiegel/cov19jpn/entity"
    "github.com/spiegel-im-spiegel/cov19jpn/fetch"
    "github.com/spiegel-im-spiegel/cov19jpn/filter"
    "github.com/spiegel-im-spiegel/cov19jpn/values/prefcodejpn"
)

func main() {
    r, err := fetch.Web(context.Background(), &http.Client{})
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    defer r.Close()
    prefcode := prefcodejpn.TOKYO
    es, err := fetch.Import(
        r,
        filter.New(prefcode),
    )
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        return
    }
    list := entity.NewList(es)
    hlist := chart.New(list.StartDayMeasure(), list.EndDayMeasure().AddDay(7), 7, list)
    if err := chart.MakeHistChart(hlist, prefcode.Title(), "./output.png"); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }
}

とすればコマンドライン版と同じ

output.png

てな感じの出力を得られる。まぁ,グラフについては好みなどもあるので,あまり参考にならないだろう。私はデザイン・センスが壊滅してるので(笑)

よろしかったらどうぞ。

参考リンク

https://zenn.dev/spiegel/scraps/e992be8b03eeb7
https://text.baldanders.info/release/2021/02/cov19jpn/

GitHubで編集を提案

Discussion