Z-GISで圃場ごとの積算温度を表示する


# この記事について
[Z-GIS](https://z-gis.net/)は、JA全農から提供されている営農管理システムです。
今回、Z-GISで管理しているデータを、システムの外側からPythonで作成したアプリケーションで変更し、積算温度を表示させるプログラムを作成したので公開します。

コードは、[github　https://github.com/keinafarm/AccTemp](https://github.com/keinafarm/AccTemp)に載せています。

# Z-GISについて
Z-GISは、営農管理システムではあるのですが、とてもユニークな仕組みになっていて、データの管理をExcelファイルで行っています。
従って、Excelファイルを直接変更出来れば、Z-GISで管理しているデータを書き換える事が出来ます。勿論Excelでも可能です。

、、、というか、Z-GIS自体は営農的な事に特化されていなくて（営農管理をサポートする機能はあります）、システムの基本的な機能は、地図上のデータとExcelファイル上のデータを関連付けるというだけのものです。

本来、農地とそれを管理するデータという構成にするのですが、それにとらわれずに、下記の例のように、仕掛けた罠の管理をしたり
![cats.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99652/4c06096a-f7b7-da0c-161f-aaa1b09f28af.jpeg)

グルメマップを作ったりする事が出来ます。
![cats2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99652/c589a3ab-1665-09c0-2415-c840c1b0fd87.jpeg)

そんなわけで、Z-GISは農家だけでなく、幅広く色々な用途に利用する事が可能です。
（全農がそれを望んでいるかどうかは別の話です）

# AccTempについて
## 作成の動機
今回作成した、AccTempは、積算温度を計算しExcelファイルに反映させる為のプログラムです。
個人的な用途としては、稲の収穫時期の管理に使うために作りました。
稲は、穂揃期からの積算温度によって収穫適期を知ることが出来ます。
この為、各圃場ごとに、穂揃期になった日付を登録しておく事により、収穫時期が何時頃なのかを知る事が出来ます。

## Excelファイルの形式
Z-GISにおけるExcelファイルの形式には、下記のルールがあります

- A1セルには”\_\_xl$gis\_\_”の文字列が入っている（他にもシートの用途で別の文字列が入る場合があります）
- A2以降のセルは、カラムの値の属性値(c:文字列、n:整数、f:小数、d:日付)のいずれかが入る
- B1セルは"."
- B2以降のセルは、カラム名が入る
- 日付のカラムは書式設定で日付にしておかないと、何かと不便

一般的には、Z-GISで先にファイルを作り、ポリゴンで位置を指定し、一旦セーブしてから、カラムを追加する方が、なにかと便利です。

今回作成したAccTempでは、下記のルールでデータを操作します。

- シート名が「積算温度」で始まっているシートのみが対象となる
- "開始日","終了日","目標積算温度","現状積算温度","目標到達度","予測終了日"のカラム名が指定されているカラムが操作対象となる
- 開始日:積算温度として加算し始める最初の日（収穫時期の例では、穂揃期の日付になります）
- 終了日:積算温度の集計を終了する日（日付が指定されていれば、指定された日まで集計しますが、このセルが空白の場合は、前日までの積算温度を計算します）
- 目標積算温度：これが指定されていれば、"目標到達度","予測終了日"を計算します
- 現状積算温度：開始日からの積算温度（終了日が指定されていれば、その日まで）
- 目標到達度：現状積算温度／目標積算温度
- 予測終了日：積算温度が目標積算温度に到達すると予測される日

予測終了日は、開始日からの積算温度が目標積算温度になるまでの日付で、前日までに到達していれば、到達した日付が記載されます。
前日までに到達していなければ、平年気温を元に、到達日を予測します。

## AccTempの起動方法

Exeファイル化はしていないので、コマンドラインから起動する事になります
コマンド形式は、下記の通りです。

python AccTemp Excelファイル名 県名 地点名

県名と地点名は、気象庁の[過去の気象データ・ダウンロード](https://www.data.jma.go.jp/gmd/risk/obsdl/)サイトにおける、県の名前と地点の名前になります。



## とりあえずお断り
本プログラムにおける注意点です。

- このプログラムは、自分が使うために作ったものなので、ユーザーの入力ミスなどのエラー処理は気分でしか行っておりません。
- 気象データは、気象庁からスクレイピングで取得しています。その事に関しての責任を負えませんので、自己責任でお願いします。責任を負えない方のご使用はお断りします。
- それ以上に、本プログラムを使用した結果発生する、いかなる問題にも責任を負いません。不安な方はソースを解析し、十分納得した上でご使用ください。
- ちなみに、「高知県」「窪川」以外の地点でのテストは行っていません。
- というか、テストケースは網羅的ではないです。
- 面目ないです

## 使用しているpythonやらなんやら
このプログラムは、windows上で開発しています。
Pythonは3.9.1です。使用したパッケージとバージョンは下記の通りです

|パッケージ|バージョン|
|:-----------|:------------|
|cssselect|1.1.0|
|et-xmlfile|1.0.1|
|jdcal|1.4.|
|lxml|4.6.2|
|numpy|1.20.0rc2|
|openpyxl|3.0.5|
|pandas|1.2.0rc0|
|pip|20.3.3|
|python-dateutil|2.8.1|
|pytz|2020.5|
|setuptools|51.1.0.post2020122|
|six|1.15.0|

## クラス構造
本プログラムは、主に４つのクラスから構成されています

- AccTemp : メインクラス
- ATWorkBook : Excel File操作部
- TemperatureCalculator : 積算温度計算部
- MeteorologicalAgency : 気象庁のサイトから、平均気温と平年気温を取得する

### AccTemp : メインクラス
AccTempでは、下記の処理を行っています

- コマンドラインから、ファイル名、県名、地点名を得る
- 指定されたファイル名でATWorkBookオブジェクトを作りExcelファイルを読み込む
- Excelファイル内に記載されている、開始日と終了日から、気象庁から取得する期間を決定する
- 決定された期間によりTemperatureCalculatorオブジェクトで積算温度を計算する
- ATWorkBookオブジェクトにより、Excelのデータをファイルに上書きする

### ATWorkBook : Excel File操作部
Excelファイルの操作に、openpyxlを使っています。
このクラスのお仕事は、Excelファイルのデータを、クラス属性に見せることです。
ATWorkBookは、複数のATSheetのリストを抱えています。
このリストは、sheets_list属性として読むことが出来ます。

sheets_listが提供するデータは、ATSheetオブジェクトです。シート単位でデータを管理します。
ATSheetオブジェクトのdata_listで、ATRowオブジェクトのリストが取得出来ます。
ATRowオブジェクトは、１行単位のデータを管理します。

ATRowオブジェクトの、クラス属性は"開始日","終了日","目標積算温度","現状積算温度","目標到達度","予測終了日"のセルに対応しており、クラス属性へのアクセスは、そのままExcelデータのアクセスと同じになります。

但し、クラス属性に対応するカラムが存在しない場合、そのクラス属性を読みだした場合、いつでもNoneが返されます。またそのクラス属性への書き込みは無視されます。
（この為、このクラス属性に値をセットしても、読み出す事は出来ません。この仕様ちょっと失敗したかと思ってる）

ATWorkBook.flash()で、実際のExcelファイルに値を反映させる事が出来ます。

### TemperatureCalculator : 積算温度計算部
このクラスのお仕事は、指定された期間の積算温度を計算する事と、平均気温と平年温度の両方を使って、目標積算温度に到達する"予測終了日"を求める事です。

このクラスは、次に説明するMeteorologicalAgencyオブジェクトを抱えます。
同じ時点の温度データを何度も気象庁から持ってくるのはよろしくないので、このクラスでは、同じ地域の既に読み込まれた期間を指定された場合、既に生成されたオブジェクトを返すように出来ています。

今回の仕様では、実際にはAccTempが、必要十分な期間を算出してTemperatureCalculatorを生成するので、この機能が使われる事はありません。

TemperatureCalculator クラス内部では、データをPandasの形式で抱えています。
なんでかというと、もうちょっとなんか色々するかと思ったからですけど、実際には積算くらいにしか使っていないので、ただのリストでも良かったかなぁと、今は思ってますけど。

### MeteorologicalAgency : 気象庁のサイトから、平均気温と平年気温を取得する
この部分は[barusan/jmadata.py](https://gist.github.com/barusan/3f098cc74b92fad00b9bb4478da35385)から拝借して改造しました。
主な変更点は、
"optionNumList": ' [["op1", 0]]'
として、平年値も取得出来るようにしたところです。

MeteorologicalAgency.get_temperature_list
で、取得した気温データを得ることが出来ますが、この時点でPandasのDataFrameになっています。

## 動作結果
本プログラムを動作させた結果を示します。

![cats3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99652/a6fede7e-f4cd-3f2b-3f6e-9a03a0384532.jpeg)

これはtest2.xlsxのデータをtest1.xlsxにコピーしてから
 python AccTemp test1.xlsx 高知 窪川
と実行した結果です。

Z-GISから、ラベル表示を選び"現状積算温度","目標到達度","予測終了日"をラベル表示させると、圃場単位に、収穫適期が表示されます。
（今回は、過去の気象データと実際の収穫日を入れているので、「本当だったらこの日に収穫するのが良かったのに」の日と、稲刈りした時点で、目標積算温度とどれだけ違っていたかの割合を示す数値になっています）

# 終わりに
実はZ-GISには、気温を取得したり、積算温度を求めたり、達成日を予測する機能があります。しかも気象庁からのスクレイピングではなくて、1kmメッシュで取得出来ます。

、、、、なのですが、そのデータを複数の圃場に結びつける方法がありません。

本当は、Z-GIS内に、それを実現する関数が欲しいところです。