iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
💻

Developing a Go Package to Retrieve Google COVID-19 Forecast Data for Japan

に公開

I spent some of my leisure time over the weekend creating a command-line tool to retrieve the Japanese version of Google COVID-19 Forecast data.

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

Since this itself is written in Go, it can also be used as a package. I have placed several code examples in the sample directory of the repository, so please refer to them.

For example:

// +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()))
}

You can extract data for the five prefectures in the Chugoku region like this.

If you want to use a CSV file already downloaded locally:

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

You can use the following instead:

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

The result of the fetch.Import() function is returned as an array of structs defined as follows:

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"`
}

Since it is returned as an array, you can encode it directly into JSON format. Also, by wrapping it into the entity.EntityList type using the entity.NewList() function, tasks like sorting, filtering data, and encoding to CSV become much easier.

Regarding bar charts:

// +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)
    }
}

Doing this will give you an output like this, which is the same as the command-line version:

output.png

Well, as for graphs, people have their own preferences, so this might not be very helpful. My design sense is catastrophic (haha).

Please feel free to use it if you like.

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

GitHubで編集を提案

Discussion