Using the Xgeo chartserver from Python

Full reference can be found on: http://nve-wiki.nve.no/index.php/Web_Chart_Service


In [11]:
# Required imports
import requests
from urllib.parse import urljoin, urlparse
import json
import re
import time
import pandas as pd

In [12]:
%matplotlib inline

Retrieving data as json

GetChart

Parameter

Påkrevd/Valgfri

Standardverdi

Kommentar

ver= P 1.0 Versjon.
req=getchart P getchart Tjeneste.
lang= V no Språk (no, en).
efmt= V image Angir formatet på eventuelle feilmeldinger.
chs=x V 600x400 Bildestørrelse.
dpi= V 96 Dots per inch.
chf= V image/png Bildeformat.
chtt= V tom streng Tittel.<br/> rt=<tidsoppløsning> V 0 Tidsoppløsning.<br/> mth=<metode> V inst Metode.<br/> time=<fra/til tid> V -21;+0 Periodeangivelse.<br/> timeo=<tidsforskyvning> V 0 Tidsforskyvning på starttidspunktet.<br/> cht=<plottetype> V lc Plottetype.<br/> cdt=<uri> V DefaultContentData.xml Innholdsbeskrivelse.<br/> sdt=<uri> V DefaultStyleDescription.xml Presentasjonsbeskrivelse.<br/> chd=<tidsseriedata> V (hvis cdt) ellers P ikke relevant Tidsseriedata.<br/> ymax=<tall> V automatisk i grafkontroll Maks verdi for Y-akser.<br/> ymin=<tall> V automatisk i grafkontroll Minimum verdi for Y-akser.<br/> ydec=<tall> V automatisk i grafkontroll Antall desimaler i Y-akse verdier.</tall></tall></tall></tidsseriedata></uri></uri></plottetype></tidsforskyvning></metode></tidsoppløsning>


In [13]:
url = "http://h-web01.nve.no/chartserver/ShowData.aspx?req=getchart&ver=1.0&vfmt=json&time=20130504T0000;20130506T0000&chs=10x10&lang=no&chlf=none&chsl=0;+0&chd=ds=htsre,da=29,id=25100.0,rt=1,cht=col,mth=sum,timeo=6:0|ds=htsry,id=metx[25100;0].6001,mth=sum,rt=1,cht=col&nocache=0.20784913911484182"
print(urlparse(url))


ParseResult(scheme='http', netloc='h-web01.nve.no', path='/chartserver/ShowData.aspx', params='', query='req=getchart&ver=1.0&vfmt=json&time=20130504T0000;20130506T0000&chs=10x10&lang=no&chlf=none&chsl=0;+0&chd=ds=htsre,da=29,id=25100.0,rt=1,cht=col,mth=sum,timeo=6:0|ds=htsry,id=metx[25100;0].6001,mth=sum,rt=1,cht=col&nocache=0.20784913911484182', fragment='')

In [14]:
def chartserver_query(base, mth, ver, fmt, tm, lang, data_req):
    return '{0}?{1}&{2}&{3}&{4}&{5}&{6}'.format(base, mth, ver, fmt, tm, lang, data_req)
    
url_base = 'http://h-web01.nve.no/chartserver/ShowData.aspx'
cs_mth = 'req=getchart'
cs_ver = 'ver=1.0'
cs_fmt = 'vfmt=json'
cs_lang = 'lang=no'
#&chd=ds=htsre,da=29,id=25100.0,rt=1,cht=col,mth=sum,timeo=6:0|
#        ds=htsry,id=metx[25100;0].6001,mth=sum,rt=1,cht=col
#&nocache=0.20784913911484182"

In [15]:
rt = "1:00" # hourly time resolution
Parameter Code
Precipitation 0
Wind direction 14
Wind speed (10m) 16
Air temperature (2m) 17
Snow depth 2002
Surface temperature 2040

In [16]:
def get_hourly(station_id, parameter_id, mth='inst'):
    """
    Allowed methods (mth): inst, mean, min, max, sum
    """
    return "ds=htsre,id={0}.{1},rt=1:00,mth={2}".format(station_id, parameter_id, mth) #,da=29, timeo=6:0

#station_id = 18500 # Bjørnholt
#station_id = 18700 # Blindern
station_id = 54710 # Filefjell
#station_id = 25830 # Finsevatn
# Hourly precipitation
ds_precip = get_hourly(station_id, 0, 'sum')
print(ds_precip)

# Hourly temperature
ds_temp = get_hourly(station_id, 17)

# Hourly wind speed
ds_wind = get_hourly(station_id, 16, 'max')

# Hourly snow depth
ds_snow = get_hourly(station_id, 2002)


ds=htsre,id=54710.0,rt=1:00,mth=sum

In [17]:
def create_data_request(req_list):
    count = 0
    max = len(req_list)
    req = "chd="
    for r in req_list:
        count += 1
        req += r
        if count<max:
            req +='|'
    return req

data_req = create_data_request([ds_precip, ds_temp, ds_wind, ds_snow])
print(data_req)


chd=ds=htsre,id=54710.0,rt=1:00,mth=sum|ds=htsre,id=54710.17,rt=1:00,mth=inst|ds=htsre,id=54710.16,rt=1:00,mth=max|ds=htsre,id=54710.2002,rt=1:00,mth=inst

