Commit 6491a1f1006f76a7f044a2656f2bd426b49edaf2

Authored by Goutte
1 parent 3faa136f

Fix up the bugs listed by Vincent.

CHANGELOG.md
... ... @@ -21,6 +21,7 @@
21 21 - [ ] Cache cleanup
22 22 - [x] API at /cache/clear
23 23 - [ ] CRON statement to call it
  24 +- [ ] Cache warmup
24 25 - [x] Download raw data (tarball of CSV) for current time interval and targets
25 26 - [ ] Download raw data as NetCDF for current everything, via SAMP
26 27 - [x] Add a warning for users with javascript disabled
... ...
config.yml
... ... @@ -5,7 +5,7 @@
5 5 # The HTML metadata in the page header.
6 6 # Don't put double quotes (") in any of these fields.
7 7 meta:
8   - title: Space Weather
  8 + title: Heliopropa ⋅ Solar System Weather
9 9 keywords:
10 10 - science
11 11 - cdpp
... ... @@ -15,6 +15,16 @@ meta:
15 15 # Will be shown by search engines below the title of the page.
16 16 description: Space weather predictions around solar celestial bodies.
17 17  
  18 +# The top bar
  19 +header:
  20 + title: CDPP / Heliopropa
  21 + links:
  22 + - text: Model
  23 + href: "https://onlinelibrary.wiley.com/doi/10.1029/2004JA010959/abstract"
  24 + - text: Horizon 2020
  25 + href: "https://ec.europa.eu/programmes/horizon2020/"
  26 +
  27 +
18 28  
19 29 # A list of authors that will appear in the HTML metadata and possibly in the
20 30 # authorship page as well. The order does not matter, it will be shuffled.
... ...
web/run.py
... ... @@ -283,7 +283,7 @@ def retrieve_amda_netcdf(orbiter, what, started_at, stopped_at):
283 283 # innermost loop of `get_data_for_target`.
284 284 # The javascript knows the targets' properties under these names.
285 285 PROPERTIES = ('time', 'vrad', 'vtan', 'vlen', 'magn', 'temp', 'pdyn', 'dens',
286   - 'angl', 'xhci', 'yhci')
  286 + 'angl', 'xhee', 'yhee')
287 287  
288 288 # The parameters that the users can handle.
289 289 # The slug must be one of the properties above.
... ... @@ -371,12 +371,12 @@ def get_data_for_target(target_config, started_at, stopped_at):
371 371 (target_config['name'], orbit_file))
372 372 cdf_handle = Dataset(orbit_file, "r", format="NETCDF4")
373 373 times = cdf_handle.variables['Time'] # YYYY DOY HH MM SS .ms
374   - data_hci = cdf_handle.variables['HCI']
375   - for time, datum_hci in zip(times, data_hci):
  374 + data_hee = cdf_handle.variables['HEE']
  375 + for time, datum_hee in zip(times, data_hee):
376 376 dtime = datetime_from_list(time)
377 377 if started_at <= dtime <= stopped_at:
378 378 dkey = dtime.strftime(precision)
379   - orbit_data[dkey] = datum_hci
  379 + orbit_data[dkey] = datum_hee
380 380 cdf_handle.close()
381 381  
382 382 all_data = {} # keys are datetime as str, values tuples of data
... ... @@ -401,16 +401,16 @@ def get_data_for_target(target_config, started_at, stopped_at):
401 401 dtime = datetime_from_list(time)
402 402 if started_at <= dtime <= stopped_at:
403 403 dkey = dtime.strftime(precision)
404   - x_hci = None
405   - y_hci = None
  404 + x_hee = None
  405 + y_hee = None
406 406 if dkey in orbit_data:
407   - x_hci = orbit_data[dkey][0]
408   - y_hci = orbit_data[dkey][1]
  407 + x_hee = orbit_data[dkey][0]
  408 + y_hee = orbit_data[dkey][1]
