diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d5fdad..8eaa762 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,5 @@ ## Misc -- [ ] Support multiple models for each target - [ ] Optimize CSV generation (numpy vectorization ?) - [ ] Credit the author of the pixel art planets - [ ] Add a README to the download tarball @@ -23,9 +22,13 @@ - [ ] CRON statement to call it - [ ] Cache warmup - [x] Download raw data (tarball of CSV) for current time interval and targets -- [ ] Download raw data as NetCDF for current everything, via SAMP +- [x] Download raw data as NetCDF for current everything, via SAMP - [x] Add a warning for users with javascript disabled - [ ] Set the log level to _error_ in production (see `web/run.py`) +- [ ] Make the targets dynamic in the orbit plot, allowing zoom +- [ ] Add units to the generated CSV files +- [x] Support multiple models for each target + ## 0.0.0 diff --git a/web/run.py b/web/run.py index e9f8d67..2c658cf 100755 --- a/web/run.py +++ b/web/run.py @@ -1,11 +1,13 @@ +# coding=utf-8 + import StringIO import datetime -import time import gzip import json import logging import random import tarfile +import time import urllib from csv import writer as csv_writer from math import sqrt @@ -15,7 +17,7 @@ from os.path import isfile, join, abspath, dirname from flask import Flask from flask import request from flask import url_for, send_from_directory, abort as abort_flask -from jinja2 import Environment, FileSystemLoader +from jinja2 import Environment, FileSystemLoader, Markup from netCDF4 import Dataset, date2num from yaml import load as yaml_load @@ -101,6 +103,33 @@ def markdown_filter(value, nl2br=False, p=True): return markdowned +_js_escapes = { + '\\': '\\u005C', + '\'': '\\u0027', + '"': '\\u0022', + '>': '\\u003E', + '<': '\\u003C', + '&': '\\u0026', + '=': '\\u003D', + '-': '\\u002D', + ';': '\\u003B', + u'\u2028': '\\u2028', + u'\u2029': '\\u2029' +} +# Escape every ASCII character with a value less than 32. +_js_escapes.update(('%c' % z, '\\u%04X' % z) for z in xrange(32)) + + +def escapejs_filter(value): + escaped = [] + for letter in value: + if letter in _js_escapes: + escaped.append(_js_escapes[letter]) + else: + escaped.append(letter) + + return Markup("".join(escaped)) + tpl_engine = Environment(loader=FileSystemLoader([get_path('view')]), trim_blocks=True, lstrip_blocks=True) @@ -113,6 +142,7 @@ tpl_engine.globals.update( tpl_engine.filters['markdown'] = markdown_filter tpl_engine.filters['md'] = markdown_filter tpl_engine.filters['shuffle'] = shuffle_filter +tpl_engine.filters['escapejs'] = escapejs_filter tpl_global_vars = { 'request': request, @@ -278,11 +308,14 @@ def retrieve_amda_netcdf(orbiter, what, started_at, stopped_at): return local_netc_files +# These two configs are not in the YAML config because adding a new parameter +# will not work as-is, you'll have to edit the netcdf-related code + # The available parameters in the generated CSV files. # The order matters. If you change this you also need to change the # innermost loop of `get_data_for_target`. # The javascript knows the targets' properties under these names. -PROPERTIES = ('time', 'vrad', 'vtan', 'vlen', 'magn', 'temp', 'pdyn', 'dens', +PROPERTIES = ('time', 'vrad', 'vtan', 'vtot', 'btan', 'temp', 'pdyn', 'dens', 'angl', 'xhee', 'yhee') # The parameters that the users can handle. @@ -293,36 +326,48 @@ PARAMETERS = { 'name': 'Dyn. Pressure', 'title': 'The dynamic pressure.', 'units': 'nPa', + 'active': True, + 'position': 10, }, - 'vlen': { - 'slug': 'vlen', + 'vtot': { + 'slug': 'vtot', 'name': 'Velocity', 'title': 'The velocity of the particles.', 'units': 'km/s', + 'active': False, + 'position': 20, }, - 'magn': { - 'slug': 'magn', + 'btan': { + 'slug': 'btan', 'name': 'B Tangential', 'title': 'B Tangential.', 'units': 'nT', + 'active': False, + 'position': 30, }, 'temp': { 'slug': 'temp', 'name': 'Temperature', 'title': 'The absolute temperature.', 'units': 'K', + 'active': False, + 'position': 40, }, 'dens': { 'slug': 'dens', 'name': 'Density', 'title': 'The density N.', - 'units': 'cm^-3', + 'units': u'cm⁻³', + 'active': False, + 'position': 50, }, 'angl': { 'slug': 'angl', 'name': 'Angle T-S-E', 'title': 'Angle Target-Sun-Earth.', 'units': 'deg', + 'active': False, + 'position': 60, }, } @@ -528,7 +573,7 @@ tpl_global_vars['visits'] = get_hit_counter() # ROUTING ##################################################################### @app.route('/favicon.ico') -def favicon(): +def favicon(): # we want it served from the root, not from static/ return send_from_directory( join(app.root_path, 'static', 'img'), 'favicon.ico', mimetype='image/vnd.microsoft.icon' @@ -540,8 +585,11 @@ def favicon(): @app.route("/index.html") def home(): increment_hit_counter() + parameters = PARAMETERS.values() + parameters.sort(key=lambda x: x['position']) return render_view('home.html.jinja2', { 'targets': config['targets'], + 'parameters': parameters, 'planets': [s for s in config['targets'] if s['type'] == 'planet'], 'probes': [s for s in config['targets'] if s['type'] == 'probe'], 'comets': [s for s in config['targets'] if s['type'] == 'comet'], @@ -751,7 +799,7 @@ def download_targets_netcdf(targets, params, started_at, stopped_at): if not isfile(nc_path): abort(500, "No NetCDF to serve. Looked at '%s'." % nc_path) - return send_from_directory(get_path("../cache/"), nc_filename) + return send_from_directory(get_path("../cache"), nc_filename) # API ######################################################################### @@ -773,12 +821,18 @@ def cache_warmup(): Warms up the cache for the current day. Linked to SpaceWeather#edit in swapp.ls """ - from dateutil.relativedelta import relativedelta # relativedelta(years=3) # startted_at = datetime.datetime.now() - relativedelta(years=3) return "To Do" +@app.route("/run.log") +def run_log(): + with open(get_path('run.log'), 'r') as f: + contents = f.read() + return contents + + # DEV TOOLS ################################################################### # @app.route("/inspect") diff --git a/web/static/js/swapp.ls b/web/static/js/swapp.ls index f288985..f54d999 100644 --- a/web/static/js/swapp.ls +++ b/web/static/js/swapp.ls @@ -337,7 +337,7 @@ export class TimeSeries # Data in y-axis (@parameter, @title, @target, data, @visible, @container, @options = {}) -> - # parameter : slug of the parameter to observe, like magn or pdyn + # parameter : slug of the parameter to observe, like btan or pdyn # title : string, more descriptive, shown on the left of the Y axis # target : target object, like described in configuration # data : list of {x: , y: } diff --git a/web/view/home.html.jinja2 b/web/view/home.html.jinja2 index 3da408e..5a3694f 100755 --- a/web/view/home.html.jinja2 +++ b/web/view/home.html.jinja2 @@ -99,13 +99,9 @@ {{ icon('flask') }} Parameters
@@ -537,7 +533,7 @@ var configuration = { time_series_container: '#time_series', orbits_container: '#orbits', - api : { + api: { 'data_for_interval': "{{ request.url_root }}__.csv", 'download': "{{ request.url_root }}__.tar.gz", 'samp': "{{ request.url_root }}___.nc" @@ -545,7 +541,7 @@ var configuration = { sun: { img: '{{ static('img/sun_128.png') }}' }, - targets : { + targets: { {% for target in targets if not target.locked %} {% if not loop.first %},{% endif %} '{{ target.slug }}': { @@ -557,45 +553,15 @@ var configuration = { } {% endfor %} }, -{# todo @Nicolas Define -somehow- error margins of each parameter ? #} -{# todo: generate this from config PARAMETERS #} - parameters : [ + parameters: [ +{% for p in parameters %} { - id: 'pdyn', - title: "Dyn. Pressure (nPa)", - active: true, - unit: "nPa" - }, - { - id: 'magn', - title: "B Tangential (nT)", - active: false, - unit: "nT" - }, - { - id: 'vlen', - title: "Velocity (km/s)", - active: false, - unit: "km/s" - }, - { - id: 'temp', - title: "Temperature (K)", - active: false, - unit: "K" - }, - { - id: 'dens', - title: "Density N (cm⁻³)", - active: false, - unit: "cm⁻³" - }, - { - id: 'angl', - title: "Angle T-S-E (deg)", - active: false, - unit: "deg" - } + id: "{{ p.slug | escapejs }}", + title: "{{ p.name | escapejs }} ({{ p.units | escapejs }})", + active: {{ 'true' if p.active else 'false' }}, + unit: "{{ p.units | escapejs }}" + }{{ ',' if not loop.last }} +{% endfor %} ] }; -- libgit2 0.21.2