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 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')]) | ||||
|  |  | |||
|  | @ -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'); | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ | |||
|             </div> | ||||
|             <div class="form-group col-md-4"> | ||||
|                 <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> | ||||
|                     <a href="{{ url_for('main.datatypes') }}" target="_blank"> | ||||
|                     Learn more about the models and scenarios | ||||
|  |  | |||
|  | @ -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()] | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										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