409 409 all_data[dkey] = (
410 410 dtime.strftime("%Y-%m-%dT%H:%M:%S+00:00"),
411 411 vrad, vtan, sqrt(vrad * vrad + vtan * vtan),
412 412 datum_b, datum_t, datum_n, datum_p, datum_d,
413   - x_hci, y_hci
  413 + x_hee, y_hee
414 414 )
415 415 cdf_handle.close()
416 416  
... ... @@ -726,14 +726,14 @@ def download_targets_netcdf(targets, params, started_at, stopped_at):
726 726 nc_var[:] = values
727 727  
728 728 # ORBIT #
729   - nc_x = nc_group.createVariable('xhci', 'f8', (dimension,))
  729 + nc_x = nc_group.createVariable('xhee', 'f8', (dimension,))
730 730 nc_x.units = 'Au'
731   - nc_y = nc_group.createVariable('yhci', 'f8', (dimension,))
  731 + nc_y = nc_group.createVariable('yhee', 'f8', (dimension,))
732 732 nc_y.units = 'Au'
733 733 values_x = []
734 734 values_y = []
735   - index_x = available_params.index('xhci')
736   - index_y = available_params.index('yhci')
  735 + index_x = available_params.index('xhee')
  736 + index_y = available_params.index('yhee')
737 737 for dkey in dkeys:
738 738 dval = data[dkey]
739 739 values_x.append(dval[index_x])
... ...
web/static/js/swapp.js
... ... @@ -42,7 +42,7 @@
42 42 SpaceWeather.prototype.init = function(){
43 43 "This is called by the inline bootstrap javascript code.\nThis ain't in the constructor because it might return a Promise later on.\n(for the loader, for example)";
44 44 var started_at, stopped_at, this$ = this;
45   - started_at = moment().subtract(1, 'year').hours(0).minutes(0).seconds(0);
  45 + started_at = moment().subtract(6, 'month').hours(0).minutes(0).seconds(0);
46 46 stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0);
47 47 this.setStartAndStop(started_at, stopped_at);
48 48 this.loadAndCreatePlots(started_at, stopped_at);
... ... @@ -126,7 +126,7 @@
126 126 console.debug("Requested CSV for " + target_slug + "...", csv);
127 127 timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z');
128 128 data = {
129   - 'hci': []
  129 + 'hee': []
130 130 };
131 131 configuration['parameters'].forEach(function(parameter){
132 132 return data[parameter['id']] = [];
... ... @@ -148,11 +148,11 @@
148 148 y: parseFloat(d[id])
149 149 });
150 150 });
151   - if (d['xhci'] && d['yhci']) {
152   - return data['hci'].push({
  151 + if (d['xhee'] && d['yhee']) {
  152 + return data['hee'].push({
153 153 t: dtime,
154   - x: parseFloat(d['xhci']),
155   - y: parseFloat(d['yhci'])
  154 + x: parseFloat(d['xhee']),
  155 + y: parseFloat(d['yhee'])
156 156 });
157 157 }
158 158 });
... ... @@ -180,12 +180,11 @@
180 180 console.info("Loading CSV data of " + target.name + "…");
181 181 targetButton = $(".targets-filters .target." + target.slug);
182 182 targetButton.addClass('loading');
183   - targetButton.removeClass('failed');
184   - targetButton.removeClass('empty');
  183 + targetButton.removeClass('failed empty');
185 184 return this$.loadData(target.slug, started_at, stopped_at).then(function(data){
186 185 console.info("Loaded CSV data of " + target.name + ".", data);
187 186 this$.createTimeSeries(target, data);
188   - this$.orbits.initOrbiter(target.slug, target.config, data['hci']);
  187 + this$.orbits.initOrbiter(target.slug, target.config, data['hee']);
189 188 targetButton.removeClass('loading');
190 189 if (target.active) {
191 190 return this$.hideLoader();
... ... @@ -392,7 +391,7 @@
392 391 });
393 392 };
394 393 TimeSeries.prototype.init = function(){
395   - var clipId, dx, this$ = this;
  394 + var formatMillisecond, formatSecond, formatMinute, formatHour, formatDay, formatWeek, formatMonth, formatYear, multiFormat, clipId, dx, this$ = this;
396 395 console.info("Initializing plot of " + this + "…");
397 396 this.margin = {
398 397 top: 30,
... ... @@ -402,7 +401,40 @@
402 401 };
403 402 this.xScale = d3.scaleTime().domain(this.xDataExtent);
404 403 this.yScale = d3.scaleLinear().domain(this.yDataExtent);
405   - this.xAxis = d3.axisBottom().ticks(7);
  404 + formatMillisecond = d3.timeFormat(".%L");
  405 + formatSecond = d3.timeFormat(":%S");
  406 + formatMinute = d3.timeFormat("%I:%M");
  407 + formatHour = d3.timeFormat("%I:%M");
  408 + formatDay = d3.timeFormat("%a %d");
  409 + formatWeek = d3.timeFormat("%b %d");
  410 + formatMonth = d3.timeFormat("%B");
  411 + formatYear = d3.timeFormat("%Y");
  412 + multiFormat = function(date){
  413 + if (date > d3.timeSecond(date)) {
  414 + return formatMillisecond(date);
  415 + }
  416 + if (date > d3.timeMinute(date)) {
  417 + return formatSecond(date);
  418 + }
  419 + if (date > d3.timeHour(date)) {
  420 + return formatMinute(date);
  421 + }
  422 + if (date > d3.timeDay(date)) {
  423 + return formatHour(date);
  424 + }
  425 + if (date > d3.timeMonth(date)) {
  426 + if (date > d3.timeWeek(date)) {
  427 + return formatDay(date);
  428 + } else {
  429 + return formatWeek(date);
  430 + }
  431 + }
  432 + if (date > d3.timeYear(date)) {
  433 + return formatMonth(date);
  434 + }
  435 + return formatYear(date);
  436 + };
  437 + this.xAxis = d3.axisBottom().tickFormat(multiFormat).ticks(7);
406 438 this.yAxis = d3.axisLeft().ticks(10);
407 439 this.line = d3.line().x(function(d){
408 440 return this$.xScale(d.x);
... ... @@ -563,7 +595,7 @@
563 595 TimeSeries.prototype.bisectDate = d3.bisector(function(d){
564 596 return d.x;
565 597 }).left;
566   - TimeSeries.prototype.timeFormat = d3.timeFormat("%Y-%m-%d %Hh");
  598 + TimeSeries.prototype.timeFormat = d3.timeFormat("%Y-%m-%d %H:%M");
567 599 TimeSeries.prototype.moveCursor = function(x0){
568 600 var i, d0, d1, d, xx, yy, mirrored, dx, transform;
569 601 i = this.bisectDate(this.data, x0, 1);
... ... @@ -634,7 +666,7 @@
634 666 this.yAxisTitle.append('tspan').attr('dy', '-3px').text(' (AU)');
635 667 this.yAxisTitle.attr('transform', 'rotate(-90)');
636 668 this.sun = this.plotWrapper.append("svg:image").attr('xlink:href', this.options.sun.img).attr('width', '32px').attr('height', '32px');
637   - this.sun.append('svg:title').text("Sol");
  669 + this.sun.append('svg:title').text("Sun");
638 670 $(this.svg.node()).hide();
639 671 return this.resize();
640 672 };
... ... @@ -651,6 +683,7 @@
651 683 this.yScale = d3.scaleLinear().domain([-1 * this.extremum, this.extremum]);
652 684 orbit_ellipse = this.plotWrapper.append("svg:ellipse").classed('orbit orbit_ellipse', true);
653 685 orbiter = this.plotWrapper.append("svg:image").attr('xlink:href', config['img']).attr('width', '32px').attr('height', '32px');
  686 + orbiter.append('svg:title').text(config.name);
654 687 orbit_line = d3.line().x(function(d){
655 688 return this$.xScale(d.x);
656 689 }).y(function(d){
... ...
web/static/js/swapp.ls
... ... @@ -74,7 +74,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE
74 74 """
75 75 # Default time interval is from two weeks ago to one week ahead.
76 76 # We set the h/m/s to zero to benefit from a daily cache.
77   - started_at = moment().subtract(1, 'year').hours(0).minutes(0).seconds(0)
  77 + started_at = moment().subtract(6, 'month').hours(0).minutes(0).seconds(0)
78 78 stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0)
79 79 @setStartAndStop(started_at, stopped_at)
80 80 @loadAndCreatePlots(started_at, stopped_at)
... ... @@ -138,7 +138,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE
138 138 d3.csv(url, (csv) ->
139 139 console.debug("Requested CSV for #{target_slug}...", csv)
140 140 timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z')
141   - data = { 'hci': [] }
  141 + data = { 'hee': [] }
142 142 configuration['parameters'].forEach((parameter) ->
143 143 data[parameter['id']] = []
144 144 )
... ... @@ -150,9 +150,9 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE
150 150 id = parameter['id']
151 151 data[id].push({x: dtime, y: parseFloat(d[id])})
152 152 )
153   - if d['xhci'] and d['yhci']
154   - data['hci'].push({
155   - t: dtime, x: parseFloat(d['xhci']), y: parseFloat(d['yhci'])
  153 + if d['xhee'] and d['yhee']
  154 + data['hee'].push({
  155 + t: dtime, x: parseFloat(d['xhee']), y: parseFloat(d['yhee'])
156 156 })
157 157 )
158 158 resolve data
... ... @@ -175,13 +175,12 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE
175 175 console.info "Loading CSV data of #{target.name}…"
176 176 targetButton = $(".targets-filters .target.#{target.slug}")
177 177 targetButton.addClass('loading')
178   - targetButton.removeClass('failed')
179   - targetButton.removeClass('empty') # fixme
  178 + targetButton.removeClass('failed empty')
180 179 @loadData(target.slug, started_at, stopped_at).then(
181 180 (data) ~>
182 181 console.info "Loaded CSV data of #{target.name}.", data
183 182 @createTimeSeries(target, data)
184   - @orbits.initOrbiter(target.slug, target.config, data['hci'])
  183 + @orbits.initOrbiter(target.slug, target.config, data['hee'])
185 184 targetButton.removeClass('loading')
186 185 if target.active then @hideLoader() else @disableTarget(target.slug)
187 186 ,
... ... @@ -341,8 +340,28 @@ export class TimeSeries
341 340 @xScale = d3.scaleTime().domain(@xDataExtent)
342 341 @yScale = d3.scaleLinear().domain(@yDataExtent)
343 342  
  343 + formatMillisecond = d3.timeFormat(".%L")
  344 + formatSecond = d3.timeFormat(":%S")
  345 + formatMinute = d3.timeFormat("%I:%M")
  346 + formatHour = d3.timeFormat("%I:%M")
  347 + formatDay = d3.timeFormat("%a %d")
  348 + formatWeek = d3.timeFormat("%b %d")
  349 + formatMonth = d3.timeFormat("%B")
  350 + formatYear = d3.timeFormat("%Y")
  351 +
  352 + multiFormat = (date) ->
  353 + if date > d3.timeSecond(date) then return formatMillisecond(date)
  354 + if date > d3.timeMinute(date) then return formatSecond(date)
  355 + if date > d3.timeHour(date) then return formatMinute(date)
  356 + if date > d3.timeDay(date) then return formatHour(date)
  357 + if date > d3.timeMonth(date)
  358 + if date > d3.timeWeek(date) then return formatDay(date)
  359 + else return formatWeek(date)
  360 + if date > d3.timeYear(date) then return formatMonth(date)
  361 + return formatYear(date)
  362 +
344 363 @xAxis = d3.axisBottom()
345   -# .tickFormat(d3.timeFormat("%Y-%m-%d"))
  364 + .tickFormat(multiFormat)
346 365 .ticks(7)
347 366 @yAxis = d3.axisLeft()
348 367 .ticks(10)
... ... @@ -554,7 +573,7 @@ export class TimeSeries
554 573 @focus.style("display", "none")
555 574  
556 575 bisectDate: d3.bisector((d) -> d.x).left # /!\ complex
557   - timeFormat: d3.timeFormat("%Y-%m-%d %Hh")
  576 + timeFormat: d3.timeFormat("%Y-%m-%d %H:%M")
558 577  
559 578 moveCursor: (x0) ->
560 579 i = @bisectDate(@data, x0, 1)
... ... @@ -610,7 +629,7 @@ export class Orbits
610 629 left: 60
611 630 }
612 631  
613   - @data = {} # slug => HCI array
  632 + @data = {} # slug => HEE array
614 633 @orbiters = {} # slug => config
615 634 @orbitersElements = {}
616 635 @extremum = 1
... ... @@ -647,7 +666,7 @@ export class Orbits
647 666 @sun = @plotWrapper.append("svg:image")
648 667 .attr('xlink:href', @options.sun.img)
649 668 .attr('width', '32px').attr('height', '32px')
650   - @sun.append('svg:title').text("Sol")
  669 + @sun.append('svg:title').text("Sun")
651 670  
652 671 $(@svg.node()).hide(); # we'll show it later when there'll be data
653 672 @resize()
... ... @@ -668,6 +687,7 @@ export class Orbits
668 687 orbiter = @plotWrapper.append("svg:image")
669 688 .attr('xlink:href', config['img'])
670 689 .attr('width', '32px').attr('height', '32px')
  690 + orbiter.append('svg:title').text(config.name)
671 691  
672 692 orbit_line = d3.line()
673 693 .x((d) ~> @xScale(d.x))
... ...
web/view/home.html.jinja2
... ... @@ -325,19 +325,19 @@
325 325 cursor: not-allowed;
326 326 }
327 327 .targets-filters .target.loading {
328   - -webkit-animation-name: spin;
  328 + -webkit-animation-name: keyframes_rotate;
329 329 -webkit-animation-duration: 4000ms;
330 330 -webkit-animation-iteration-count: infinite;
331 331 -webkit-animation-timing-function: linear;
332   - -moz-animation-name: spin;
  332 + -moz-animation-name: keyframes_rotate;
333 333 -moz-animation-duration: 4000ms;
334 334 -moz-animation-iteration-count: infinite;
335 335 -moz-animation-timing-function: linear;
336   - -ms-animation-name: spin;
  336 + -ms-animation-name: keyframes_rotate;
337 337 -ms-animation-duration: 4000ms;
338 338 -ms-animation-iteration-count: infinite;
339 339 -ms-animation-timing-function: linear;
340   - animation-name: spin;
  340 + animation-name: keyframes_rotate;
341 341 animation-duration: 4000ms;
342 342 animation-iteration-count: infinite;
343 343 animation-timing-function: linear;
... ...
web/view/layout.html.jinja2
... ... @@ -42,7 +42,7 @@
42 42 <!-- Navigation. We hide it in small screens. -->
43 43 <nav class="mdl-navigation mdl-layout--large-screen-only">
44 44 <a class="mdl-navigation__link" href="https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE">v{{ version }}</a>
45   - <a class="mdl-navigation__link" href="#">Model</a>
  45 + <a class="mdl-navigation__link" href="https://onlinelibrary.wiley.com/doi/10.1029/2004JA010959/abstract">Model</a>
46 46 <a class="mdl-navigation__link" href="https://ec.europa.eu/programmes/horizon2020/">Horizon 2020</a>
47 47 </nav>
48 48 </div>
... ...