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
		Add a link
		
	
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon