WIP
This commit is contained in:
parent
d5c58d6167
commit
1c64fca4a2
6 changed files with 163 additions and 30 deletions
|
@ -1,39 +1,27 @@
|
||||||
from flask_wtf import Form
|
from flask_wtf import Form
|
||||||
from wtforms import IntegerField, SelectField
|
from wtforms import IntegerField, SelectField
|
||||||
from wtforms.validators import NumberRange, Required
|
from wtforms.validators import NumberRange, Required
|
||||||
from wtforms.ext.sqlalchemy.fields import QuerySelectField
|
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
|
||||||
from .models import Dataset, Temperature, DB
|
from .models import Temperature, DB
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
|
|
||||||
class AKIYearField(IntegerField):
|
class AKIYearField(IntegerField):
|
||||||
def pre_validate(self, form):
|
def pre_validate(self, form):
|
||||||
if form.model.data is not None:
|
pass
|
||||||
ymin, ymax = Temperature.query \
|
# if form.dataset.data is not None:
|
||||||
.with_entities(func.min(Temperature.year),
|
# ymin, ymax = Temperature.query \
|
||||||
func.max(Temperature.year)) \
|
# .with_entities(func.min(Temperature.year),
|
||||||
.filter(Temperature.dataset_id == form.model.data.id).all()[0]
|
# func.max(Temperature.year)) \
|
||||||
self.validators = [NumberRange(min=ymin, max=ymax), Required()]
|
# .filter(Temperature.dataset_id == form.dataset.data.id).all()[0]
|
||||||
|
# self.validators = [NumberRange(min=ymin, max=ymax), Required()]
|
||||||
|
|
||||||
def datasets():
|
|
||||||
return Dataset.query.order_by('datatype', 'model', 'scenario')
|
|
||||||
|
|
||||||
|
|
||||||
def dataset_names(ds):
|
|
||||||
return "{0.type} ({0.resolution}) - {0.modelname} {0.scenario}".format(ds)
|
|
||||||
|
|
||||||
|
|
||||||
class AKIForm(Form):
|
class AKIForm(Form):
|
||||||
community = SelectField(coerce=int,
|
community = SelectField(coerce=int,
|
||||||
validators=[Required(message='Please select a community')])
|
validators=[Required(message='Please select a community')])
|
||||||
|
dataset = SelectField(validators=[Required(message='Please select a dataset')])
|
||||||
minyear = AKIYearField('minyear')
|
minyear = AKIYearField('minyear')
|
||||||
maxyear = AKIYearField('maxyear')
|
maxyear = AKIYearField('maxyear')
|
||||||
|
|
||||||
model = QuerySelectField(query_factory=datasets,
|
|
||||||
get_label=dataset_names,
|
|
||||||
allow_blank=True,
|
|
||||||
blank_text='---Select a dataset---',
|
|
||||||
validators=[Required(message='Please select a dataset')])
|
|
||||||
|
|
|
@ -62,3 +62,35 @@ class DB:
|
||||||
"""
|
"""
|
||||||
result = db.engine.execute(text(cmd), id=id).fetchall()
|
result = db.engine.execute(text(cmd), id=id).fetchall()
|
||||||
return result or abort(500)
|
return result or abort(500)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def getDatasets(cls):
|
||||||
|
cmd = """
|
||||||
|
SELECT DISTINCT ON (
|
||||||
|
doc->'model',
|
||||||
|
doc->'datatype',
|
||||||
|
doc->'resolution',
|
||||||
|
doc->'modelname',
|
||||||
|
doc->'scenario'
|
||||||
|
)
|
||||||
|
doc->'model' AS model,
|
||||||
|
doc->'datatype' AS datatype,
|
||||||
|
doc->'resolution' AS resolution,
|
||||||
|
doc->'modelname' AS modelname,
|
||||||
|
doc->'scenario' AS scenario
|
||||||
|
FROM new_communities c,
|
||||||
|
jsonb_array_elements(c.data)
|
||||||
|
WITH ORDINALITY t1(doc, rn)
|
||||||
|
ORDER BY datatype ASC, modelname ASC, scenario ASC;
|
||||||
|
"""
|
||||||
|
result = db.engine.execute(text(cmd), id=id).fetchall()
|
||||||
|
return result or abort(500)
|
||||||
|
|
||||||
|
# WITH x AS (
|
||||||
|
# SELECT name, jsonb_array_elements(data) AS data
|
||||||
|
# FROM new_communities
|
||||||
|
# WHERE name='Anchorage')
|
||||||
|
# SELECT d.key::INTEGER AS year, d.value AS temperatures
|
||||||
|
# FROM x, jsonb_each(data) d
|
||||||
|
# WHERE data->>'model'='CRU'
|
||||||
|
# AND d.key NOT IN ('model', 'datatype', 'scenario', 'modelname', 'resolution');
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group col-md-4">
|
<div class="form-group col-md-4">
|
||||||
<label for="modelinput">Dataset</label>
|
<label for="modelinput">Dataset</label>
|
||||||
{{ render_field(form.model, class='form-control', id='modelinput') }}
|
{{ render_field(form.dataset, class='form-control', id='modelinput') }}
|
||||||
<small>Historical (1901-2009) or Projection (2001-2099)<br>
|
<small>Historical (1901-2009) or Projection (2001-2099)<br>
|
||||||
<a href="{{ url_for('main.datatypes') }}" target="_blank">
|
<a href="{{ url_for('main.datatypes') }}" target="_blank">
|
||||||
Learn more about the models and scenarios
|
Learn more about the models and scenarios
|
||||||
|
|
|
@ -70,5 +70,13 @@ def des_air_indices(indices):
|
||||||
def c_to_f(temp):
|
def c_to_f(temp):
|
||||||
return (temp * 9. / 5.) + 32.
|
return (temp * 9. / 5.) + 32.
|
||||||
|
|
||||||
|
|
||||||
def communitiesSelect():
|
def communitiesSelect():
|
||||||
return [(c.id, c.name) for c in DB.getCommunities()]
|
return [(c.id, c.name) for c in DB.getCommunities()]
|
||||||
|
|
||||||
|
|
||||||
|
def datasetsSelect():
|
||||||
|
return [("{0.model},{0.scenario}".format(d),
|
||||||
|
"{x} ({d.resolution}) - {d.modelname} {d.scenario}".format(d=d,
|
||||||
|
x=d.datatype.title()))
|
||||||
|
for d in DB.getDatasets()]
|
||||||
|
|
|
@ -2,17 +2,18 @@ from numpy import arange, hstack
|
||||||
|
|
||||||
from flask import session, render_template, request, redirect, url_for
|
from flask import session, render_template, request, redirect, url_for
|
||||||
|
|
||||||
|
from flask import current_app
|
||||||
|
|
||||||
from . import main
|
from . import main
|
||||||
from .forms import AKIForm
|
from .forms import AKIForm
|
||||||
from .utils import getTemps, avg_air_temp, ann_air_indices, \
|
from .utils import getTemps, avg_air_temp, ann_air_indices, \
|
||||||
avg_air_indices, des_air_indices, communitiesSelect
|
avg_air_indices, des_air_indices, communitiesSelect, datasetsSelect
|
||||||
from .models import Dataset, DB
|
from .models import Dataset, DB
|
||||||
|
|
||||||
|
|
||||||
@main.route('/', methods=['GET'])
|
@main.route('/', methods=['GET'])
|
||||||
def index():
|
def index():
|
||||||
form = AKIForm()
|
form = generateForm()
|
||||||
form.community.choices = communitiesSelect()
|
|
||||||
session['community_data'] = None
|
session['community_data'] = None
|
||||||
session['avg_temp'] = None
|
session['avg_temp'] = None
|
||||||
session['avg_indices'] = None
|
session['avg_indices'] = None
|
||||||
|
@ -48,8 +49,7 @@ def index():
|
||||||
|
|
||||||
@main.route('/', methods=['POST'])
|
@main.route('/', methods=['POST'])
|
||||||
def index_submit():
|
def index_submit():
|
||||||
form = AKIForm()
|
form = generateForm()
|
||||||
form.community.choices = communitiesSelect()
|
|
||||||
if form.validate():
|
if form.validate():
|
||||||
session['community'] = request.form['community']
|
session['community'] = request.form['community']
|
||||||
session['minyear'] = request.form['minyear']
|
session['minyear'] = request.form['minyear']
|
||||||
|
@ -57,12 +57,15 @@ def index_submit():
|
||||||
if session['minyear'] > session['maxyear']:
|
if session['minyear'] > session['maxyear']:
|
||||||
session['maxyear'] = session['minyear']
|
session['maxyear'] = session['minyear']
|
||||||
|
|
||||||
session['datasets'] = request.form['model']
|
session['datasets'] = request.form['dataset']
|
||||||
|
current_app.logger.info(session)
|
||||||
return redirect(url_for('main.index'))
|
return redirect(url_for('main.index'))
|
||||||
else:
|
else:
|
||||||
|
# TODO: Fix post-POST handling
|
||||||
return render_template('main/index.html', form=form)
|
return render_template('main/index.html', form=form)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: reimport this template
|
||||||
@main.route('/datatypes')
|
@main.route('/datatypes')
|
||||||
def datatypes():
|
def datatypes():
|
||||||
return render_template('main/datatypes.html')
|
return render_template('main/datatypes.html')
|
||||||
|
@ -121,3 +124,10 @@ def delete():
|
||||||
record = request.args.get('record', '')
|
record = request.args.get('record', '')
|
||||||
session['save'].pop(record)
|
session['save'].pop(record)
|
||||||
return redirect(url_for('main.index'))
|
return redirect(url_for('main.index'))
|
||||||
|
|
||||||
|
|
||||||
|
def generateForm():
|
||||||
|
form = AKIForm()
|
||||||
|
form.community.choices = communitiesSelect()
|
||||||
|
form.dataset.choices = datasetsSelect()
|
||||||
|
return form
|
||||||
|
|
95
app/misc/transform.sql
Normal file
95
app/misc/transform.sql
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
-- Transforms AKIndices v1 schema to v2 schema
|
||||||
|
SELECT t.community_id,
|
||||||
|
d.datatype,
|
||||||
|
d.model,
|
||||||
|
d.modelname,
|
||||||
|
d.scenario,
|
||||||
|
d.resolution,
|
||||||
|
t.year::text,
|
||||||
|
json_build_array(
|
||||||
|
t.january::decimal(3,1),
|
||||||
|
t.february::decimal(3,1),
|
||||||
|
t.march::decimal(3,1),
|
||||||
|
t.april::decimal(3,1),
|
||||||
|
t.may::decimal(3,1),
|
||||||
|
t.june::decimal(3,1),
|
||||||
|
t.july::decimal(3,1),
|
||||||
|
t.august::decimal(3,1),
|
||||||
|
t.september::decimal(3,1),
|
||||||
|
t.october::decimal(3,1),
|
||||||
|
t.november::decimal(3,1),
|
||||||
|
t.december::decimal(3,1))::jsonb AS temps
|
||||||
|
INTO TEMP temp01
|
||||||
|
FROM temperatures t
|
||||||
|
INNER JOIN datasets d ON d.id=t.dataset_id;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SELECT community_id,
|
||||||
|
datatype,
|
||||||
|
model,
|
||||||
|
modelname,
|
||||||
|
scenario,
|
||||||
|
resolution,
|
||||||
|
json_object_agg(year, temps)::jsonb AS data
|
||||||
|
INTO TEMP temp02
|
||||||
|
FROM temp01
|
||||||
|
GROUP BY community_id, datatype, model, modelname, scenario, resolution;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CREATE TEMP SEQUENCE a;
|
||||||
|
SELECT nextval('a') AS id,
|
||||||
|
community_id,
|
||||||
|
json_build_object(
|
||||||
|
'datatype', datatype,
|
||||||
|
'model', model,
|
||||||
|
'modelname', modelname,
|
||||||
|
'scenario', scenario,
|
||||||
|
'resolution', resolution)::jsonb as dataset,
|
||||||
|
data
|
||||||
|
INTO TEMP temp03
|
||||||
|
FROM temp02;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
WITH all_json_key_value AS (
|
||||||
|
SELECT id, community_id, t1.key, t1.value
|
||||||
|
FROM temp03, jsonb_each(dataset) AS t1
|
||||||
|
UNION
|
||||||
|
SELECT id, community_id, t1.key, t1.value
|
||||||
|
FROM temp03, jsonb_each(data) AS t1
|
||||||
|
)
|
||||||
|
SELECT community_id, json_object_agg(key, value) AS data
|
||||||
|
INTO TEMP temp04
|
||||||
|
GROUP BY id, community_id;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SELECT community_id, json_agg(data)::jsonb AS data
|
||||||
|
INTO TEMP temp05
|
||||||
|
FROM temp04
|
||||||
|
GROUP BY community_id;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SELECT c.name, c.latitude, c.longitude, c.northing, c.easting, t.data
|
||||||
|
INTO new_communities
|
||||||
|
FROM temp05 t
|
||||||
|
INNER JOIN communities c ON c.id=t.community_id;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
select distinct on (doc->'model', doc->'datatype', doc->'scenario') doc->'model', doc->'datatype', doc->'scenario' from new_communities c, jsonb_array_elements(c.data) with ordinality t1(doc, rn);
|
Loading…
Add table
Reference in a new issue