More or less copy and paste to get mvp
This commit is contained in:
		
							parent
							
								
									871a2f97b3
								
							
						
					
					
						commit
						b86ebd63c2
					
				
					 9 changed files with 606 additions and 31 deletions
				
			
		
							
								
								
									
										45
									
								
								app/main/forms.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								app/main/forms.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | from flask_wtf import Form | ||||||
|  | from wtforms import IntegerField | ||||||
|  | from wtforms.validators import NumberRange, Required | ||||||
|  | from wtforms.ext.sqlalchemy.fields import QuerySelectField | ||||||
|  | from app.models import Community, Dataset, Temperature | ||||||
|  | from sqlalchemy import func | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 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 communities(): | ||||||
|  |     return Community.query.order_by('name') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 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): | ||||||
|  |     community = QuerySelectField(query_factory=communities, | ||||||
|  |                                  get_label='name', | ||||||
|  |                                  allow_blank=True, | ||||||
|  |                                  blank_text='---Select a community---', | ||||||
|  |                                  validators=[Required(message='Please select a community')]) | ||||||
|  | 
 | ||||||
|  |     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')]) | ||||||
							
								
								
									
										71
									
								
								app/main/utils.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/main/utils.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | ||||||
|  | import numpy | ||||||
|  | 
 | ||||||
|  | from app.models import Temperature, Dataset | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def getTemps(datasets, community_id, minyear, maxyear): | ||||||
|  |     temps = Temperature.query.join(Dataset). \ | ||||||
|  |             filter(Dataset.id == Temperature.dataset_id, | ||||||
|  |                    Dataset.id == datasets, | ||||||
|  |                    Temperature.community_id == community_id, | ||||||
|  |                    Temperature.year >= minyear, | ||||||
|  |                    Temperature.year <= maxyear) | ||||||
|  | 
 | ||||||
|  |     length = int(maxyear) - int(minyear) | ||||||
|  |     temps_arr = numpy.zeros((length+1, 12)) | ||||||
|  | 
 | ||||||
|  |     i = 0 | ||||||
|  |     for t in temps.all(): | ||||||
|  |         temps_arr[i,:] =  [t.january, t.february, t.march, | ||||||
|  |                            t.april, t.may, t.june, | ||||||
|  |                            t.july, t.august, t.september, | ||||||
|  |                            t.october, t.november, t.december] | ||||||
|  |         i += 1 | ||||||
|  |     return temps_arr | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def avg_air_temp(temps): | ||||||
|  |     return numpy.average(temps) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def ann_air_indices(temps): | ||||||
|  |     ATI, AFI = 0.0, 0.0 | ||||||
|  |     indices = numpy.zeros((temps.shape[0], 2), dtype='int') | ||||||
|  |     months = [0.0 for m in range(12)] | ||||||
|  |     days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] | ||||||
|  |     i = 0 | ||||||
|  |     for year in temps: | ||||||
|  |         j = 0 | ||||||
|  |         for month in months: | ||||||
|  |             months[j] = days[j] * year[j] | ||||||
|  |             j += 1 | ||||||
|  | 
 | ||||||
|  |         for ind in months: | ||||||
|  |             if ind >= 0.0: | ||||||
|  |                 ATI = ATI + ind | ||||||
|  |             else: | ||||||
|  |                 AFI = AFI + ind | ||||||
|  |         indices[i, 0], indices[i, 1] = int(ATI), int(AFI) | ||||||
|  |         ATI, AFI = 0.0, 0.0 | ||||||
|  |         i += 1 | ||||||
|  |     return indices | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def avg_air_indices(indices): | ||||||
|  |     temp = numpy.average(indices, axis=0) | ||||||
|  |     return (int(temp[0]), int(temp[1])) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def des_air_indices(indices): | ||||||
|  |     if indices.shape[0] > 2: | ||||||
|  |         ati = numpy.sort(indices[:,0]) | ||||||
|  |         afi = numpy.sort(indices[:,1]) | ||||||
|  |         dti = (ati[-1] + ati[-2] + ati[-3]) / 3.0 | ||||||
|  |         dfi = (afi[0] + afi[1] + afi[2]) / 3.0 | ||||||
|  |         return (int(dti), int(dfi)) | ||||||
|  |     else: | ||||||
|  |         return (None, None) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def c_to_f(temp): | ||||||
|  |     return (temp * 9. / 5.) + 32. | ||||||
|  | @ -1,6 +1,114 @@ | ||||||
|  | from numpy import arange, hstack | ||||||
|  | 
 | ||||||