In [18]:
cs_time = 'time=20160127T0000;20160209T0000'

In [19]:
url = chartserver_query(url_base, cs_mth, cs_ver, cs_fmt, cs_time, cs_lang, data_req)
print(url)


http://h-web01.nve.no/chartserver/ShowData.aspx?req=getchart&ver=1.0&vfmt=json&time=20160127T0000;20160209T0000&lang=no&chd=ds=htsre,id=54710.0,rt=1:00,mth=sum|ds=htsre,id=54710.17,rt=1:00,mth=inst|ds=htsre,id=54710.16,rt=1:00,mth=max|ds=htsre,id=54710.2002,rt=1:00,mth=inst

In [20]:
resp = requests.get(url)
data = json.loads(resp.text)

In [ ]:


In [21]:
#print(json.dumps(data, indent=2)) # formated printing of a json object

In [ ]:


In [ ]:

{ "LegendText": "FILEFJELL - KYRKJEST\u00d8LANE (54710), Sn\u00f8dybde (cm)", "Statistics": [], "SeriesPoints": [ { "Value": 78, "Key": "/Date(1454544000000)/", "CorrectionMark": 0 }, }


In [ ]:


In [ ]:


In [22]:
def convert_timestr(s, as_string=True):
    """
    :param s: time string returned by chartserver query, e.g. /Date(1457485200000)/
    :return:
    """
    # regular expression to extract the numeric values in the json date string
    regex = re.compile("\d+")
    # extract numerical value, make it a float, and divide by 1000 to get seconds since 1.1.1970
    ds = time.gmtime(float(regex.search(s).group())*0.001)
    if as_string:
        ds = time.strftime("%Y-%m-%dT%H:%M:%S", ds)

    return ds

#df['Key'] = [convert_timestr(s) for s in df['Key']]

#print(df)
# s = re.findall('\(.*?\)', df['Key'][0])
# s = time.gmtime(df['Key'][0])
#print('Done')

In [23]:
# parse data as pandas time-series

ts_list = []
for i in range(len(data)):
    val = [v['Value'] for v in data[i]['SeriesPoints']]
    d = [convert_timestr(v['Key']) for v in data[i]['SeriesPoints']]
    ts_list.append(pd.Series(val, index=d, name=data[i]['LegendText']))

df = pd.concat(ts_list, axis=1)

# print(df)

# make the date the new index
# df.index = df['Key']

# remove the duplicate Key column
# del df['Key']

In [24]:
df.plot(subplots='True', figsize=(14, 9))


Out[24]:
array([<matplotlib.axes._subplots.AxesSubplot object at 0x0000027607A47BE0>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x0000027607FE0D68>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x0000027608041780>,
       <matplotlib.axes._subplots.AxesSubplot object at 0x00000276080A7A90>], dtype=object)

In [25]:
import sqlite3

In [26]:
db_name = 'filefjell.db'
# Establish connection and cursor
conn = sqlite3.connect(db_name)
#ur = conn.cursor()

df.to_sql(name='FILEFJELL', con=conn)


C:\Anaconda3\lib\site-packages\pandas\core\generic.py:1201: UserWarning: The spaces in these column names will not be changed. In pandas versions < 0.14, spaces were converted to underscores.
  chunksize=chunksize, dtype=dtype)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-26-407028b2ff78> in <module>()
      4 #ur = conn.cursor()
      5 
----> 6 df.to_sql(name='FILEFJELL', con=conn)

C:\Anaconda3\lib\site-packages\pandas\core\generic.py in to_sql(self, name, con, flavor, schema, if_exists, index, index_label, chunksize, dtype)
   1199         sql.to_sql(self, name, con, flavor=flavor, schema=schema,
   1200                    if_exists=if_exists, index=index, index_label=index_label,
-> 1201                    chunksize=chunksize, dtype=dtype)
   1202 
   1203     def to_pickle(self, path):

C:\Anaconda3\lib\site-packages\pandas\io\sql.py in to_sql(frame, name, con, flavor, schema, if_exists, index, index_label, chunksize, dtype)
    468     pandas_sql.to_sql(frame, name, if_exists=if_exists, index=index,
    469                       index_label=index_label, schema=schema,
--> 470                       chunksize=chunksize, dtype=dtype)
    471 
    472 

C:\Anaconda3\lib\site-packages\pandas\io\sql.py in to_sql(self, frame, name, if_exists, index, index_label, schema, chunksize, dtype)
   1500                             if_exists=if_exists, index_label=index_label,
   1501                             dtype=dtype)
-> 1502         table.create()
   1503         table.insert(chunksize)
   1504 

C:\Anaconda3\lib\site-packages\pandas\io\sql.py in create(self)
    584         if self.exists():
    585             if self.if_exists == 'fail':
--> 586                 raise ValueError("Table '%s' already exists." % self.name)
    587             elif self.if_exists == 'replace':
    588                 self.pd_sql.drop_table(self.name, self.schema)

ValueError: Table 'FILEFJELL' already exists.

In [27]:
conn.close()

In [ ]: