Commit f75faf5fc10b7165139fd1787dd8288dad60ecbc
1 parent
01d09323
Exists in
master
and in
3 other branches
WIP
Showing
5 changed files
with
166 additions
and
34 deletions
Show diff stats
CHANGELOG.md
1 | +## TO DO | |
2 | + | |
3 | +- Add source name on time series | |
1 | 4 | - Start/Stop datetime fields |
2 | 5 | - Play button to start time dimension |
3 | -- Download raw data for time interval | |
6 | +- Download raw data (as CSV) for time interval | |
4 | 7 | - Same via SAMP |
5 | 8 | |
6 | -- Planets | |
7 | -- Probes | |
8 | - - Rosetta | |
9 | - - Juno | |
10 | -- Comets (the one visited by rosetta) | |
11 | - | |
12 | 9 | ## 0.0.0 |
13 | 10 | |
14 | 11 | - Initial website skeleton |
... | ... | @@ -18,5 +15,10 @@ |
18 | 15 | - Density `N` (cm^-3) |
19 | 16 | - Angle Planet-Sun-Earth `Delta_angle` (degrees) |
20 | 17 | - Magnetism => B Tangential |
18 | +- Planets | |
19 | +- Probes | |
20 | + - Rosetta | |
21 | + - Juno | |
22 | +- Comets (the one visited by rosetta) | |
21 | 23 | - Orbits axes titles |
22 | 24 | - Logo Europlanet | ... | ... |
web/run.py
... | ... | @@ -10,6 +10,7 @@ import csv |
10 | 10 | import json |
11 | 11 | import gzip |
12 | 12 | import urllib |
13 | +import logging | |
13 | 14 | from pprint import pprint |
14 | 15 | from csv import writer as csv_writer |
15 | 16 | from yaml import load as yaml_load |
... | ... | @@ -19,9 +20,6 @@ from flask import request |
19 | 20 | from jinja2 import Environment, FileSystemLoader |
20 | 21 | from netCDF4 import Dataset |
21 | 22 | |
22 | -# from model.Config import Config | |
23 | -# from model.News import NewsCollection, News | |
24 | - | |
25 | 23 | |
26 | 24 | # PATH RELATIVITY ############################################################# |
27 | 25 | |
... | ... | @@ -43,6 +41,13 @@ with open(get_path('../config.yml'), 'r') as config_file: |
43 | 41 | config = yaml_load(config_file.read()) |
44 | 42 | |
45 | 43 | |
44 | +# LOGGING ##################################################################### | |
45 | + | |
46 | +log = logging.getLogger("HelioPropa") | |
47 | +log.setLevel(logging.INFO) | |
48 | +log.addHandler(logging.FileHandler(get_path('run.log'))) | |
49 | + | |
50 | + | |
46 | 51 | # SETUP FLASK ENGINE ########################################################## |
47 | 52 | |
48 | 53 | app = Flask(__name__, root_path=THIS_DIRECTORY) |
... | ... | @@ -249,12 +254,11 @@ def analyze_cdf(): |
249 | 254 | return si.getvalue() |
250 | 255 | |
251 | 256 | |
252 | -@app.route("/<orbiter>_data.csv") | |
253 | -def get_orbiter_csv(orbiter): | |
257 | +@app.route("/<source>/data.csv") | |
258 | +def get_orbiter_csv(source): | |
254 | 259 | # http://cdpp1.cesr.fr/BASE/DDService/getDataUrl.php?dataSet=tao_ros_sw&StartTime=2014-02-23T10:00&StopTime=2016-02-24T23:59 |
255 | 260 | # Process input parameters |
256 | - if orbiter not in config['models']: | |
257 | - abort(400, "Invalid orbiter '%s'." % orbiter) | |
261 | + source_config = get_source_config(source) | |
258 | 262 | date_fmt = "%Y-%m-%dT%H:%M:%S" |
259 | 263 | started_at = request.args.get('started_at') |
260 | 264 | try: |
... | ... | @@ -267,19 +271,17 @@ def get_orbiter_csv(orbiter): |
267 | 271 | except: |
268 | 272 | abort(400, "Invalid stopped_at parameter : '%s'." % stopped_at) |
269 | 273 | |
270 | - | |
271 | - source_config = get_source_config(orbiter) | |
272 | 274 | # todo: iterate on models when there are many |
273 | 275 | try: |
274 | 276 | model_slug = source_config['models'][0]['slug'] |
275 | 277 | except: |
276 | - abort(500, "Invalid model configuration for '%s'." % orbiter) | |
278 | + abort(500, "Invalid model configuration for '%s'." % source) | |
277 | 279 | |
278 | 280 | # Grab the list of netCDF files from Myriam's API |
279 | 281 | # http://cdpp.irap.omp.eu/BASE/DDService/getDataUrl.php?dataSet=jupiter_orb_all&StartTime=2014-02-23T10:00:10&StopTime=2017-02-24T23:59:00 |
280 | 282 | # http://cdpp.irap.omp.eu/BASE/DATA/TAO/JUPITER/SW/sw_2014.nc.gz |
281 | - model_files = retrieve_data(orbiter, model_slug, started_at, stopped_at) | |
282 | - orbits_files = retrieve_data(orbiter, source_config['orbit'], started_at, stopped_at) | |
283 | + model_files = retrieve_data(source, model_slug, started_at, stopped_at) | |
284 | + orbits_files = retrieve_data(source, source_config['orbit'], started_at, stopped_at) | |
283 | 285 | |
284 | 286 | si = StringIO.StringIO() |
285 | 287 | cw = csv_writer(si) | ... | ... |
web/static/js/swapp.js
... | ... | @@ -6,15 +6,83 @@ |
6 | 6 | SpaceWeather.displayName = 'SpaceWeather'; |
7 | 7 | var prototype = SpaceWeather.prototype, constructor = SpaceWeather; |
8 | 8 | function SpaceWeather(configuration){ |
9 | + this.configuration = configuration; | |
9 | 10 | console.info("Creating Space Weather app...", configuration); |
11 | + this.sources = {}; | |
10 | 12 | } |
13 | + SpaceWeather.prototype.buildDataUrlForSource = function(source_slug){ | |
14 | + var url; | |
15 | + url = this.configuration['api']['data_for_interval']; | |
16 | + url = url.replace('<source>', source_slug); | |
17 | + return url; | |
18 | + }; | |
19 | + SpaceWeather.prototype.addSource = function(source){ | |
20 | + this.sources[source.slug] = source; | |
21 | + return this; | |
22 | + }; | |
23 | + SpaceWeather.prototype.showAllSources = function(){ | |
24 | + var slug, ref$, source; | |
25 | + for (slug in ref$ = this.sources) { | |
26 | + source = ref$[slug]; | |
27 | + source.show(); | |
28 | + } | |
29 | + return this; | |
30 | + }; | |
31 | + SpaceWeather.prototype.showSource = function(source){ | |
32 | + source.show(); | |
33 | + return this; | |
34 | + }; | |
35 | + SpaceWeather.prototype.hideSource = function(source){ | |
36 | + source.hide(); | |
37 | + return this; | |
38 | + }; | |
39 | + SpaceWeather.prototype.loadData = function(source_slug, started_at, stopped_at){ | |
40 | + var sw, promise; | |
41 | + sw = this; | |
42 | + promise = new Promise(function(resolve, reject){ | |
43 | + var url; | |
44 | + url = sw.buildDataUrlForSource(source_slug); | |
45 | + return d3.csv(url + ("?started_at=" + started_at + "&stopped_at=" + stopped_at), function(csv){ | |
46 | + var timeFormat, data; | |
47 | + timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z'); | |
48 | + data = { | |
49 | + 'hci': [] | |
50 | + }; | |
51 | + configuration['parameters'].forEach(function(parameter){ | |
52 | + return data[parameter['id']] = []; | |
53 | + }); | |
54 | + csv.forEach(function(d){ | |
55 | + var dtime; | |
56 | + dtime = timeFormat(d['time']); | |
57 | + configuration['parameters'].forEach(function(parameter){ | |
58 | + var id; | |
59 | + id = parameter['id']; | |
60 | + return data[id].push({ | |
61 | + x: dtime, | |
62 | + y: parseFloat(d[id]) | |
63 | + }); | |
64 | + }); | |
65 | + if (d['xhci'] && d['yhci']) { | |
66 | + return data['hci'].push({ | |
67 | + t: dtime, | |
68 | + x: parseFloat(d['xhci']), | |
69 | + y: parseFloat(d['yhci']) | |
70 | + }); | |
71 | + } | |
72 | + }); | |
73 | + return resolve(data); | |
74 | + }); | |
75 | + }); | |
76 | + return promise; | |
77 | + }; | |
11 | 78 | return SpaceWeather; |
12 | 79 | }()); |
13 | 80 | Source = (function(){ |
14 | 81 | Source.displayName = 'Source'; |
15 | 82 | var prototype = Source.prototype, constructor = Source; |
16 | - function Source(slug){ | |
83 | + function Source(slug, config){ | |
17 | 84 | this.slug = slug; |
85 | + this.config = config; | |
18 | 86 | this.time_series = {}; |
19 | 87 | } |
20 | 88 | Source.prototype.addTimeSeries = function(ts){ | ... | ... |
web/static/js/swapp.ls
... | ... | @@ -7,16 +7,60 @@ const GOLDEN_RATIO = 2 / (1 + Math.sqrt(5)) |
7 | 7 | |
8 | 8 | export class SpaceWeather |
9 | 9 | |
10 | - (configuration) -> | |
10 | + (@configuration) -> | |
11 | 11 | console.info "Creating Space Weather app...", configuration |
12 | + @sources = {} | |
12 | 13 | |
13 | - # fixme | |
14 | + buildDataUrlForSource: (source_slug) -> | |
15 | + url = @configuration['api']['data_for_interval'] | |
16 | + url = url.replace('<source>', source_slug) | |
17 | + url | |
14 | 18 | |
19 | + addSource: (source) -> | |
20 | + @sources[source.slug] = source | |
21 | + this | |
22 | + | |
23 | + showAllSources: -> | |
24 | + for slug, source of @sources | |
25 | + source.show() | |
26 | + this | |
27 | + | |
28 | + showSource: (source) -> | |
29 | + source.show() | |
30 | + this | |
31 | + | |
32 | + hideSource: (source) -> | |
33 | + source.hide() | |
34 | + this | |
35 | + | |
36 | + loadData: (source_slug, started_at, stopped_at) -> | |
37 | + sw = this | |
38 | + promise = new Promise((resolve, reject) -> | |
39 | + url = sw.buildDataUrlForSource(source_slug) | |
40 | + d3.csv(url+"?started_at=#{started_at}&stopped_at=#{stopped_at}", (csv) -> | |
41 | + timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z') | |
42 | + data = {'hci': []}; | |
43 | + configuration['parameters'].forEach((parameter) -> | |
44 | + data[parameter['id']] = [] | |
45 | + ) | |
46 | + csv.forEach((d) -> | |
47 | + dtime = timeFormat(d['time']) | |
48 | + configuration['parameters'].forEach((parameter) -> | |
49 | + id = parameter['id'] | |
50 | + data[id].push({x: dtime, y: parseFloat(d[id])}) | |
51 | + ) | |
52 | + if (d['xhci'] && d['yhci']) | |
53 | + data['hci'].push({t: dtime, x: parseFloat(d['xhci']), y: parseFloat(d['yhci'])}); | |
54 | + ) | |
55 | + resolve(data) | |
56 | + ) | |
57 | + ) | |
58 | + promise | |
15 | 59 | |
16 | 60 | |
17 | 61 | |
18 | 62 | class Source |
19 | - (@slug) -> | |
63 | + (@slug, @config) -> | |
20 | 64 | @time_series = {} |
21 | 65 | |
22 | 66 | addTimeSeries: (ts) -> | ... | ... |
web/view/home.html.jinja2
... | ... | @@ -157,6 +157,10 @@ |
157 | 157 | var configuration = { |
158 | 158 | time_series_container: '#time_series', |
159 | 159 | orbits_container: '#orbits', |
160 | + api : { | |
161 | + 'data_for_interval': "{{ request.url_root }}<source>/data.csv" | |
162 | + // ?started_at=<started_at>&stopped_at=<stopped_at> | |
163 | + }, | |
160 | 164 | sources : { |
161 | 165 | jupiter: { |
162 | 166 | slug: 'jupiter', |
... | ... | @@ -168,30 +172,37 @@ var configuration = { |
168 | 172 | img: '{{ static('img/planet/jupiter_128.png') }}' |
169 | 173 | } |
170 | 174 | }, |
175 | +{# todo @Nicolas Define -somehow- error margins of each parameter #} | |
171 | 176 | parameters : [ |
172 | 177 | { |
173 | 178 | id: 'pdyn', |
174 | - title: "Dynamic Pressure (nPa)" | |
179 | + title: "Dynamic Pressure (nPa)", | |
180 | + unit: "nPa" | |
175 | 181 | }, |
176 | 182 | { |
177 | 183 | id: 'magn', |
178 | - title: "Magnetism (nT)" | |
184 | + title: "Magnetism (nT)", | |
185 | + unit: "nT" | |
179 | 186 | }, |
180 | 187 | { |
181 | 188 | id: 'vlen', |
182 | - title: "Velocity (km/s)" | |
189 | + title: "Velocity (km/s)", | |
190 | + unit: "km/s" | |
183 | 191 | }, |
184 | 192 | { |
185 | 193 | id: 'temp', |
186 | - title: "Temperature (K)" | |
194 | + title: "Temperature (K)", | |
195 | + unit: "K" | |
187 | 196 | }, |
188 | 197 | { |
189 | 198 | id: 'dens', |
190 | - title: "Density N (cm⁻³)" | |
199 | + title: "Density N (cm⁻³)", | |
200 | + unit: "cm⁻³" | |
191 | 201 | }, |
192 | 202 | { |
193 | 203 | id: 'angl', |
194 | - title: "Angle S-S-E (deg)" | |
204 | + title: "Angle S-S-E (deg)", | |
205 | + unit: "deg" | |
195 | 206 | } |
196 | 207 | ] |
197 | 208 | }; |
... | ... | @@ -201,10 +212,17 @@ jQuery().ready(function($){ |
201 | 212 | var orbits; |
202 | 213 | |
203 | 214 | var sw = new SpaceWeather(configuration); |
215 | + sw.loadData('jupiter', '2016-01-01T00:00:00', '2023-01-01T00:00:00').then( | |
216 | + function (data) { console.log('OK', data); }, | |
217 | + function (data) { console.log('Failed', data); } | |
218 | + ); | |
204 | 219 | |
205 | - d3.csv('{{ url_for('get_orbiter_csv', orbiter='jupiter', started_at='2016-03-19T00:00:00', stopped_at='2022-01-01T00:00:00') }}', function(csv){ | |
220 | + d3.csv('{{ url_for('get_orbiter_csv', source='jupiter', started_at='2016-03-19T00:00:00', stopped_at='2022-01-01T00:00:00') }}', function(csv){ | |
206 | 221 | var timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z'); |
207 | - var data = {'pdyn': [], 'magn': [], 'vlen': [], 'temp': [], 'dens': [], 'angl': [], 'hci': []}; | |
222 | + var data = {'hci': []}; | |
223 | + configuration['parameters'].forEach(function(parameter){ | |
224 | + data[parameter['id']] = []; | |
225 | + }); | |
208 | 226 | csv.forEach(function (d) { |
209 | 227 | var dtime = timeFormat(d['time']); |
210 | 228 | configuration['parameters'].forEach(function(parameter){ |
... | ... | @@ -221,9 +239,7 @@ jQuery().ready(function($){ |
221 | 239 | configuration['parameters'].forEach(function(parameter){ |
222 | 240 | var id = parameter['id']; |
223 | 241 | var title = parameter['title']; |
224 | - timeSeries.push(new TimeSeries( | |
225 | - id, title, data[id], container | |
226 | - )); | |
242 | + timeSeries.push(new TimeSeries(id, title, data[id], container)); | |
227 | 243 | }); |
228 | 244 | // move outside (after promises) |
229 | 245 | timeSeries.forEach(function(ts){ | ... | ... |