|  | from flask import session, render_template, request, redirect, current_app | ||||||
|  | 
 | ||||||
| from . import main | from . import main | ||||||
|  | from .forms import AKIForm | ||||||
|  | from .utils import getTemps, avg_air_temp, ann_air_indices, avg_air_indices, des_air_indices | ||||||
|  | from app.models import Community, Dataset, Temperature | ||||||
| 
 | 
 | ||||||
| @main.route('/') | 
 | ||||||
|  | @main.route('/', methods=['GET']) | ||||||
| def index(): | def index(): | ||||||
|     return '<h1>Hello world</h1>' |     form = AKIForm() | ||||||
|  |     session['community_data'] = None | ||||||
|  |     session['avg_temp'] = None | ||||||
|  |     session['avg_indices'] = None | ||||||
|  |     session['des_indices'] = None | ||||||
| 
 | 
 | ||||||
|  |     if 'community' in session: | ||||||
|  |         community_id = session['community'] | ||||||
|  |         if all(key in session for key in ('minyear', 'maxyear', 'datasets')): | ||||||
|  |             community = Community.query.get_or_404(community_id) | ||||||
|  | 
 | ||||||
|  |             # TODO: clean this up | ||||||
|  |             session['community_data'] = dict() | ||||||
|  |             session['community_data']['id'] = community_id | ||||||
|  |             session['community_data']['name'] = community.name | ||||||
|  |             session['community_data']['latitude'] = round(community.latitude, 5) | ||||||
|  |             session['community_data']['longitude'] = round(community.longitude, 5) | ||||||
|  | 
 | ||||||
|  |             session['ds_name'] = Dataset.query. \ | ||||||
|  |                 with_entities(Dataset.modelname, Dataset.scenario). \ | ||||||
|  |                 filter_by(id=session['datasets']).all() | ||||||
|  |             temps_arr = getTemps(session['datasets'], community_id, session['minyear'], session['maxyear']) | ||||||
|  | 
 | ||||||
|  |             session['avg_temp'] = avg_air_temp(temps_arr) | ||||||
|  |             indices = ann_air_indices(temps_arr) | ||||||
|  |             session['avg_indices'] = avg_air_indices(indices) | ||||||
|  |             session['des_indices'] = des_air_indices(indices) | ||||||
|  | 
 | ||||||
|  |     return render_template("index.html", form=form) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @main.route('/', methods=['POST']) | ||||||
|  | def index_submit(): | ||||||
|  |     form = AKIForm() | ||||||
|  |     if form.validate(): | ||||||
|  |         session['community'] = request.form['community'] | ||||||
|  |         session['minyear'] = request.form['minyear'] | ||||||
|  |         session['maxyear'] = request.form['maxyear'] | ||||||
|  |         if session['minyear'] > session['maxyear']: | ||||||
|  |             session['maxyear'] = session['minyear'] | ||||||
|  | 
 | ||||||
|  |         session['datasets'] = request.form['model'] | ||||||
|  |         return redirect('/') | ||||||
|  |     else: | ||||||
|  |         return render_template("index.html", form=form) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @main.route('/datatypes') | ||||||
|  | def datatypes(): | ||||||
|  |     return render_template("datatypes.html") | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @main.route('/reset') | ||||||
|  | def reset(): | ||||||
|  |     session.clear() | ||||||
|  |     return redirect('/') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @main.route('/details') | ||||||
|  | def details(): | ||||||
|  |     datasets = request.args.get('datasets', '') | ||||||
|  |     community_id = request.args.get('community_id', '') | ||||||
|  |     minyear = request.args.get('minyear', '') | ||||||
|  |     maxyear = request.args.get('maxyear', '') | ||||||
|  |     temps = getTemps(datasets, community_id, minyear, maxyear) | ||||||
|  |     years = arange(int(minyear), int(maxyear)+1).reshape(int(maxyear)-int(minyear) + 1, 1) | ||||||
|  |     temps = hstack((years, temps)) | ||||||
|  |     return render_template("details.html", | ||||||
|  |         lat=request.args.get('lat', ''), | ||||||
|  |         lon=request.args.get('lon', ''), | ||||||
|  |         community_name=request.args.get('name', ''), | ||||||
|  |         temps=temps) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @main.route('/save') | ||||||
|  | def save(): | ||||||
|  |     if 'save' in session: | ||||||
|  |         i = len(session['save']) | ||||||
|  |         save = session['save'] | ||||||
|  |     else: | ||||||
|  |         save = dict() | ||||||
|  |         i = 0 | ||||||
|  | 
 | ||||||
