Commit 1324cc91515ffac764b9fb895a96639c6cdb4ed2
1 parent
ea6c8d5d
Exists in
master
and in
2 other branches
Make the footer images clickable
Highlight the visits counter Use a default interval up to 3 weeks in the future
Showing
7 changed files
with
62 additions
and
29 deletions
Show diff stats
CHANGELOG.md
@@ -10,9 +10,7 @@ | @@ -10,9 +10,7 @@ | ||
10 | - [ ] Give the future data another color | 10 | - [ ] Give the future data another color |
11 | - [ ] Sort times series by closeness to the sun | 11 | - [ ] Sort times series by closeness to the sun |
12 | - [ ] Generate a CDF file (not NetCDF) | 12 | - [ ] Generate a CDF file (not NetCDF) |
13 | -- [ ] Make the footer images clickable | ||
14 | - [ ] Move the link to the source in the footer | 13 | - [ ] Move the link to the source in the footer |
15 | -- [ ] Highlight the visits counter | ||
16 | 14 | ||
17 | An heliospheric propagation 1D MHD model for solar wind prediction at planets, probes and comets. | 15 | An heliospheric propagation 1D MHD model for solar wind prediction at planets, probes and comets. |
18 | 16 | ||
@@ -20,6 +18,9 @@ An heliospheric propagation 1D MHD model for solar wind prediction at planets, p | @@ -20,6 +18,9 @@ An heliospheric propagation 1D MHD model for solar wind prediction at planets, p | ||
20 | 18 | ||
21 | ## 1.0.0-rc4 | 19 | ## 1.0.0-rc4 |
22 | 20 | ||
21 | +- [x] Make the footer images clickable | ||
22 | +- [x] Highlight the visits counter | ||
23 | +- [x] Use a default interval up to 3 weeks in the future | ||
23 | - [x] Add interval constraints for orbit models (Rosetta uses P67 after a time) | 24 | - [x] Add interval constraints for orbit models (Rosetta uses P67 after a time) |
24 | - [x] Make the download with a netcdf file instead of a tarball of CSVs | 25 | - [x] Make the download with a netcdf file instead of a tarball of CSVs |
25 | - [x] Support having no position to display (for Rosetta in some intervals) | 26 | - [x] Support having no position to display (for Rosetta in some intervals) |
config.yml
@@ -166,10 +166,13 @@ targets: | @@ -166,10 +166,13 @@ targets: | ||
166 | - type: 'probe' | 166 | - type: 'probe' |
167 | slug: 'juno' | 167 | slug: 'juno' |
168 | name: 'Juno' | 168 | name: 'Juno' |
169 | - title: 'Juno (coming soon)' | 169 | + title: 'Juno' |
170 | orbit: | 170 | orbit: |
171 | models: | 171 | models: |
172 | - slug: 'juno_cruise_all' | 172 | - slug: 'juno_cruise_all' |
173 | + stopped_at: '2016-07-01T00:00:00' | ||
174 | + - slug: 'jupiter_orb_all' | ||
175 | + started_at: '2016-07-01T00:00:00' | ||
173 | models: | 176 | models: |
174 | - slug: 'tao_juno_sw' | 177 | - slug: 'tao_juno_sw' |
175 | locked: false | 178 | locked: false |
web/run.py
@@ -46,10 +46,12 @@ FILE_DATE_FMT = "%Y-%m-%dT%H:%M:%S" | @@ -46,10 +46,12 @@ FILE_DATE_FMT = "%Y-%m-%dT%H:%M:%S" | ||
46 | 46 | ||
47 | # LOGGING ##################################################################### | 47 | # LOGGING ##################################################################### |
48 | 48 | ||
49 | +LOG_FILE = get_path('run.log') | ||
50 | + | ||
49 | log = logging.getLogger("HelioPropa") | 51 | log = logging.getLogger("HelioPropa") |
50 | log.setLevel(logging.DEBUG) | 52 | log.setLevel(logging.DEBUG) |
51 | # log.setLevel(logging.ERROR) # <-- set log level here ! | 53 | # log.setLevel(logging.ERROR) # <-- set log level here ! |
52 | -logHandler = logging.FileHandler(get_path('run.log')) | 54 | +logHandler = logging.FileHandler(LOG_FILE) |
53 | logHandler.setFormatter(logging.Formatter( | 55 | logHandler.setFormatter(logging.Formatter( |
54 | "%(asctime)s - %(levelname)s - %(message)s" | 56 | "%(asctime)s - %(levelname)s - %(message)s" |
55 | )) | 57 | )) |
@@ -265,6 +267,19 @@ def is_list_in_list(needle, haystack): | @@ -265,6 +267,19 @@ def is_list_in_list(needle, haystack): | ||
265 | return True | 267 | return True |
266 | 268 | ||
267 | 269 | ||
270 | +def round_time(dt=None, round_to=60): | ||
271 | + """ | ||
272 | + Round a datetime object to any time laps in seconds | ||
273 | + dt : datetime.datetime object, default now. | ||
274 | + roundTo : Closest number of seconds to round to, default 1 minute. | ||
275 | + """ | ||
276 | + if dt is None: | ||
277 | + dt = datetime.datetime.now() | ||
278 | + seconds = (dt.replace(tzinfo=None) - dt.min).seconds | ||
279 | + rounding = (seconds + round_to / 2) // round_to * round_to | ||
280 | + return dt + datetime.timedelta(0, rounding-seconds, -dt.microsecond) | ||
281 | + | ||
282 | + | ||
268 | def datetime_from_list(time_list): | 283 | def datetime_from_list(time_list): |
269 | """ | 284 | """ |
270 | Datetimes in retrieved CDFs are stored as lists of numbers, | 285 | Datetimes in retrieved CDFs are stored as lists of numbers, |
@@ -465,9 +480,13 @@ def get_data_for_target(target_config, started_at, stopped_at): | @@ -465,9 +480,13 @@ def get_data_for_target(target_config, started_at, stopped_at): | ||
465 | log.debug("%s: aggregating data from '%s'..." % | 480 | log.debug("%s: aggregating data from '%s'..." % |
466 | (target_config['name'], orbit_file)) | 481 | (target_config['name'], orbit_file)) |
467 | for time, datum_hee in zip(times, data_hee): | 482 | for time, datum_hee in zip(times, data_hee): |
468 | - dtime = datetime_from_list(time) | 483 | + try: |
484 | + dtime = datetime_from_list(time) | ||
485 | + except Exception as e: | ||
486 | + log.error("Failed to parse time from %s." % time) | ||
487 | + raise e | ||
469 | if s0 <= dtime <= s1: | 488 | if s0 <= dtime <= s1: |
470 | - dkey = dtime.strftime(precision) | 489 | + dkey = round_time(dtime, 60*60).strftime(precision) |
471 | orbit_data[dkey] = datum_hee | 490 | orbit_data[dkey] = datum_hee |
472 | cdf_handle.close() | 491 | cdf_handle.close() |
473 | 492 | ||
@@ -490,9 +509,13 @@ def get_data_for_target(target_config, started_at, stopped_at): | @@ -490,9 +509,13 @@ def get_data_for_target(target_config, started_at, stopped_at): | ||
490 | in zip(times, data_v, data_b, data_t, data_n, data_p, data_d): | 509 | in zip(times, data_v, data_b, data_t, data_n, data_p, data_d): |
491 | vrad = datum_v[0] | 510 | vrad = datum_v[0] |
492 | vtan = datum_v[1] | 511 | vtan = datum_v[1] |
493 | - dtime = datetime_from_list(time) | 512 | + try: |
513 | + dtime = datetime_from_list(time) | ||
514 | + except Exception as e: | ||
515 | + log.error("Failed to parse time from %s." % time) | ||
516 | + raise e | ||
494 | if started_at <= dtime <= stopped_at: | 517 | if started_at <= dtime <= stopped_at: |
495 | - dkey = dtime.strftime(precision) | 518 | + dkey = round_time(dtime, 60*60).strftime(precision) |
496 | x_hee = None | 519 | x_hee = None |
497 | y_hee = None | 520 | y_hee = None |
498 | if dkey in orbit_data: | 521 | if dkey in orbit_data: |
@@ -913,13 +936,20 @@ def cache_warmup(): | @@ -913,13 +936,20 @@ def cache_warmup(): | ||
913 | return "To Do" | 936 | return "To Do" |
914 | 937 | ||
915 | 938 | ||
916 | -@app.route("/run.log") | ||
917 | -def run_log(): | ||
918 | - with open(get_path('run.log'), 'r') as f: | 939 | +@app.route("/log") |
940 | +def log_show(): | ||
941 | + with open(LOG_FILE, 'r') as f: | ||
919 | contents = f.read() | 942 | contents = f.read() |
920 | return contents | 943 | return contents |
921 | 944 | ||
922 | 945 | ||
946 | +@app.route("/log/clear") | ||
947 | +def log_clear(): | ||
948 | + with open(LOG_FILE, 'w') as f: | ||
949 | + f.truncate() | ||
950 | + return "Log cleared successfully." | ||
951 | + | ||
952 | + | ||
923 | # DEV TOOLS ################################################################### | 953 | # DEV TOOLS ################################################################### |
924 | 954 | ||
925 | # @app.route("/inspect") | 955 | # @app.route("/inspect") |
@@ -951,6 +981,11 @@ def run_log(): | @@ -951,6 +981,11 @@ def run_log(): | ||
951 | # MAIN ######################################################################## | 981 | # MAIN ######################################################################## |
952 | 982 | ||
953 | if __name__ == "__main__": | 983 | if __name__ == "__main__": |
984 | + | ||
985 | + a = "2015171150000001" | ||
986 | + | ||
987 | + | ||
988 | + | ||
954 | # Debug mode on, as the production server does not use this but run.wsgi | 989 | # Debug mode on, as the production server does not use this but run.wsgi |
955 | extra_files = [get_path('../config.yml')] | 990 | extra_files = [get_path('../config.yml')] |
956 | app.run(debug=True, extra_files=extra_files) | 991 | app.run(debug=True, extra_files=extra_files) |
web/static/js/swapp.js
@@ -43,7 +43,7 @@ | @@ -43,7 +43,7 @@ | ||
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)"; | 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 | var started_at, stopped_at, this$ = this; | 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(1, 'year').hours(0).minutes(0).seconds(0); |
46 | - stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0); | 46 | + stopped_at = moment().add(3, 'week').hours(0).minutes(0).seconds(0); |
47 | this.setStartAndStop(started_at, stopped_at); | 47 | this.setStartAndStop(started_at, stopped_at); |
48 | this.loadAndCreatePlots(started_at, stopped_at); | 48 | this.loadAndCreatePlots(started_at, stopped_at); |
49 | return window.addEventListener('resize', function(){ | 49 | return window.addEventListener('resize', function(){ |
web/static/js/swapp.ls
@@ -75,7 +75,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | @@ -75,7 +75,7 @@ https://gitlab.irap.omp.eu/CDPP/SPACEWEATHERONLINE | ||
75 | # Default time interval is from two weeks ago to one week ahead. | 75 | # Default time interval is from two weeks ago to one week ahead. |
76 | # We set the h/m/s to zero to benefit from a daily cache. | 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(1, 'year').hours(0).minutes(0).seconds(0) |
78 | - stopped_at = moment().add(1, 'week').hours(0).minutes(0).seconds(0) | 78 | + stopped_at = moment().add(3, 'week').hours(0).minutes(0).seconds(0) |
79 | @setStartAndStop(started_at, stopped_at) | 79 | @setStartAndStop(started_at, stopped_at) |
80 | @loadAndCreatePlots(started_at, stopped_at) | 80 | @loadAndCreatePlots(started_at, stopped_at) |
81 | 81 |
web/view/home.html.jinja2
@@ -298,7 +298,7 @@ | @@ -298,7 +298,7 @@ | ||
298 | path.orbit.orbit_section { | 298 | path.orbit.orbit_section { |
299 | fill: none; | 299 | fill: none; |
300 | stroke: steelblue; | 300 | stroke: steelblue; |
301 | - stroke-width: 3px; | 301 | + stroke-width: 1.5px; |
302 | } | 302 | } |
303 | ellipse.orbit.orbit_ellipse { | 303 | ellipse.orbit.orbit_ellipse { |
304 | fill: none; | 304 | fill: none; |
web/view/layout.html.jinja2
@@ -70,36 +70,30 @@ | @@ -70,36 +70,30 @@ | ||
70 | 70 | ||
71 | <footer class="mdl-mini-footer"> | 71 | <footer class="mdl-mini-footer"> |
72 | <div class="mdl-mini-footer__left-section"> | 72 | <div class="mdl-mini-footer__left-section"> |
73 | + <p style="float: left; margin: 1.5em;"> | ||
74 | + {{ visits }} visits since 2017 | ||
75 | + </p> | ||
73 | <p class="disclaimer"> | 76 | <p class="disclaimer"> |
74 | The <a href="http://www.europlanet-2020-ri.eu/">Europlanet 2020 Research Infrastructure</a> project has received funding | 77 | The <a href="http://www.europlanet-2020-ri.eu/">Europlanet 2020 Research Infrastructure</a> project has received funding |
75 | <br> | 78 | <br> |
76 | from the <a href="https://ec.europa.eu/programmes/horizon2020/">European Union's Horizon 2020</a> research and innovation programme | 79 | from the <a href="https://ec.europa.eu/programmes/horizon2020/">European Union's Horizon 2020</a> research and innovation programme |
77 | under grant agreement N° 654208. | 80 | under grant agreement N° 654208. |
78 | <br> | 81 | <br> |
79 | - {{ visits }} visits since 2017 | ||
80 | </p> | 82 | </p> |
81 | </div> | 83 | </div> |
82 | <div class="mdl-mini-footer__right-section"> | 84 | <div class="mdl-mini-footer__right-section"> |
83 | - <img class="logo" src="{{ static('img/logo/logo_cdpp.png') }}" alt="CDPP" id="logo_cdpp" /> | 85 | + <a href="http://cdpp.irap.omp.eu"> |
86 | + <img class="logo" src="{{ static('img/logo/logo_cdpp.png') }}" alt="CDPP" id="logo_cdpp" /> | ||
87 | + </a> | ||
84 | | 88 | |
85 | - <img class="logo" src="{{ static('img/logo/logo_europlanet.png') }}" alt="Europlanet" id="logo_europlanet" /> | 89 | + <a href="http://planetaryspaceweather-europlanet.irap.omp.eu/"> |
90 | + <img class="logo" src="{{ static('img/logo/logo_europlanet.png') }}" alt="Europlanet" id="logo_europlanet" /> | ||
91 | + </a> | ||
86 | </div> | 92 | </div> |
87 | </footer> | 93 | </footer> |
88 | 94 | ||
89 | </div> | 95 | </div> |
90 | 96 | ||
91 | -{# <script type="application/javascript">#} | ||
92 | -{# // fixme: GOOGLE ANALYTICS ?#} | ||
93 | -{# /*#} | ||
94 | -{# (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){#} | ||
95 | -{# (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),#} | ||
96 | -{# m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)#} | ||
97 | -{# })(window,document,'script','//www.google-analytics.com/analytics.js','ga');#} | ||
98 | -{# ga('create', 'UA-56037907-1', 'auto');#} | ||
99 | -{# ga('send', 'pageview');#} | ||
100 | -{# */#} | ||
101 | -{# </script>#} | ||
102 | - | ||
103 | <script type="application/javascript" src="{{ static('js/vendor/jquery-3.2.1.min.js') }}"></script> | 97 | <script type="application/javascript" src="{{ static('js/vendor/jquery-3.2.1.min.js') }}"></script> |
104 | <script type="application/javascript" src="{{ static('js/vendor/material-custom.js') }}"></script> | 98 | <script type="application/javascript" src="{{ static('js/vendor/material-custom.js') }}"></script> |
105 | <script type="application/javascript"> | 99 | <script type="application/javascript"> |