app-wx.py

'''\
Weather.

Developer@Sonnack.com
July 2017
'''
####################################################################################################
from __future__ import print_function
from sys import argvstdoutstderrpath as syspath
from os import environpathlistdir
from datetime import datetimedelta
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocatorFormatStrFormatter
from matplotlib.dates import DayLocatorDateFormatter
from logger import loggerinfodebugtrace
from db_weather import BasePathdbLocalClimateDataTabledbWeatherStationTableQueries
####################################################################################################
Log = logger('weather')


##================================================================================================##
def classify_data (*args):
    Log.info('Classify-Table-Data')
    fn = args[0if 0 < len(argselse 'data-types.out'

    tbl = dbLocalClimateDataTable()
    sql = 'SELECT * FROM "%s" ORDER BY date' % tbl.name
    rs = tbl.db_query(sql)
    if not rs: Log.warn('No Data!'); return []

    accum = [[0,0,0,0,0for n in tbl.col_headers# 0:unknown, 1:"", 2:strs, 3:ints, 4:reals
    for r in rs:
        for cx,c in enumerate(r):
            if isinstance(c,float):
                accum[cx][4] += 1
                continue
            if isinstance(c,int):
                accum[cx][3] += 1
                continue
            if isinstance(c,unicode):
                if len(c) == 0:
                    accum[cx][1] += 1
                    continue
                # Int?...
                try:
                    n = int(c)
                    accum[cx][3] += 1
                    continue
                except: pass
                # Float?...
                try:
                    n = float(c)
                    accum[cx][4] += 1
                    continue
                except: pass
                # Text!...
                accum[cx][2] += 1
                continue
            # Unknown!...
            accum[cx][0] += 1

    h1 = 'Column Name                     DataType    unkn   empt   text    int  float    total\n'
    h2 = '==============================  ========  ====== ====== ====== ====== ======  =======\n'
    fp = open(path.join(BasePath,fn), 'w')
    fp.write(h1)
    fp.write(h2)
    for rcd in zip(tbl.col_headerstbl.col_types, *zip(*accum)):
        t = rcd+(sum(rcd[-5:]), )
        fp.write('%-30s  %-8s  %6d %6d %6d %6d %6d  %7d\n' % t)
    fp.write(h2)
    fp.close()
    Log.info('wrote: %s' % fn)
    return rs

##================================================================================================##
## STATIONS TABLE
##================================================================================================##
def create_stations_table ():
    Log.info('Make-Stations-Table')
    tbl = dbWeatherStationTable()
    tbl.create_table()
    return tbl
##================================================================================================##
def destroy_stations_table ():
    Log.info('Drop-Stations-Table')
    tbl = dbWeatherStationTable()
    tbl.destroy_table()
    return tbl
##================================================================================================##
def list_stations_table (*args):
    Log.info('List-Stations-Table: %s' % str(args))
    tbl = dbWeatherStationTable()
    return tbl.list_to_file()

##================================================================================================##
## LOCAL CLIMATE DATA (LCD) TABLE
##================================================================================================##
def create_lcd_table ():
    Log.info('Make-LCD-Table')
    tbl = dbLocalClimateDataTable()
    tbl.create_table()
    return tbl
##================================================================================================##
def destroy_lcd_table ():
    Log.info('Drop-LCD-Table')
    tbl = dbLocalClimateDataTable()
    tbl.destroy_table()
    return tbl
##================================================================================================##
def list_lcd_table (*args):
    Log.info('List-LCD-Table: %s' % str(args))
    tbl = dbLocalClimateDataTable()
    return tbl.list_to_file()
##================================================================================================##
def add_records_lcd_table (*args):
    fname = args[0if 0 < len(argselse 'lcd_1990-1999.csv'
    Log.info('Add2-LCD-Table')
    tbl = dbLocalClimateDataTable()
    tbl.load_records(fname)
    return tbl
##================================================================================================##
def do_chart_month_temps (*args):
    Log.info('Chart/Month/Temps: %s' % str(args))
    mo = args[0if 0 < len(argselse '7'
    yr = args[1if 1 < len(argselse '2017'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_month_temps(int(mo), int(yr))
##================================================================================================##
def do_chart_month_precip (*args):
    Log.info('Chart/Month/Precip: %s' % str(args))
    mo = args[0if 0 < len(argselse '7'
    yr = args[1if 1 < len(argselse '2017'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_month_precip(int(mo), int(yr))
##================================================================================================##
def do_chart_year_temps (*args):
    Log.info('Chart/Year/Temps: %s' % str(args))
    yr = args[0if 0 < len(argselse '2017'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_year_temps(int(yr))
##================================================================================================##
def do_chart_year_precip (*args):
    Log.info('Chart/Year/Precip: %s' % str(args))
    yr = args[0if 0 < len(argselse '2017'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_year_precip(int(yr))
##================================================================================================##
def do_chart_decade_temps (*args):
    Log.info('Chart/Decade/Temps: %s' % str(args))
    yr = args[0if 0 < len(argselse '2006'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_decade_temps(int(yr))
##================================================================================================##
def do_chart_decade_precip (*args):
    Log.info('Chart/Decade/Precip: %s' % str(args))
    yr = args[0if 0 < len(argselse '2006'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_decade_precip(int(yr))
##================================================================================================##
def do_chart_months_temps_hi (*args):
    Log.info('Chart/Months/Temps/Hi: %s' % str(args))
    mon = args[0if 0 < len(argselse '9'
    yr0 = args[1if 1 < len(argselse '2010'
    yr1 = args[2if 2 < len(argselse '2017'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_months_temps_hi(int(mon), int(yr0), int(yr1))
##================================================================================================##
def do_chart_months_temps_lo (*args):
    Log.info('Chart/Months/Temps/Lo: %s' % str(args))
    mon = args[0if 0 < len(argselse '9'
    yr0 = args[1if 1 < len(argselse '2010'
    yr1 = args[2if 2 < len(argselse '2017'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_months_temps_lo(int(mon), int(yr0), int(yr1))
##================================================================================================##
def do_chart_months_temps_hi_lo (*args):
    Log.info('Chart/Months/Temps: %s' % str(args))
    mon = args[0if 0 < len(argselse '9'
    yr0 = args[1if 1 < len(argselse '2010'
    yr1 = args[2if 2 < len(argselse '2017'
    tbl = dbLocalClimateDataTable()
    return tbl.chart_months_temps_hi_lo(int(mon), int(yr0), int(yr1))
##================================================================================================##
##================================================================================================##
def do_chart_temp_min_max (*args):
    Log.info('Chart/Temp/Min-Max: %s' % str(args))
    tbl = dbLocalClimateDataTable()
    return tbl.chart_temp_min_max(*args)
##================================================================================================##
def do_chart_pressure (*args):
    Log.info('Chart/Pressure: %s' % str(args))
    tbl = dbLocalClimateDataTable()
    return tbl.chart_pressure(*args)
##================================================================================================##
def do_chart_rel_hum (*args):
    Log.info('Chart/Rel-Hum: %s' % str(args))
    tbl = dbLocalClimateDataTable()
    return tbl.chart_rel_hum(*args)

##================================================================================================##
SQL_CHRT = '''\
SELECT
    cast(substr(date,1,4) as INTEGER) AS "dtY",
    cast(substr(date,6,2) as INTEGER) AS "dtM",
    cast(substr(date,9,2) as INTEGER) AS "dtD",
    day_precip, day_snowfall
FROM "%s"
WHERE (report_type=?) AND (substr(date,1,4)=?)
ORDER BY date
'''
def do_chart (*args):
    Log.info('chart/parameters: %s' % str(args))
    yr = args[0if 0 < len(argselse '2017'
    fn = args[1if 1 < len(argselse 'wx-chart.png'
    ps = ['SOD'yr]
    year = int(yr)
    #
    tbl = dbLocalClimateDataTable()
    sql = SQL_CHRT % tbl.name
    rs = tbl.db_query(sqlps)
    if not rs: Log.warn('No Data!'); return rs
    rain = [(date(r[0],r[1],r[2]),r[3]) for r in rs if isinstance(r[3],float)]
    snow = [(date(r[0],r[1],r[2]),r[4]) for r in rs if isinstance(r[4],float)]
    rain_dtsrain_vals = zip(*rain)
    snow_dtssnow_vals = zip(*snow)
    #
    xmin = date(year,1,1)
    xmax = date(year+1,1,1) - timedelta(1)
    yminymax = 0.0, +2.5
    xt0 = [date(year,m+1,1for m in range(12)]+[date(year,12,31)]
    xt1 = []
    [xt1.extend(xfor x in [[date(year,m+1,dfor d in [7,14,21,28]] for m in range(12)]]
    #
    figax = plt.subplots()
    fig.suptitle('Rain & Snow %04d' % yearfontsize=13)
    #xlab: ax.set_xlabel('Dates', fontsize=11)
    ax.set_ylabel('Precip (inches)'fontsize=11)
    ax.xaxis_date()
    ax.minorticks_on()
    ax.set_xlim(xminxmax)
    ax.set_ylim(yminymax)
    #
    ax.set_xticks(xt0)
    ax.set_xticks(xt1minor=True)
    ax.xaxis.set_major_formatter(DateFormatter('%b %d'))
    ax.yaxis.set_major_locator(MultipleLocator(1.0))
    ax.yaxis.set_minor_locator(MultipleLocator(0.25))
    for tick in ax.xaxis.get_major_ticks():
        tick.label1.set_rotation('vertical')
        tick.label1.set_size(11)
    ax.tick_params(which='major'axis='both'direction='out')
    ax.tick_params(which='minor'axis='both'direction='out')
    ax.grid(which='minor'axis='x'color='#afafaf'lw=0.8,ls='-'alpha=1.0zorder=2)
    ax.grid(which='minor'axis='y'color='#cfcfcf'lw=0.7,ls='-'alpha=1.0zorder=2)
    ax.grid(which='major'axis='x'color='#7f7f7f'lw=1.3,ls='-'alpha=1.0zorder=4)
    ax.grid(which='major'axis='y'color='#7f7f7f'lw=0.9,ls='-'alpha=1.0zorder=4)
    #
    ax.fill_between(rain_dts,rain_vals,0color='#007fbf'alpha=0.75zorder=9)
    ax.fill_between(snow_dts,snow_vals,0color='#3f3f3f'alpha=0.75zorder=8)
    #
    fig.set_figwidth(9.8)
    fig.set_figheight(4.8)
    fig.subplots_adjust(left=0.10bottom=0.18right=0.97top=0.92)
    fig.savefig(path.join(tbl.imgsPath,fn))
    #plt.show()
    #
    return rs
##================================================================================================##
SQL_QRY = '''\
SELECT rowid, date,time, report_type, day_heat_deg_days
FROM "%s"
WHERE (0 < length(day_heat_deg_days)) AND (substr(day_heat_deg_days,-1) = 's')
ORDER BY date,time
'''
def do_query (*args):
    Log.info('query/parameters: %s' % str(args))
    fname = args[0if 0 < len(argselse 'wx-query.out'
    fn = path.join(BasePath,fname)
    ps = []
    #
    tbl = dbLocalClimateDataTable()
    sql = SQL_QRY % tbl.name
    rs = tbl.db_query(sqlps)
    if not rs: Log.warn('No Data!'); return []
    #
    Log.info()
    for r in rs:
        Log.info(r)
    Log.info()
    Log.info(sql)
    Log.info(ps)
    Log.info()
    #
    return rs
##================================================================================================##
SQL_UPDT = '''\
UPDATE "%s"
SET day_heat_deg_days = substr(day_heat_deg_days, 1, length(day_heat_deg_days)-1)
WHERE (substr(day_heat_deg_days,-1) = 's')
'''
def do_test (*args):
    Log.info('test/parameters: %s' % str(args))
    fname = args[0if 0 < len(argselse 'wx-test.out'
    fn = path.join(BasePath,fname)
    ps = [123456]
    sql = 'select * from %s where rowid=?'
    #
    tbl = dbLocalClimateDataTable()
    sql = sql % tbl.name
    rs = tbl.db_query(sqlps)
    if not rs: Log.warn('No Data!'); return []
    for r in rs: Log.trace(r)
    #
    return rs
##================================================================================================##
def do_main (*args):
    Log.info('main/parameters: %s' % str(args))
    fname = args[0if 0 < len(argselse ''
    #
    tbl = dbLocalClimateDataTable()
    Log.info('Database-Name: %s' % tbl.dbname)
    Log.info('Table-Name: %s' % tbl.name)
    Log.info()
    Log.info('Column-Names: %s' % str(tbl.col_names))
    Log.info()
    Log.info('Column-Types: %s' % str(tbl.col_types))
    Log.info()
    Log.info('Header-Names: %s' % str(tbl.col_headers))
    Log.info()
    #
    return tbl
####################################################################################################
def dispatch (cmd, *args):
    Log.info('command: %s' % cmd)
    Log.info('arguments: %d' % len(args))

    if cmd == 'c.10.temp': return do_chart_decade_temps(*args)
    if cmd == 'c.10.precip': return do_chart_decade_precip(*args)

    if cmd == 'c.yr.temp': return do_chart_year_temps(*args)
    if cmd == 'c.yr.precip': return do_chart_year_precip(*args)

    if cmd == 'c.mn.temp': return do_chart_month_temps(*args)
    if cmd == 'c.mn.precip': return do_chart_month_precip(*args)

    if cmd == 'c.ms.temp': return do_chart_months_temps_hi_lo(*args)
    if cmd == 'c.ms.temp.hi': return do_chart_months_temps_hi(*args)
    if cmd == 'c.ms.temp.lo': return do_chart_months_temps_lo(*args)

    if cmd == 'c.rel_hum': return do_chart_rel_hum(*args)
    if cmd == 'c.pressure': return do_chart_pressure(*args)
    if cmd == 'c.temps': return do_chart_temp_min_max(*args)

    if cmd == 'chart': return do_chart(*args)
    if cmd == 'query': return do_query(*args)
    if cmd == 'test': return do_test(*args)
    if cmd == 'main': return do_main(*args)

    if cmd == 'classify': return classify_data()

    if cmd == 'lcd.add2': return add_records_lcd_table(*args)
    if cmd == 'lcd.list': return list_lcd_table(*args)
    if cmd == 'lcd.make': return create_lcd_table(*args)
    if cmd == 'lcd.drop': return destroy_lcd_table(*args)

    if cmd == 'sta.list': return list_stations_table(*args)
    if cmd == 'sta.make': return create_stations_table(*args)
    if cmd == 'sta.drop': return destroy_stations_table(*args)

    return [Nonecmdargs]
####################################################################################################
if __name__ == '__main__':
    print('autorun: %s' % argv[0])
    Log.start(path.join(BasePath,'app-wx.log'))
    Log.level(trace())
    cmd = argv[1if 1 < len(argvelse ''
    etc = argv[2:if 2 < len(argvelse []
    try:
        obj = dispatch(cmd, *etc)
        print('exit')
        Log.debug('exit')
    except Exception as e:
        print('ERROR! "%s"' % efile=stderr)
        Log.error(e)
        raise
    finally:
        Log.end()
####################################################################################################
'''eof'''