|  |     save[i] = dict() | ||||||
|  |     save[i]['datasets'] = session['datasets'] | ||||||
|  |     save[i]['ds_name'] = session['ds_name'] | ||||||
|  |     save[i]['community_data'] = session['community_data'] | ||||||
|  |     save[i]['minyear'] = session['minyear'] | ||||||
|  |     save[i]['maxyear'] = session['maxyear'] | ||||||
|  |     save[i]['avg_temp'] = session['avg_temp'] | ||||||
|  |     save[i]['avg_indices'] = session['avg_indices'] | ||||||
|  |     save[i]['des_indices'] = session['des_indices'] | ||||||
|  |     session.clear() | ||||||
|  |     session['save'] = save | ||||||
|  |     return redirect('/') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @main.route('/delete') | ||||||
|  | def delete(): | ||||||
|  |     record = request.args.get('record', '') | ||||||
|  |     session['save'].pop(record) | ||||||
|  |     return redirect('/') | ||||||
|  |  | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| from . import db | from . import db | ||||||
|  | from sqlalchemy.ext.hybrid import hybrid_property | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Community(db.Model): | class Community(db.Model): | ||||||
|  | @ -24,6 +25,10 @@ class Dataset(db.Model): | ||||||
|     resolution = db.Column(db.String(15), nullable=False) |     resolution = db.Column(db.String(15), nullable=False) | ||||||
|     temperatures = db.relationship('Temperature', backref='datasets') |     temperatures = db.relationship('Temperature', backref='datasets') | ||||||
| 
 | 
 | ||||||
|  |     @hybrid_property | ||||||
|  |     def type(self): | ||||||
|  |         return self.datatype.lower().capitalize() | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| class Temperature(db.Model): | class Temperature(db.Model): | ||||||
|     __tablename__ = 'temperatures' |     __tablename__ = 'temperatures' | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								app/templates/_formhelpers.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/templates/_formhelpers.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | {% macro render_field(field) %} | ||||||
|  |     {{ field(**kwargs)|safe }} | ||||||
|  |     {% if field.errors %} | ||||||
|  |     <div class="alert alert-danger"> | ||||||
|  |         <ul> | ||||||
|  |         {% for error in field.errors %} | ||||||
|  |             <li>{{ error }}</li> | ||||||
|  |         {% endfor %} | ||||||
|  |         </ul> | ||||||
|  |     </div> | ||||||
|  |   {% endif %} | ||||||
|  | {% endmacro %} | ||||||
							
								
								
									
										31
									
								
								app/templates/base.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								app/templates/base.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  |     <head> | ||||||
|  |         <title>{{config['TITLE']}}</title> | ||||||
|  |         <link href="/static/css/bootstrap-readable.min.css" rel="stylesheet"> | ||||||
|  |         <link href="/static/css/akindices.css" rel="stylesheet"> | ||||||
|  |         <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> | ||||||
|  |         <script src="/static/js/bootstrap.min.js"></script> | ||||||
|  |         <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|  |     </head> | ||||||
|  |     <body> | ||||||
|  |     <script type=text/javascript> | ||||||
|  |         var $SCRIPT_ROOT = {{ request.script_root|tojson|safe }}; | ||||||
|  |     </script> | ||||||
|  |     <div class="container" style="max-width:90%"> | ||||||
|  |         <div class="page-header"> | ||||||
|  |             <h1>{{title}}<br><small>alaska climate data</small></h1> | ||||||
|  |         </div> | ||||||
|  |         {% block content %}{% endblock %} | ||||||
|  |         <hr> | ||||||
|  | 
 | ||||||
|  |         <div id="footer"> | ||||||
|  |             <p class="text-muted credit"> | ||||||
|  |             <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/3.0/80x15.png" /></a> This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/3.0/">Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License</a>. | ||||||
|  |             <br> | ||||||
|  |             <small>Created by <a href="mailto:mrdillon@alaska.edu">Matthew Dillon</a>, 2015.</small> | ||||||
|  |             </p> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |     </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										66
									
								
								app/templates/details.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								app/templates/details.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,66 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | {% block content %} | ||||||
|  | 
 | ||||||
