Last active
June 17, 2023 20:07
-
-
Save yano404/ece205af2e7e2c0ec15e to your computer and use it in GitHub Desktop.
気象庁のホームページから世界103地点の気象データを入手して、気候区分を判定するプログラム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
__version__ = '0.0.1' | |
## import required libraries | |
import pandas | |
from decimal import Decimal | |
import numpy as np | |
## CONSTANT | |
PROGRAM_DESCRIPTION = ''' | |
############################################################################### | |
ケッペンの気候区分判定プログラム | |
作者: KouQ7802 | |
ライセンス: GPLv3 | |
''' + 'バージョン: ' + __version__ + ''' | |
############################################################################### | |
''' | |
REGION = {0:'東アジア・シベリア', | |
1:'南アジア', | |
2:'ヨーロッパ', | |
3:'中東・アフリカ', | |
4:'北アメリカ', | |
5:'南アメリカ', | |
6:'オセアニア', | |
7:'南極'} | |
KOPPEN_CLIMATIC_DIVISION_LIST = {'Af':'熱帯雨林気候', | |
'Am':'熱帯雨林気候(弱い乾季あり)', | |
'Aw':'サバナ気候', | |
'BS':'ステップ気候', | |
'BW':'砂漠気候', | |
'Cfa':'温暖湿潤気候', | |
'Cfb':'西岸海洋性気候', | |
'Cs':'地中海性気候', | |
'Cw':'温暖冬季少雨気候', | |
'Df':'亜寒帯湿潤気候', | |
'Dw':'亜寒帯冬季少雨気候', | |
'ET':'ツンドラ気候', | |
'EF':'氷雪気候'} | |
## preprocess | |
# fetch climatic data from server of Japan Meteorological Agency | |
# 気象庁のWebページより世界の主要な地点の月別の気温・降水量平年値のデータを得る | |
CLIMATIC_DATA_SOURCE = 'http://www.data.jma.go.jp/gmd/cpd/monitor/mainstn/nrmlist.php' | |
RAW_CLIMATIC_DATA = pandas.io.html.read_html(CLIMATIC_DATA_SOURCE) | |
# rearrange CLIMATIC_DATA | |
# CLIMATIC_DATAを整理する | |
for i in range(len(RAW_CLIMATIC_DATA)): | |
for j in range(2, len(RAW_CLIMATIC_DATA[i]), 2): | |
for k in range(12, -1, -1): | |
RAW_CLIMATIC_DATA[i].xs(j)[k+2] = RAW_CLIMATIC_DATA[i].xs(j)[k] | |
RAW_CLIMATIC_DATA[i].xs(j)[0] = np.nan | |
RAW_CLIMATIC_DATA[i].xs(j)[1] = np.nan | |
## define functions | |
def show_region(): | |
for i in range(len(REGION)): | |
print(i, ':', REGION[i]) | |
print(len(REGION), ':', '全地域') | |
def show_city(region_key): | |
if region_key == len(REGION): | |
for i in range(len(RAW_CLIMATIC_DATA)): | |
for j in range(1, len(RAW_CLIMATIC_DATA[i]), 2): | |
print(i, REGION[i], ':', RAW_CLIMATIC_DATA[i][0][j]) | |
print('===============================================================================') | |
else: | |
for i in range(1, len(RAW_CLIMATIC_DATA[region_key]), 2): | |
print(i, ':', RAW_CLIMATIC_DATA[region_key][0][i]) | |
def search_index(city_name): | |
for i in range(len(RAW_CLIMATIC_DATA)): | |
for j in range(1, len(RAW_CLIMATIC_DATA[i]), 2): | |
if city_name in RAW_CLIMATIC_DATA[i][0][j]: | |
city_index = (i, j) | |
break | |
return city_index | |
def get_city_index(): | |
while True: | |
show_region() | |
while True: | |
print('判定対象の都市がある地域の番号を入力してください') | |
try: | |
region_key = int(input('-->')) | |
break | |
except ValueError: | |
continue | |
if region_key<0 or 8<region_key: | |
continue | |
show_city(region_key) | |
if region_key == 8: | |
continue | |
print('判定対象の都市は見つかりましたか?(Y/n)') | |
switch = input('-->') | |
if switch == 'Y' or switch == 'y': | |
break | |
else: | |
continue | |
while True: | |
print('都市名または都市の番号を入力してください') | |
city_name = input('-->') | |
try: | |
if isinstance(int(city_name), int): | |
if int(city_name) % 2 == 1: | |
city_index = (region_key, int(city_name)) | |
break | |
else: | |
pass | |
except ValueError: | |
pass | |
if isinstance(city_name, str): | |
try: | |
city_index = search_index(city_name) | |
break | |
except UnboundLocalError: | |
print('入力された都市は見つかりませんでした') | |
continue | |
else: | |
continue | |
return city_index | |
def show_target_city(city_index): | |
print('都市名: ', RAW_CLIMATIC_DATA[city_index[0]][0][city_index[1]]) | |
print('国名または地域名: ', RAW_CLIMATIC_DATA[city_index[0]][1][city_index[1]]) | |
print('太州名: ', REGION[city_index[0]]) | |
# generate climatic data(pandas.DataFrame) | |
def gen_pandas_dataframe(city_index): | |
city_climatic_data = pandas.DataFrame() | |
city_temperature = pandas.DataFrame() | |
city_precipitation = pandas.DataFrame() | |
for i in range(3,15): | |
city_temperature = \ | |
city_temperature.append( [Decimal(RAW_CLIMATIC_DATA[city_index[0]].xs(city_index[1])[i])] ) | |
if RAW_CLIMATIC_DATA[city_index[0]].xs(city_index[1]+1)[i] == '---': | |
city_precipitation = city_precipitation.append([np.nan]) | |
else: | |
city_precipitation = \ | |
city_precipitation.append( [Decimal(RAW_CLIMATIC_DATA[city_index[0]].xs(city_index[1]+1)[i])] ) | |
city_temperature = city_temperature.append([city_temperature.mean()]) | |
city_precipitation = city_precipitation.append([city_precipitation.sum()]) | |
city_climatic_data = pandas.concat([city_temperature, city_precipitation], axis=1) | |
city_climatic_data.index = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 'annual'] | |
city_climatic_data.columns = ['temperature', 'precipitation'] | |
return city_climatic_data | |
# judge North Hemisphere or South Hemisphere | |
def judge_north_south(city_climatic_data): | |
temperature_high_to_low = city_climatic_data[:12].sort('temperature', ascending=False) | |
if 4 <= temperature_high_to_low.index[0] <= 9: | |
north_south = True | |
else: | |
north_south = False | |
return north_south | |
# judge climatic region of target city | |
def judge_fsw(city_climatic_data): | |
max_precipitation = city_climatic_data['precipitation'][:12].max() | |
min_precipitation = city_climatic_data['precipitation'][:12].min() | |
precipitation_high_to_low = city_climatic_data[:12].sort('precipitation', ascending=False) | |
if judge_north_south(city_climatic_data): | |
if 4<= precipitation_high_to_low.index[11] <= 9: | |
if min_precipitation*3 <= max_precipitation: | |
climatic_region = 's' | |
else: | |
climatic_region = 'f' | |
else: | |
if min_precipitation*10 <= max_precipitation: | |
climatic_region = 'w' | |
else: | |
climatic_region = 'f' | |
else: | |
if 4<= precipitation_high_to_low.index[11] <= 9: | |
if min_precipitation*10 <= max_precipitation: | |
climatic_region = 'w' | |
else: | |
climatic_region = 'f' | |
else: | |
if min_precipitation*3 <= max_precipitation: | |
climatic_region = 's' | |
else: | |
climatic_region = 'f' | |
return climatic_region | |
# judge climatic zone of target city | |
def judge_ACDE(city_climatic_data): | |
climatic_division = {"climatic_zone":"", "climatic_region":"", "temperature":""} | |
max_temperature = city_climatic_data['temperature'][:12].max() | |
min_temperature = city_climatic_data['temperature'][:12].min() | |
max_precipitation = city_climatic_data['precipitation'][:12].max() | |
min_precipitation = city_climatic_data['precipitation'][:12].min() | |
if max_temperature < 10: | |
climatic_division["climatic_zone"] = "E" | |
if max_temperature >= 0: | |
climatic_division["climatic_region"] = "T" | |
else: | |
climatic_division["climatic_region"] = "F" | |
elif min_temperature >= 18: | |
climatic_division["climatic_zone"] = "A" | |
if min_precipitation >= 60: | |
climatic_division["climatic_region"] = "f" | |
else: | |
if (Decimal(-0.04)*Decimal(city_climatic_data['precipitation']['annual'])+100) > min_precipitation: | |
climatic_division["climatic_region"] = "w" | |
else: | |
climatic_division["climatic_region"] = "m" | |
elif min_temperature >= -3: | |
climatic_division["climatic_zone"] = "C" | |
climatic_division["climatic_region"] = judge_fsw(city_climatic_data) | |
if climatic_division["climatic_region"] == "f": | |
if max_temperature >= 22: | |
climatic_division["temperature"] = "a" | |
else: | |
climatic_division["temperature"] = "b" | |
else: | |
climatic_division["climatic_zone"] = "D" | |
climatic_division["climatic_region"] = judge_fsw(city_climatic_data) | |
return climatic_division | |
# judge climatic zone whether "B" or not | |
def judge_B(city_climatic_data,climatic_division): | |
if climatic_division["climatic_zone"] != "E": | |
annual_mean_temperature = city_climatic_data['temperature']['annual'] | |
annual_precipitation = city_climatic_data['precipitation']['annual'] | |
if climatic_division["climatic_region"] == "s": | |
arid_boundary = 20 * annual_mean_temperature | |
elif climatic_division["climatic_region"] == "f": | |
arid_boundary = 20 * (annual_mean_temperature+7) | |
elif climatic_division["climatic_region"] == "m": | |
arid_boundary = 20 * (annual_mean_temperature+7) | |
elif climatic_division["climatic_region"] == "w": | |
arid_boundary = 20 * (annual_mean_temperature+14) | |
if annual_precipitation < arid_boundary: | |
climatic_division["climatic_zone"] = "B" | |
if annual_precipitation < arid_boundary/2: | |
climatic_division["climatic_region"] = "W" | |
climatic_division["temperature"] = "" | |
else: | |
climatic_division["climatic_region"] = "S" | |
climatic_division["temperature"] = "" | |
else: | |
pass | |
return climatic_division | |
def show_result(city_index, city_climatic_data, climatic_division): | |
climatic_division_str = climatic_division["climatic_zone"]+\ | |
climatic_division["climatic_region"]+\ | |
climatic_division["temperature"] | |
print('=================================== result ====================================') | |
show_target_city(city_index) | |
if judge_north_south(city_climatic_data) == True: | |
print('北半球') | |
else: | |
print('南半球') | |
print('-------------------------------------------------------------------------------') | |
print(city_climatic_data) | |
print('-------------------------------------------------------------------------------') | |
print('気候区分: ', climatic_division_str) | |
print('気候区名: ', KOPPEN_CLIMATIC_DIVISION_LIST[climatic_division_str]) | |
print("===============================================================================") | |
# main function | |
def main(): | |
print(PROGRAM_DESCRIPTION) | |
city_index = get_city_index() | |
print(show_target_city(city_index)) | |
print('対象地点のINDEX:', city_index) | |
city_climatic_data = gen_pandas_dataframe(city_index) | |
climatic_division = judge_ACDE(city_climatic_data) | |
climatic_division = judge_B(city_climatic_data,climatic_division) | |
show_result(city_index, city_climatic_data, climatic_division) | |
## main process | |
if __name__ == '__main__': | |
main() | |
## end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment