diff --git a/app/main/forms.py b/app/main/forms.py index c7fbc96..19c791d 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1,39 +1,27 @@ from flask_wtf import Form from wtforms import IntegerField, SelectField from wtforms.validators import NumberRange, Required -from wtforms.ext.sqlalchemy.fields import QuerySelectField from sqlalchemy import func -from .models import Dataset, Temperature, DB +from .models import Temperature, DB + +from flask import current_app class AKIYearField(IntegerField): def pre_validate(self, form): - if form.model.data is not None: - ymin, ymax = Temperature.query \ - .with_entities(func.min(Temperature.year), - func.max(Temperature.year)) \ - .filter(Temperature.dataset_id == form.model.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) + pass + # if form.dataset.data is not None: + # ymin, ymax = Temperature.query \ + # .with_entities(func.min(Temperature.year), + # func.max(Temperature.year)) \ + # .filter(Temperature.dataset_id == form.dataset.data.id).all()[0] + # self.validators = [NumberRange(min=ymin, max=ymax), Required()] class AKIForm(Form): community = SelectField(coerce=int, validators=[Required(message='Please select a community')]) - + dataset = SelectField(validators=[Required(message='Please select a dataset')]) minyear = AKIYearField('minyear') 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')]) diff --git a/app/main/models.py b/app/main/models.py index 64a9d3f..29115e6 100644 --- a/app/main/models.py +++ b/app/main/models.py @@ -62,3 +62,35 @@ class DB: """ result = db.engine.execute(text(cmd), id=id).fetchall() 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'); diff --git a/app/main/templates/main/index.html b/app/main/templates/main/index.html index 434d7ae..f10d275 100644 --- a/app/main/templates/main/index.html +++ b/app/main/templates/main/index.html @@ -19,7 +19,7 @@
- {{ render_field(form.model, class='form-control', id='modelinput') }} + {{ render_field(form.dataset, class='form-control', id='modelinput') }} Historical (1901-2009) or Projection (2001-2099)
Learn more about the models and scenarios diff --git a/app/main/utils.py b/app/main/utils.py index fcada2d..93f6c16 100644 --- a/app/main/utils.py +++ b/app/main/utils.py @@ -70,5 +70,13 @@ def des_air_indices(indices): def c_to_f(temp): return (temp * 9. / 5.) + 32. + def communitiesSelect(): 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()] diff --git a/app/main/views.py b/app/main/views.py index 44230fc..6b28077 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -2,17 +2,18 @@ from numpy import arange, hstack from flask import session, render_template, request, redirect, url_for +from flask import current_app + from . import main from .forms import AKIForm 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 @main.route('/', methods=['GET']) def index(): - form = AKIForm() - form.community.choices = communitiesSelect() + form = generateForm() session['community_data'] = None session['avg_temp'] = None session['avg_indices'] = None @@ -48,8 +49,7 @@ def index(): @main.route('/', methods=['POST']) def index_submit(): - form = AKIForm() - form.community.choices = communitiesSelect() + form = generateForm() if form.validate(): session['community'] = request.form['community'] session['minyear'] = request.form['minyear'] @@ -57,12 +57,15 @@ def index_submit(): if session['minyear'] > session['maxyear']: 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')) else: + # TODO: Fix post-POST handling return render_template('main/index.html', form=form) +# TODO: reimport this template @main.route('/datatypes') def datatypes(): return render_template('main/datatypes.html') @@ -121,3 +124,10 @@ def delete(): record = request.args.get('record', '') session['save'].pop(record) return redirect(url_for('main.index')) + + +def generateForm(): + form = AKIForm() + form.community.choices = communitiesSelect() + form.dataset.choices = datasetsSelect() + return form diff --git a/app/misc/transform.sql b/app/misc/transform.sql new file mode 100644 index 0000000..4547434 --- /dev/null +++ b/app/misc/transform.sql @@ -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);