Commit 1185f3539dbfab249ec9cc9e2d4a7adef0545e56
1 parent
03452084
Exists in
master
and in
2 other branches
Fix the CME Catalogs and continue THE GREAT REFACTO
Showing
4 changed files
with
60 additions
and
26 deletions
Show diff stats
CHANGELOG.md
@@ -29,7 +29,6 @@ et prendre aussi | @@ -29,7 +29,6 @@ et prendre aussi | ||
29 | 29 | ||
30 | ## Future ? | 30 | ## Future ? |
31 | 31 | ||
32 | -- [ ] Re-enable Earth | ||
33 | - [ ] Enable p67 | 32 | - [ ] Enable p67 |
34 | - [ ] Layer : Auroral Emissions | 33 | - [ ] Layer : Auroral Emissions |
35 | - [ ] Set the log level to _error_ in production (see `web/run.py`) | 34 | - [ ] Set the log level to _error_ in production (see `web/run.py`) |
@@ -39,6 +38,12 @@ et prendre aussi | @@ -39,6 +38,12 @@ et prendre aussi | ||
39 | - [ ] IE compat, if you can (I can't) | 38 | - [ ] IE compat, if you can (I can't) |
40 | 39 | ||
41 | 40 | ||
41 | +## 1.6 | ||
42 | + | ||
43 | +- [x] Re-enable Earth | ||
44 | +- [x] Layer : CME Catalogs | ||
45 | + | ||
46 | + | ||
42 | ## 1.5 | 47 | ## 1.5 |
43 | 48 | ||
44 | - [x] Use the new AMDA API | 49 | - [x] Use the new AMDA API |
config.yml
@@ -69,6 +69,7 @@ layers: | @@ -69,6 +69,7 @@ layers: | ||
69 | file: "ICME_WP4_V10.json" | 69 | file: "ICME_WP4_V10.json" |
70 | start: "ICME_START_TIME" | 70 | start: "ICME_START_TIME" |
71 | stop: "MO_END_TIME" | 71 | stop: "MO_END_TIME" |
72 | + format: "%Y-%m-%dT%H:%MZ" | ||
72 | l1: | 73 | l1: |
73 | venus: | 74 | venus: |
74 | constraints: [ { SC_INSITU: ["VEX"] } ] | 75 | constraints: [ { SC_INSITU: ["VEX"] } ] |
@@ -78,6 +79,7 @@ layers: | @@ -78,6 +79,7 @@ layers: | ||
78 | url: "https://www.helcats-fp7.eu/catalogues/data/HCME_WP4_V6.json" | 79 | url: "https://www.helcats-fp7.eu/catalogues/data/HCME_WP4_V6.json" |
79 | file: "HCME_WP4_V6.json" | 80 | file: "HCME_WP4_V6.json" |
80 | start: "TARGET_ARRIVAL" | 81 | start: "TARGET_ARRIVAL" |
82 | + format: "%Y-%m-%dT%H:%MZ" | ||
81 | l1: | 83 | l1: |
82 | mars: | 84 | mars: |
83 | constraints: [ { TARGET_NAME: ["MARS", "MAVEN", "MSC"] } ] | 85 | constraints: [ { TARGET_NAME: ["MARS", "MAVEN", "MSC"] } ] |
@@ -85,6 +87,7 @@ layers: | @@ -85,6 +87,7 @@ layers: | ||
85 | url: "https://cdaw.gsfc.nasa.gov/CME_list/UNIVERSAL/text_ver/univ_all.txt" | 87 | url: "https://cdaw.gsfc.nasa.gov/CME_list/UNIVERSAL/text_ver/univ_all.txt" |
86 | file: "univ_all.json" | 88 | file: "univ_all.json" |
87 | start: "DATETIME" | 89 | start: "DATETIME" |
90 | + format: "%Y-%m-%dT%H:%M:%S" | ||
88 | l1: | 91 | l1: |
89 | earth: ~ | 92 | earth: ~ |
90 | 93 |
web/run.py
@@ -44,6 +44,7 @@ with open(get_path('../config.yml'), 'r') as config_file: | @@ -44,6 +44,7 @@ with open(get_path('../config.yml'), 'r') as config_file: | ||
44 | config = yaml_load(config_file.read()) | 44 | config = yaml_load(config_file.read()) |
45 | 45 | ||
46 | FILE_DATE_FMT = "%Y-%m-%dT%H:%M:%S" | 46 | FILE_DATE_FMT = "%Y-%m-%dT%H:%M:%S" |
47 | +MOMENT_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" | ||
47 | 48 | ||
48 | 49 | ||
49 | # LOGGING ##################################################################### | 50 | # LOGGING ##################################################################### |
@@ -802,7 +803,7 @@ def get_interval_from_query(): | @@ -802,7 +803,7 @@ def get_interval_from_query(): | ||
802 | return started_at, stopped_at | 803 | return started_at, stopped_at |
803 | 804 | ||
804 | 805 | ||
805 | -def get_catalog_layers(input_slug, target_slug): | 806 | +def get_catalog_layers(input_slug, target_slug, started_at, stopped_at): |
806 | """ | 807 | """ |
807 | In the JSON file we have "columns" and "data". | 808 | In the JSON file we have "columns" and "data". |
808 | Of course, each JSON file has its own columns, with different conventions. | 809 | Of course, each JSON file has its own columns, with different conventions. |
@@ -821,6 +822,15 @@ def get_catalog_layers(input_slug, target_slug): | @@ -821,6 +822,15 @@ def get_catalog_layers(input_slug, target_slug): | ||
821 | raise | 822 | raise |
822 | return index | 823 | return index |
823 | 824 | ||
825 | + try: | ||
826 | + started_at = datetime.datetime.strptime(started_at, FILE_DATE_FMT) | ||
827 | + except: | ||
828 | + abort(400, "Invalid started_at parameter : '%s'." % started_at) | ||
829 | + try: | ||
830 | + stopped_at = datetime.datetime.strptime(stopped_at, FILE_DATE_FMT) | ||
831 | + except: | ||
832 | + abort(400, "Invalid stopped_at parameter : '%s'." % stopped_at) | ||
833 | + | ||
824 | catalog_layers = {} | 834 | catalog_layers = {} |
825 | for config_layer in config['layers']: | 835 | for config_layer in config['layers']: |
826 | if 'data' not in config_layer: | 836 | if 'data' not in config_layer: |
@@ -836,11 +846,15 @@ def get_catalog_layers(input_slug, target_slug): | @@ -836,11 +846,15 @@ def get_catalog_layers(input_slug, target_slug): | ||
836 | constraints = [] | 846 | constraints = [] |
837 | else: | 847 | else: |
838 | constraints = cl_datum[input_slug][target_slug]['constraints'] | 848 | constraints = cl_datum[input_slug][target_slug]['constraints'] |
849 | + | ||
839 | with open(get_path("../data/catalog/%s" % cl_datum['file'])) as f: | 850 | with open(get_path("../data/catalog/%s" % cl_datum['file'])) as f: |
840 | json_data = json.load(f) | 851 | json_data = json.load(f) |
841 | if 'start' not in cl_datum: | 852 | if 'start' not in cl_datum: |
842 | log.error("Invalid configuration: 'start' is missing.") | 853 | log.error("Invalid configuration: 'start' is missing.") |
843 | continue # skip this | 854 | continue # skip this |
855 | + if 'format' not in cl_datum: | ||
856 | + log.error("Invalid configuration: 'format' is missing.") | ||
857 | + continue # skip this | ||
844 | start_index = _get_index_of_key(json_data, cl_datum['start']) | 858 | start_index = _get_index_of_key(json_data, cl_datum['start']) |
845 | if 'stop' not in cl_datum: | 859 | if 'stop' not in cl_datum: |
846 | stop_index = start_index | 860 | stop_index = start_index |
@@ -867,9 +881,20 @@ def get_catalog_layers(input_slug, target_slug): | @@ -867,9 +881,20 @@ def get_catalog_layers(input_slug, target_slug): | ||
867 | continue | 881 | continue |
868 | start_time = json_datum[start_index] | 882 | start_time = json_datum[start_index] |
869 | stop_time = json_datum[stop_index] | 883 | stop_time = json_datum[stop_index] |
884 | + | ||
885 | + start_time = datetime.datetime.strptime( | ||
886 | + start_time, cl_datum['format'] | ||
887 | + ) | ||
888 | + stop_time = datetime.datetime.strptime( | ||
889 | + stop_time, cl_datum['format'] | ||
890 | + ) | ||
891 | + | ||
892 | + if start_time < started_at: | ||
893 | + continue | ||
894 | + | ||
870 | catalog_layers[config_layer['slug']].append({ | 895 | catalog_layers[config_layer['slug']].append({ |
871 | - 'start': start_time, | ||
872 | - 'stop': stop_time, | 896 | + 'start': start_time.strftime(MOMENT_DATE_FMT), |
897 | + 'stop': stop_time.strftime(MOMENT_DATE_FMT), | ||
873 | }) | 898 | }) |
874 | 899 | ||
875 | return catalog_layers | 900 | return catalog_layers |
@@ -940,7 +965,7 @@ def home(): | @@ -940,7 +965,7 @@ def home(): | ||
940 | started_at, stopped_at = get_interval_from_query() | 965 | started_at, stopped_at = get_interval_from_query() |
941 | for i, target in enumerate(targets): | 966 | for i, target in enumerate(targets): |
942 | targets[i]['catalog_layers'] = get_catalog_layers( | 967 | targets[i]['catalog_layers'] = get_catalog_layers( |
943 | - input_slug, target['slug'] | 968 | + input_slug, target['slug'], started_at, stopped_at |
944 | ) | 969 | ) |
945 | return render_view('home.html.jinja2', { | 970 | return render_view('home.html.jinja2', { |
946 | # 'targets': config['targets'], | 971 | # 'targets': config['targets'], |
web/static/js/main.js
@@ -71,12 +71,12 @@ | @@ -71,12 +71,12 @@ | ||
71 | 71 | ||
72 | init(started_at, stopped_at) { | 72 | init(started_at, stopped_at) { |
73 | // "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)"; | 73 | // "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)"; |
74 | - const this$ = this; | 74 | + const app = this; |
75 | started_at = moment(started_at).hours(0).minutes(0).seconds(0); | 75 | started_at = moment(started_at).hours(0).minutes(0).seconds(0); |
76 | stopped_at = moment(stopped_at).hours(0).minutes(0).seconds(0); | 76 | stopped_at = moment(stopped_at).hours(0).minutes(0).seconds(0); |
77 | this.setStartAndStop(started_at, stopped_at); | 77 | this.setStartAndStop(started_at, stopped_at); |
78 | this.loadAndCreatePlots(started_at, stopped_at); | 78 | this.loadAndCreatePlots(started_at, stopped_at); |
79 | - window.addEventListener('resize', () => this$.resize()); | 79 | + window.addEventListener('resize', () => app.resize()); |
80 | return this; | 80 | return this; |
81 | } | 81 | } |
82 | 82 | ||
@@ -219,9 +219,8 @@ | @@ -219,9 +219,8 @@ | ||
219 | } | 219 | } |
220 | 220 | ||
221 | resize() { | 221 | resize() { |
222 | - let ref$; | ||
223 | - if ((ref$ = this.orbits) != null) { | ||
224 | - ref$.resize(); | 222 | + if (null != this.orbits) { |
223 | + this.orbits.resize(); | ||
225 | } | 224 | } |
226 | this.time_series.forEach(ts => ts.resize()); | 225 | this.time_series.forEach(ts => ts.resize()); |
227 | return this; | 226 | return this; |
@@ -401,7 +400,7 @@ | @@ -401,7 +400,7 @@ | ||
401 | return true; | 400 | return true; |
402 | }).bind(ts); | 401 | }).bind(ts); |
403 | 402 | ||
404 | - return ts.options['onDblClick'] = () => { | 403 | + ts.options['onDblClick'] = () => { |
405 | let ref$; | 404 | let ref$; |
406 | app.resetZoom(); | 405 | app.resetZoom(); |
407 | if ((ref$ = $("#zoom_controls_help")) != null) { | 406 | if ((ref$ = $("#zoom_controls_help")) != null) { |
@@ -506,6 +505,7 @@ | @@ -506,6 +505,7 @@ | ||
506 | let starting_ts_key = tsv.indexOf(starting_ts); | 505 | let starting_ts_key = tsv.indexOf(starting_ts); |
507 | if (starting_ts_key === -1) starting_ts_key = 0; | 506 | if (starting_ts_key === -1) starting_ts_key = 0; |
508 | zoomedOnVisible = new Promise((resolve, reject) => { | 507 | zoomedOnVisible = new Promise((resolve, reject) => { |
508 | + console.log("Zoom on invisible time series…"); | ||
509 | let tsv_zoom_on_next; | 509 | let tsv_zoom_on_next; |
510 | tsv_zoom_on_next = i => { | 510 | tsv_zoom_on_next = i => { |
511 | let ts; | 511 | let ts; |
@@ -517,9 +517,10 @@ | @@ -517,9 +517,10 @@ | ||
517 | ts.zoomIn(started_at, stopped_at) | 517 | ts.zoomIn(started_at, stopped_at) |
518 | .then(() => tsv_zoom_on_next(i + 1)); | 518 | .then(() => tsv_zoom_on_next(i + 1)); |
519 | }; | 519 | }; |
520 | - return tsv_zoom_on_next(0); | 520 | + tsv_zoom_on_next(0); |
521 | }); | 521 | }); |
522 | zoomedOnVisible.then(() => { | 522 | zoomedOnVisible.then(() => { |
523 | + console.log("Now zoom on invisible time series…"); | ||
523 | this.time_series.forEach(ts => { | 524 | this.time_series.forEach(ts => { |
524 | if (!ts.visible) { | 525 | if (!ts.visible) { |
525 | ts.zoomIn(started_at, stopped_at); | 526 | ts.zoomIn(started_at, stopped_at); |
@@ -843,13 +844,12 @@ | @@ -843,13 +844,12 @@ | ||
843 | } | 844 | } |
844 | 845 | ||
845 | applyZoom() { | 846 | applyZoom() { |
846 | - let duration; | ||
847 | - let t; | 847 | + let duration = 0; |
848 | duration = 0; | 848 | duration = 0; |
849 | if (this.visible) { | 849 | if (this.visible) { |
850 | duration = 750; | 850 | duration = 750; |
851 | console.debug(`Applying zoom to visible ${this}…`); | 851 | console.debug(`Applying zoom to visible ${this}…`); |
852 | - t = this.svg.transition().duration(duration); | 852 | + let t = this.svg.transition().duration(duration); |
853 | this.svg.select('.x.axis').transition(t).call(this.xAxis); | 853 | this.svg.select('.x.axis').transition(t).call(this.xAxis); |
854 | this.svg.select('.y.axis').transition(t).call(this.yAxis); | 854 | this.svg.select('.y.axis').transition(t).call(this.yAxis); |
855 | this.path.transition(t).attr('d', this.line); | 855 | this.path.transition(t).attr('d', this.line); |
@@ -1095,7 +1095,7 @@ | @@ -1095,7 +1095,7 @@ | ||
1095 | return this.hideOrbiter(slug); | 1095 | return this.hideOrbiter(slug); |
1096 | } | 1096 | } |
1097 | 1097 | ||
1098 | - showOrbiter(slug) { | 1098 | + showOrbiter(slug, doResize=true) { |
1099 | if (!this.data[slug].length) { | 1099 | if (!this.data[slug].length) { |
1100 | return; | 1100 | return; |
1101 | } | 1101 | } |
@@ -1106,7 +1106,9 @@ | @@ -1106,7 +1106,9 @@ | ||
1106 | this.orbitersElements[slug].orbiter.style("display", null); | 1106 | this.orbitersElements[slug].orbiter.style("display", null); |
1107 | this.orbitersElements[slug].orbit_ellipse.style("display", null); | 1107 | this.orbitersElements[slug].orbit_ellipse.style("display", null); |
1108 | this.orbitersElements[slug].orbit_section.style("display", null); | 1108 | this.orbitersElements[slug].orbit_section.style("display", null); |
1109 | - return this.resize(true); | 1109 | + if (doResize) this.resize(true); |
1110 | + | ||
1111 | + return this; | ||
1110 | } | 1112 | } |
1111 | 1113 | ||
1112 | hideOrbiter(slug) { | 1114 | hideOrbiter(slug) { |
@@ -1136,7 +1138,7 @@ | @@ -1136,7 +1138,7 @@ | ||
1136 | extremum == null && (extremum = null); | 1138 | extremum == null && (extremum = null); |
1137 | const width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); | 1139 | const width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); |
1138 | const height = width; // it's a square | 1140 | const height = width; // it's a square |
1139 | - console.debug(`Resizing orbits : ${width} × ${height}…`); | 1141 | + console.debug(`Resizing orbits : ${width} × ${height}… (animated: ${animate})`); |
1140 | if (extremum === null) { | 1142 | if (extremum === null) { |
1141 | extremum = 1.1 * d3.max((function () { | 1143 | extremum = 1.1 * d3.max((function () { |
1142 | let ref$; | 1144 | let ref$; |
@@ -1272,25 +1274,24 @@ | @@ -1272,25 +1274,24 @@ | ||
1272 | } | 1274 | } |
1273 | 1275 | ||
1274 | resizeDomain(started_at, stopped_at) { | 1276 | resizeDomain(started_at, stopped_at) { |
1275 | - let slug; | ||
1276 | - let ref$; | ||
1277 | let config; | 1277 | let config; |
1278 | let el; | 1278 | let el; |
1279 | let data; | 1279 | let data; |
1280 | - const results$ = []; | ||
1281 | - for (slug in ref$ = this.orbiters) { | ||
1282 | - config = ref$[slug]; | 1280 | + for (let slug in this.orbiters) { |
1281 | + config = this.orbiters[slug]; | ||
1283 | el = this.orbitersElements[slug]; | 1282 | el = this.orbitersElements[slug]; |
1284 | data = this.data[slug].filter(onlyDataInRange); | 1283 | data = this.data[slug].filter(onlyDataInRange); |
1285 | - if (!data.length) { | 1284 | + if ( ! data.length) { |
1286 | this.hideOrbiter(slug); | 1285 | this.hideOrbiter(slug); |
1287 | continue; | 1286 | continue; |
1288 | } | 1287 | } |
1289 | el['orbit_section'].datum(data); | 1288 | el['orbit_section'].datum(data); |
1290 | el['orbit_section'].attr('d', el['orbit_line']); | 1289 | el['orbit_section'].attr('d', el['orbit_line']); |
1291 | - results$.push(this.showOrbiter(slug)); | 1290 | + this.showOrbiter(slug, false); |
1292 | } | 1291 | } |
1293 | - return results$; | 1292 | + this.resize(true); |
1293 | + | ||
1294 | + return this; | ||
1294 | 1295 | ||
1295 | function onlyDataInRange(d) { | 1296 | function onlyDataInRange(d) { |
1296 | return started_at <= d.t && d.t <= stopped_at; | 1297 | return started_at <= d.t && d.t <= stopped_at; |