Hello, I wrote this code in order to obtain a series of monthly weather observations at Helsinki for a period from 1960 to 2020 and then I saved the data to a local file using package pickle. I used the data available from the API provided by the Finnish Meteorological Institute.
import datetime
import requests
import lxml.etree as etree
from pprint import pprint
import pickle
import pandas as pd
import numpy as np
class FmiApi:
"""
a minimalistic wrapper for the Finnish Meteorological Institute API
"""
def __init__(self):
self.base_url = 'http://opendata.fmi.fi/wfs'
self.fixed_params = {
'service': 'WFS',
'version':'2.0.0',
}
self.namespaces ={
'wfs':'http://www.opengis.net/wfs/2.0',
'gml':'http://www.opengis.net/gml/3.2',
'BsWfs':'http://xml.fmi.fi/schema/wfs/2.0'
}
def get_monthly_obs(self, place, year, month, maxlocations=5):
"""
get monthly simple observation
in:
place [str]
year [int]
month [int]
maxlocations [int] (optional)
out:
dictionary with tuple of locations and times keys
and dictionary of parameter names and values as values
tmon <=> temperature
rrmon <=> rainfall
"""
sdate = str(datetime.date(year,month,1))
parms = {
'request': 'getFeature',
'storedquery_id': 'fmi::observations::weather::monthly::simple',
'place':place.lower(),
'maxlocations':'%d'%maxlocations,
'starttime': sdate + 'T00:00:00',
'endtime': sdate + 'T00:00:00',
}
parms.update(self.fixed_params)
try:
resp = requests.get(self.base_url, params=parms, stream=True)
except:
raise Exception('request failed')
if resp.status_code != 200: raise Exception('FMI returned status code %d'%resp.status_code)
resp.raw.decode_content=True
try:
root = etree.parse(resp.raw)
except:
raise Exception('parsing failed')
members = root.xpath('//wfs:member', namespaces=self.namespaces)
weather = {}
for member in members:
ppos = member.xpath('.//gml:pos', namespaces=self.namespaces)[0].text.strip()
ppos = tuple([float(x) for x in ppos.split()])
ptime = member.xpath('.//BsWfs:Time', namespaces=self.namespaces)[0].text.strip()
if not ppos in weather:
weather[ppos] = {}
pname = member.xpath('.//BsWfs:ParameterName', namespaces=self.namespaces)[0].text.strip()
pvalue = member.xpath('.//BsWfs:ParameterValue', namespaces=self.namespaces)[0].text.strip()
weather[ppos][pname] = (pvalue, ptime)
return weather
def test():
api = FmiApi()
weather = api.get_monthly_obs('kuusamo', 1985, 1)
pprint(weather)
try:
with open('wdata.pkl', 'rb') as f:
data=pickle.load(f)
except:
wheaters=[]
for year in range(1960,2021):
for month in range(1,13):
api = FmiApi()
w = api.get_monthly_obs('oulu', year, month )
wheaters.append(w)
pprint(w)
with open('wdata.pkl', 'wb') as f:
pickle.dump(wheaters, f)
Now I want to use the local file to access the data in order to plot the monthly average temperature for the years 1960 to 2020. I wrote this code but it doesn't print the average temperature
def pest():
df_weath = pd.read_csv('wdata.pkl', parse_dates=[0], infer_datetime_format=True)
df_weath.sort_values('Date', inplace=True, ignore_index=True)
df_weath['Date'] = df_weath['Date'].dt.date #convert to datetime objects
#input()
api = FmiApi() #instantiate the api
params = {
'place': u'helsinki',
'maxlocations': '5',
}
d0 = df_weath['date'].values[0]
d1 = df_weath['date'].values[-1]
n_days = (d1 - d0).days + 1 #number of days between d0 and d1
wdata = []
for i_day in range(n_days):
date = d0 + datetime.timedelta(days=i_day)
params['starttime'] = str(date) + 'T00:00:00'
params['endtime'] = str(date) + 'T00:00:00'
try:
print('requesting weather data for %s'%str(date))
weather = api.get_daily_obs(params)
except:
print('getting weather failed, skipping')
continue
wdata.append(weather)
#move weather data to a pandas dataframe (calculate avg over valid observations)
date = []
temps=[]
variables = ['tday']
for wobs in wdata:
avgs = {}
for pos, obs in wobs.items():
for var, xx in obs.items():
if not var in variables: continue
date = datetime.date(1990,6,15)
if xx[0] != 'NaN':
val = float(xx[0])
else:
val = None
if not var in avgs: avgs[var] = []
if val != None: avgs[var].append(val)
vals = []
for var in variables: #calculate the average when available
if len(avgs[var]) > 0:
vals.append(sum(avgs[var])/len(avgs[var]))
else:
vals.append(None)
wdata.append(temps)
wdata.append(date)
Can you help me to find what I am doing wrong? Or do you know any easier way to plot the monthly average temperature?
Thank you.