Commit 1185f3539dbfab249ec9cc9e2d4a7adef0545e56

Authored by Goutte
1 parent 03452084

Fix the CME Catalogs and continue THE GREAT REFACTO

@@ -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
@@ -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
@@ -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;