|  | <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css" /> | ||||||
|  | <script src="http://cdn.leafletjs.com/leaflet-0.5/leaflet.js"></script> | ||||||
|  | 
 | ||||||
|  | <h2>{{ community_name }}</h4> | ||||||
|  | 
 | ||||||
|  | <div id="map" style="width: 500px; height: 300px"></div> | ||||||
|  | <br> | ||||||
|  | 
 | ||||||
|  | <h3>Monthly Temperatures</h3> | ||||||
|  | <div class="table-responsive"> | ||||||
|  |     <table class="table table-hover table-condensed table-bordered"> | ||||||
|  |         <thead> | ||||||
|  |             <tr> | ||||||
|  |                 <th>Year<br> </th> | ||||||
|  |                 <th>January<br>°C</th> | ||||||
|  |                 <th>February<br>°C</th> | ||||||
|  |                 <th>March<br>°C</th> | ||||||
|  |                 <th>April<br>°C</th> | ||||||
|  |                 <th>May<br>°C</th> | ||||||
|  |                 <th>June<br>°C</th> | ||||||
|  |                 <th>July<br>°C</th> | ||||||
|  |                 <th>August<br>°C</th> | ||||||
|  |                 <th>September<br>°C</th> | ||||||
|  |                 <th>October<br>°C</th> | ||||||
|  |                 <th>November<br>°C</th> | ||||||
|  |                 <th>December<br>°C</th> | ||||||
|  |             </tr> | ||||||
|  |         </thead> | ||||||
|  |         <tbody> | ||||||
|  |            {% for temp in temps %} | ||||||
|  |          <tr> | ||||||
|  |           <td>{{ temp[0]|int }}</td> | ||||||
|  |           <td>{{ temp[1]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[2]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[3]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[4]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[5]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[6]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[7]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[8]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[9]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[10]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[11]|round(2) }}</td> | ||||||
|  |           <td>{{ temp[12]|round(2) }}</td> | ||||||
|  |          </tr> | ||||||
|  |        {% endfor %} | ||||||
|  |    </tbody> | ||||||
|  | 
 | ||||||
|  | </table> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | <script> | ||||||
|  | var map = L.map('map').setView([{{ lat }}, {{ lon }}], 5); | ||||||
|  | L.tileLayer('http://otile1.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg', { | ||||||
|  |     maxZoom: 18, | ||||||
|  |     attribution: '{{ community_name }}, AK' | ||||||
|  | }).addTo(map); | ||||||
|  | var marker_1 = L.marker([{{ lat }}, {{ lon }}]); | ||||||
|  | marker_1.bindPopup("{{ community_name }}, AK<br>{{ lat }}° N, {{ lon }}° W"); | ||||||
|  | map.addLayer(marker_1) | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										230
									
								
								app/templates/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								app/templates/index.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,230 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | {% from "_formhelpers.html" import render_field %} | ||||||
|  | {% block content %} | ||||||
|  | 
 | ||||||
|  | <p class="lead" align="justify"> | ||||||
|  |     Air temperature data from over 400 communities, reduced to relevant engineering parameters | ||||||
|  |     (<a href="#info">Additional info</a>) | ||||||
|  | </p> | ||||||
|  | 
 | ||||||
|  | <h3>Search</h3> | ||||||
|  | 
 | ||||||
