つくば市の1年間の気温の推移をプロット with F#スクリプト

# まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207987/7c70bb43-58d9-5114-9749-68ccf314d009.png)

---

## 気持ち

やっぱりめっちゃギザギザでつらい、最近気温の変化が激しくて体調が辛いです。

[気象庁|過去の気象データ](https://www.data.jma.go.jp/gmd/risk/obsdl/index.php)のデータを利用しました。

今回はF#スクリプトから[FSharp.Data](https://fsharp.github.io/FSharp.Data/ja/index.html)と[XPlot](https://fslab.org/XPlot/)をつかってみました。1ファイル完結で50行くらいなので楽ですね。

---

# データの用意

## 気象庁のサイトからダウンロード

1. [気象庁|過去の気象データ](https://www.data.jma.go.jp/gmd/risk/obsdl/index.php)から
1. 目的の地名を選択して 
1. 1日毎の平均気温・最高気温・最低気温を選択して
1. 10年分くらいまとめてダウンロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207987/b8f67f58-9834-54e6-1e2c-ac29c0d08a34.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207987/22de950e-b83d-88ce-d3af-2663e35d0d04.png)


---

## CSVファイルの手直し

ヘッダーが狂ったCSVファイル（しかもShiftJIS）が降ってくるので、

```data.csv
ダウンロードした時刻：2020/06/26 19:21:13

,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）
年月日,平均気温(℃),平均気温(℃),平均気温(℃),最高気温(℃),最高気温(℃),最高気温(℃),最低気温(℃),最低気温(℃),最低気温(℃)
,,,,,,,,,
,,品質情報,均質番号,,品質情報,均質番号,,品質情報,均質番号
2010/6/25,24.3,8,1,30.9,8,1,17.9,8,1
2010/6/26,24.7,8,1,28.5,8,1,20.1,8,1
...略
```

---

1. ヘッダーを消去して、
1. ShiftJISからUTF-8に変換して、 (VSCodeの機能でできますね)
1. いい感じに書き換えます。

```diff:data.csv
- ダウンロードした時刻：2020/06/26 19:21:13
- 
- ,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）,つくば（館野）
- 年月日,平均気温(℃),平均気温(℃),平均気温(℃),最高気温(℃),最高気温(℃),最高気温(℃),最低気温(℃),最低気温(℃),最低気温(℃)
- ,,,,,,,,,
- ,,品質情報,均質番号,,品質情報,均質番号,,品質情報,均質番号
+ 年月日,平均気温(℃),,,最高気温(℃),,,最低気温(℃),,
2010/6/25,24.3,8,1,30.9,8,1,17.9,8,1
2010/6/26,24.7,8,1,28.5,8,1,20.1,8,1
...略
```

こうなる。作業用ディレクトリに置きましょう。

---

# F#スクリプトを書く

## 準備
手元の.NET Coreは3.1.201、 エディタはVSCode + Ionideを使ってます。

F#5.0の機能を利用します。2020/06/26現在ではまだプレビュー版なので、以下の記事を参考に指定する必要があります。

[F#スクリプトでNuGetパッケージを使って爆速開発](https://qiita.com/Midoliy/items/75ef70b701eae5df83aa)

作業用ディレクトリに`temperatures.fsx`というファイルを作る。

```
TemperaturesPlot
|--data.csv
|--temperatures.fsx
```

---

## 書いた

分けてありますが、上から順に実行されるだけなので素直な心で眺めていきましょう。

F#5.0の機能で、[FSharp.Data](https://fsharp.github.io/FSharp.Data/ja/index.html)と[XPlot](https://fslab.org/XPlot/)を[nuget](https://www.nuget.org/)（.NETのパッケージマネージャ）から直接読み込ませます。

```fsharp:temperatures.fsx
#r "nuget: FSharp.Data"
#r "nuget: XPlot.GoogleCharts"

// ファイルパスを指定
// なお、相対パスで指定すると失敗しました。一時ディレクトリに展開されたりするから？
let [<Literal>] SourcePath = __SOURCE_DIRECTORY__ + @"/data.csv"

// 静的型付きCSV、うれしい
type Weather = FSharp.Data.CsvProvider<SourcePath>

// そのままサンプルに使ったデータを取得
let data = Weather.GetSample()
```

---

FSharp.Dataのおかげで、自動で型がついてプロパティアクセスできます。
`Seq`モジュールの関数でデータを加工しましょう。

```fsharp

let oldestDate = (data.Rows |> Seq.head).年月日
let latestDate = (data.Rows |> Seq.last).年月日
let startDate = latestDate.AddYears(-1)

let temperatures =
  data.Rows
  // 直近一年分を表示したい
  |> Seq.filter (fun r -> startDate <= r.年月日)
  // (横軸, 縦軸)のデータの組を作る
  |> Seq.map(fun r ->
    (r.年月日, r.平均気温), (r.年月日, r.最高気温), (r.年月日, r.最低気温))
  |> Seq.toList
  // list<'T1 * 'T2 * 'T3> -> list<'T1> * list<'T2> * list<'T3>
  |> List.unzip3
  // XPlotが利用する形式に変換
  |> fun (a, b, c) -> [a; b; c]
```

---

```fsharp
open XPlot.GoogleCharts

let [<Literal>] Place = "つくば（館野）"

temperatures
|> Chart.Line
|> Chart.WithOptions(
  Options
    ( colors = [|"orange"; "red"; "blue"|]
    , legend = Legend(position = "right") ))
|> Chart.WithLabels [ "平均気温"; "最高気温"; "最低気温" ]
|> Chart.WithXTitle "年月日"
|> Chart.WithYTitle "気温(℃)"
|> Chart.WithTitle (
  sprintf "%sの気温の推移（%s ~ %s）"
    Place ((max oldestDate startDate).ToString "yyyy/MM/dd") (latestDate.ToString "yyyy/MM/dd"))
|> Chart.WithHeight 800
|> Chart.Show
```

VSCode右上の三角ボタンを押して実行、ブラウザにGoogleChartの結果が表示された。

---

再掲

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207987/7c70bb43-58d9-5114-9749-68ccf314d009.png)