|  | <form action="" method="post" role="form"> | ||||||
|  |     {{ form.csrf_token }} | ||||||
|  |     <div class="row"> | ||||||
|  |         <div class="col-md-12"> | ||||||
|  |             <div class="form-group col-md-4"> | ||||||
|  |                 <label for="communityinput">Community</label> | ||||||
|  |                 {{ render_field(form.community, class='form-control', id='communityinput') }} | ||||||
|  |             </div> | ||||||
|  |             <div class="form-group col-md-4"> | ||||||
|  |                 <label for="modelinput">Dataset</label> | ||||||
|  |                 {{ render_field(form.model, 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 | ||||||
|  |                 </a></small> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <div class="row"> | ||||||
|  |         <div class="col-md-12"> | ||||||
|  |             <div class="form-group col-md-4"> | ||||||
|  |                 <label for="minyearinput">Start Year</label> | ||||||
|  |                 {{ render_field(form.minyear, class='form-control', id='minyearinput') }} | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <div class="form-group col-md-4"> | ||||||
|  |                 <label for="maxyearinput">End Year</label> | ||||||
|  |                 {{ render_field(form.maxyear, class='form-control', id='maxyearinput') }} | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | 
 | ||||||
|  |     <div class="row"> | ||||||
|  |         <div class="col-md-12"> | ||||||
|  |             <div class="form-group col-md-4"> | ||||||
|  |                 <input type="submit" name="submit" class="btn btn-primary form-control" | ||||||
|  |                        value="Get Temperatures" > | ||||||
|  |             </div> | ||||||
|  |             <div class="form-group col-md-4"> | ||||||
|  |                 <input type="button" name="reset" class="btn btn-danger form-control" | ||||||
|  |                        onclick="window.location.href='{{ url_for('main.reset') }}'" | ||||||
|  |                        value="Clear All Data" /> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </form> | ||||||
|  | 
 | ||||||
|  | <h3>Results</h3> | ||||||
|  |         <div class="table-responsive"> | ||||||
|  |             <table class="table table-hover table-condensed table-bordered"> | ||||||
|  |                 <thead> | ||||||
|  |                     <tr> | ||||||
|  |                         <th>Community<br> </th> | ||||||
|  |                         <th>Years<br> </th> | ||||||
|  |                         <th>T<sub>avg</sub><br>°C</th> | ||||||
|  |                         <th>ATI<br>°C-days</th> | ||||||
|  |                         <th>AFI<br>°C-days</th> | ||||||
|  |                         <th>DTI<br>°C-days</th> | ||||||
|  |                         <th>DFI<br>°C-days</th> | ||||||
|  |                         <th>Type<br> </th> | ||||||
|  |                         <th width="50px">Add/<br>Remove</th> | ||||||
|  |                     </tr> | ||||||
|  |                 </thead> | ||||||
|  |                 <tbody> | ||||||
|  |                     <tr class="active"> | ||||||
|  |                         <td colspan="9" align="center"> | ||||||
|  |                             Current Search | ||||||
|  |                         </td> | ||||||
|  |                     </tr> | ||||||
|  |                     {% if session['avg_temp'] %} | ||||||
|  |                     <tr> | ||||||
|  |                         <td><a href="{{ url_for('main.details', lat=session['community_data']['latitude'], | ||||||
|  |                                         lon=session['community_data']['longitude'], | ||||||
|  |                                         name=session['community_data']['name'], | ||||||
|  |                                         datasets=session['datasets'], | ||||||
|  |                                         community_id=session['community_data']['id'], | ||||||
|  |                                         minyear=session['minyear'], | ||||||
|  |                                         maxyear=session['maxyear']) }}" | ||||||
|  |                                         target="_blank"> | ||||||
|  |                                         {{ session['community_data']['name'] }}<br> | ||||||
|  |                             <small>{{ session['community_data']['latitude'] }}° N, | ||||||
|  |                             {{ session['community_data']['longitude'] }}° W</small></a></td> | ||||||
|  |                         <td>{{ session['minyear'] }} - {{ session['maxyear'] }}</td> | ||||||
|  |                         <td>{{ session['avg_temp']|round(1) }}</td> | ||||||
|  |                         <td>{{ session['avg_indices'][0] }}</td> | ||||||
|  |                         <td>{{ session['avg_indices'][1] }}</td> | ||||||
|  |                         <td>{{ session['des_indices'][0] }}</td> | ||||||
|  |                         <td>{{ session['des_indices'][1] }}</td> | ||||||
|  |                         <td>{{ session['ds_name'][0][0] }} ({{ session['ds_name'][0][1] }})</td> | ||||||
|  |                         <td><button type="button" class="btn btn-success btn-sm" | ||||||
|  |                                     onclick="window.location.href='{{ url_for('main.save') }}'" | ||||||
|  |                                     title="Click to save this search"> | ||||||
|  |                             <span class="glyphicon glyphicon-plus-sign"></span> | ||||||
|  |                             </button></td> | ||||||
|  |                     </tr> | ||||||
|  |                     {% else %} | ||||||
|  |                     <tr> | ||||||
|  |                         <td colspan="9" align="center"> | ||||||
|  |                             [no data] | ||||||
|  |                         </td> | ||||||
|  |                     </tr> | ||||||
|  |                     {% endif %} | ||||||
|  |                     {# | ||||||
|  |                     <tr> | ||||||
|  |                         <td colspan="9"> </td> | ||||||
|  |                     </tr> | ||||||
|  |                     #} | ||||||
|  |                     <tr class="active"> | ||||||
|  |                         <td colspan="9" align="center"> | ||||||
|  |                             Saved Searches | ||||||
|  |                         </td> | ||||||
|  |                     </tr> | ||||||
|  |                     {% if session.save %} | ||||||
|  |                     {% for key, value in session.save|dictsort %} | ||||||
|  |                     <tr> | ||||||
|  |                         <td><a href="{{ url_for('main.details', lat=value['community_data']['latitude'], | ||||||
|  |                                         lon=value['community_data']['longitude'], | ||||||
|  |                                         name=value['community_data']['name'], | ||||||
|  |                                         datasets=value['datasets'], | ||||||
|  |                                         community_id=value['community_data']['id'], | ||||||
|  |                                         minyear=value['minyear'], | ||||||
|  |                                         maxyear=value['maxyear']) }}" | ||||||
|  |                                         target="_blank"> | ||||||
|  |                                         {{ value['community_data']['name'] }}<br> | ||||||
|  |                             <small>{{ value['community_data']['latitude'] }}° N, | ||||||
|  |                             {{ value['community_data']['longitude'] }}° W</small></a></td> | ||||||
|  |                         <td>{{ value['minyear'] }} - {{ value['maxyear'] }}</td> | ||||||
|  |                         <td>{{ value['avg_temp']|round(1) }}</td> | ||||||
|  |                         <td>{{ value['avg_indices'][0] }}</td> | ||||||
|  |                         <td>{{ value['avg_indices'][1] }}</td> | ||||||
|  |                         <td>{{ value['des_indices'][0] }}</td> | ||||||
|  |                         <td>{{ value['des_indices'][1] }}</td> | ||||||
|  |                         <td>{{ value['ds_name'][0][0] }} ({{ value['ds_name'][0][1] }})</td> | ||||||
|  |                         <td><button type="button" class="btn btn-danger btn-sm" | ||||||
|  |                             onclick="window.location.href='{{ url_for('main.delete', record=key) }}'" | ||||||
|  |                             title="Click to delete this search"> | ||||||
|  |                             <span class="glyphicon glyphicon-trash"></span></button></td> | ||||||
|  |                     </tr> | ||||||
|  |                     {% endfor %} | ||||||
|  |                     {% else %} | ||||||
|  |                     <tr> | ||||||
|  |                         <td colspan="9" align="center"> | ||||||
|  |                             [no data] | ||||||
|  |                         </td> | ||||||
|  |                     </tr> | ||||||
|  |                     {% endif %} | ||||||
|  |                 </tbody> | ||||||
|  |             </table> | ||||||
|  |         <strong> | ||||||
|  |         NOTE: The parameters calculated by AKIndices are based on average monthly temperatures, | ||||||
|  |         not average daily temperatures. As well, derived data is provided without any rounding or | ||||||
|  |         consideration for significant digits, allowing the user to decide what is appropriate for | ||||||
|  |         their analysis. | ||||||
|  |         </strong> | ||||||
|  |         </div> | ||||||
|  | 
 | ||||||
|  | <div align="justify"> | ||||||
|  | <a name="info"></a> | ||||||
|  | <h3>Info</h3> | ||||||
|  | <dl class="dl-horizontal"> | ||||||
|  |   <dt>What</dt> | ||||||
|  |   <dd>AKIndices provides basic engineering climate parameters that are commonly used for engineering and | ||||||
|  |       site-development purposes. These parameters include: | ||||||
|  |         <ul> | ||||||
|  |             <li><strong>T<sub>avg</sub>:</strong> The average (arithmetic mean) air temperature, based on all of | ||||||
|  |                 the monthly air temperatures for the specified range of years. | ||||||
|  |             </li> | ||||||
|  |             <li><strong>ATI:</strong> The average (arithmetic mean) annual thawing index. The thawing index is the | ||||||
|  |                 total number of degree-days above the freezing point. The number displayed by AKIndices is the | ||||||
|  |                 average of the annual indices for the specified range of years. | ||||||
|  |             </li> | ||||||
|  |             <li><strong>AFI:</strong> The average (arithmetic mean) annual freezing index. The freezing index is the | ||||||
|  |                 total number of degree-days below the freezing point. The number displayed by AKIndices is the | ||||||
|  |                 average of the annual indices for the specified range of years. | ||||||
|  |             </li> | ||||||
|  |             <li><strong>DTI:</strong> The design thawing index. The number displayed by AKIndices is the | ||||||
|  |                 arithmetic mean of the three warmest thawing indices for the specified range of years. If less | ||||||
|  |                 than three years are displayed, the DTI is listed as 'None.' Typically, the DTI is calculated | ||||||
|  |                 over a 30-year or 10-year time span. | ||||||
|  |             </li> | ||||||
|  |             <li><strong>DFI:</strong> The design freezing index. The number displayed by AKIndices is the | ||||||
|  |                 arithmetic mean of the three coolest freezing indices for the specified range of years. If less | ||||||
|  |                 than three years are displayed, the DFI is listed as 'None.' Typically, the DFI is calculated | ||||||
|  |                 over a 30-year or 10-year time span. | ||||||
|  |             </li> | ||||||
|  |         </ul> | ||||||
|  |   </dd> | ||||||
|  |   <dt>Why</dt> | ||||||
|  |   <dd>AKIndices provides quick and simple access to the massive amounts of data released by the SNAP | ||||||
|  |       group. It does not aim to replace, modify, or build on SNAP's work, but rather provide an alternative | ||||||
|  |       means for users to explore and understand the data.</dd> | ||||||
|  |   <dt>How</dt> | ||||||
|  |   <dd>AKIndices is built with <a href="http://www.python.org" target="_blank">python</a>. Check out | ||||||
|  |       <a href="http://github.com/thermokarst/AKExtract" target="_blank">AKExtract</a> and | ||||||
|  |       <a href="http://github.com/thermokarst/AKIndices" target="_blank">AKIndices</a> on GitHub for more info | ||||||
|  |       on how to install on your own machine, fork the project, or submit | ||||||
|  |       <a href="http://github.com/thermokarst/AKIndices/issues" target="_blank">bug reports.</a> | ||||||
|  |       In a nutshell, AKExtract takes a list of communities and their coordinates, as well as SNAP datasets, | ||||||
|  |       and extracts the air temperature data from the data point closest to a community's location. AKIndices | ||||||
|  |       is the front-end for interacting with that extracted data. | ||||||
|  |   </dd> | ||||||
|  |   <dt>Who</dt> | ||||||
|  |   <dd>This project is the work of <a href="mailto:mrdillon@alaska.edu">Matthew Dillon.</a> | ||||||
|  |       While this project would not exist without <a href="http://www.snap.uaf.edu" target="_blank">SNAP</a>, | ||||||
|  |       AKIndices is <em>not endorsed or supported by SNAP in any way.</em> Before utilizing the derived data | ||||||
|  |       from AKIndices make sure to take a look at SNAP's page to learn about the science | ||||||
|  |       and the methods behind their products.<br> | ||||||
|  |   </dd> | ||||||
|  | </dl> | ||||||
|  | <h4>This product is provided as-is, with no warranty express or implied. Use at your own risk.</h4> | ||||||
|  | <h4>Commercial use disclaimer: It is the sole responsibility of the user to execute any agreements | ||||||
|  |     with SNAP <a href="http://www.snap.uaf.edu/people.php?topic=data#contact" target="_blank">regarding commercial | ||||||
|  |     use</a> of the SNAP data (potentially including the derived products found on this page).</h4> | ||||||
|  | <h4>Question? Comment? Find a problem? <a href="mailto:mrdillon@alaska.edu">Email me</a> | ||||||
|  |     or <a href="http://github.com/thermokarst/AKIndices/issues" target="_blank">submit a bug report!</a></h4> | ||||||
|  | </div> | ||||||
|  | 
 | ||||||
|  | {% endblock %} | ||||||
|  | @ -7,4 +7,11 @@ SQLAlchemy==1.0.5 | ||||||
| Werkzeug==0.10.4 | Werkzeug==0.10.4 | ||||||
| itsdangerous==0.24 | itsdangerous==0.24 | ||||||
| psycopg2==2.6.1 | psycopg2==2.6.1 | ||||||
| wsgiref==0.1.2 | Flask-WTF==0.12 | ||||||
|  | WTForms==2.0.2 | ||||||
|  | flake8==2.4.1 | ||||||
|  | flake8-docstrings==0.2.1.post1 | ||||||
|  | mccabe==0.3.1 | ||||||
|  | pep257==0.6.0 | ||||||
|  | pep8==1.5.7 | ||||||
|  | pyflakes==0.8.1 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Matthew Dillon
						Matthew Dillon