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 | 29 | |
30 | 30 | ## Future ? |
31 | 31 | |
32 | -- [ ] Re-enable Earth | |
33 | 32 | - [ ] Enable p67 |
34 | 33 | - [ ] Layer : Auroral Emissions |
35 | 34 | - [ ] Set the log level to _error_ in production (see `web/run.py`) |
... | ... | @@ -39,6 +38,12 @@ et prendre aussi |
39 | 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 | 47 | ## 1.5 |
43 | 48 | |
44 | 49 | - [x] Use the new AMDA API | ... | ... |
config.yml
... | ... | @@ -69,6 +69,7 @@ layers: |
69 | 69 | file: "ICME_WP4_V10.json" |
70 | 70 | start: "ICME_START_TIME" |
71 | 71 | stop: "MO_END_TIME" |
72 | + format: "%Y-%m-%dT%H:%MZ" | |
72 | 73 | l1: |
73 | 74 | venus: |
74 | 75 | constraints: [ { SC_INSITU: ["VEX"] } ] |
... | ... | @@ -78,6 +79,7 @@ layers: |
78 | 79 | url: "https://www.helcats-fp7.eu/catalogues/data/HCME_WP4_V6.json" |
79 | 80 | file: "HCME_WP4_V6.json" |
80 | 81 | start: "TARGET_ARRIVAL" |
82 | + format: "%Y-%m-%dT%H:%MZ" | |
81 | 83 | l1: |
82 | 84 | mars: |
83 | 85 | constraints: [ { TARGET_NAME: ["MARS", "MAVEN", "MSC"] } ] |
... | ... | @@ -85,6 +87,7 @@ layers: |
85 | 87 | url: "https://cdaw.gsfc.nasa.gov/CME_list/UNIVERSAL/text_ver/univ_all.txt" |
86 | 88 | file: "univ_all.json" |
87 | 89 | start: "DATETIME" |
90 | + format: "%Y-%m-%dT%H:%M:%S" | |
88 | 91 | l1: |
89 | 92 | earth: ~ |
90 | 93 | ... | ... |
web/run.py
... | ... | @@ -44,6 +44,7 @@ with open(get_path('../config.yml'), 'r') as config_file: |
44 | 44 | config = yaml_load(config_file.read()) |
45 | 45 | |
46 | 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 | 50 | # LOGGING ##################################################################### |
... | ... | @@ -802,7 +803,7 @@ def get_interval_from_query(): |
802 | 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 | 808 | In the JSON file we have "columns" and "data". |
808 | 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 | 822 | raise |
822 | 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 | 834 | catalog_layers = {} |
825 | 835 | for config_layer in config['layers']: |
826 | 836 | if 'data' not in config_layer: |
... | ... | @@ -836,11 +846,15 @@ def get_catalog_layers(input_slug, target_slug): |
836 | 846 | constraints = [] |
837 | 847 | else: |
838 | 848 | constraints = cl_datum[input_slug][target_slug]['constraints'] |
849 | + | |
839 | 850 | with open(get_path("../data/catalog/%s" % cl_datum['file'])) as f: |
840 | 851 | json_data = json.load(f) |
841 | 852 | if 'start' not in cl_datum: |
842 | 853 | log.error("Invalid configuration: 'start' is missing.") |
843 | 854 | continue # skip this |
855 | + if 'format' not in cl_datum: | |
856 | + log.error("Invalid configuration: 'format' is missing.") | |
857 | + continue # skip this | |
844 | 858 | start_index = _get_index_of_key(json_data, cl_datum['start']) |
845 | 859 | if 'stop' not in cl_datum: |
846 | 860 | stop_index = start_index |
... | ... | @@ -867,9 +881,20 @@ def get_catalog_layers(input_slug, target_slug): |
867 | 881 | continue |
868 | 882 | start_time = json_datum[start_index] |
869 | 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 | 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 | 900 | return catalog_layers |
... | ... | @@ -940,7 +965,7 @@ def home(): |
940 | 965 | started_at, stopped_at = get_interval_from_query() |
941 | 966 | for i, target in enumerate(targets): |
942 | 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 | 970 | return render_view('home.html.jinja2', { |
946 | 971 | # 'targets': config['targets'], | ... | ... |
web/static/js/main.js
... | ... | @@ -71,12 +71,12 @@ |
71 | 71 | |
72 | 72 | init(started_at, stopped_at) { |
73 | 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 | 75 | started_at = moment(started_at).hours(0).minutes(0).seconds(0); |
76 | 76 | stopped_at = moment(stopped_at).hours(0).minutes(0).seconds(0); |
77 | 77 | this.setStartAndStop(started_at, stopped_at); |
78 | 78 | this.loadAndCreatePlots(started_at, stopped_at); |
79 | - window.addEventListener('resize', () => this$.resize()); | |
79 | + window.addEventListener('resize', () => app.resize()); | |
80 | 80 | return this; |
81 | 81 | } |
82 | 82 | |
... | ... | @@ -219,9 +219,8 @@ |
219 | 219 | } |
220 | 220 | |
221 | 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 | 225 | this.time_series.forEach(ts => ts.resize()); |
227 | 226 | return this; |
... | ... | @@ -401,7 +400,7 @@ |
401 | 400 | return true; |
402 | 401 | }).bind(ts); |
403 | 402 | |
404 | - return ts.options['onDblClick'] = () => { | |
403 | + ts.options['onDblClick'] = () => { | |
405 | 404 | let ref$; |
406 | 405 | app.resetZoom(); |
407 | 406 | if ((ref$ = $("#zoom_controls_help")) != null) { |
... | ... | @@ -506,6 +505,7 @@ |
506 | 505 | let starting_ts_key = tsv.indexOf(starting_ts); |
507 | 506 | if (starting_ts_key === -1) starting_ts_key = 0; |
508 | 507 | zoomedOnVisible = new Promise((resolve, reject) => { |
508 | + console.log("Zoom on invisible time series…"); | |
509 | 509 | let tsv_zoom_on_next; |
510 | 510 | tsv_zoom_on_next = i => { |
511 | 511 | let ts; |
... | ... | @@ -517,9 +517,10 @@ |
517 | 517 | ts.zoomIn(started_at, stopped_at) |
518 | 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 | 522 | zoomedOnVisible.then(() => { |
523 | + console.log("Now zoom on invisible time series…"); | |
523 | 524 | this.time_series.forEach(ts => { |
524 | 525 | if (!ts.visible) { |
525 | 526 | ts.zoomIn(started_at, stopped_at); |
... | ... | @@ -843,13 +844,12 @@ |
843 | 844 | } |
844 | 845 | |
845 | 846 | applyZoom() { |
846 | - let duration; | |
847 | - let t; | |
847 | + let duration = 0; | |
848 | 848 | duration = 0; |
849 | 849 | if (this.visible) { |
850 | 850 | duration = 750; |
851 | 851 | console.debug(`Applying zoom to visible ${this}…`); |
852 | - t = this.svg.transition().duration(duration); | |
852 | + let t = this.svg.transition().duration(duration); | |
853 | 853 | this.svg.select('.x.axis').transition(t).call(this.xAxis); |
854 | 854 | this.svg.select('.y.axis').transition(t).call(this.yAxis); |
855 | 855 | this.path.transition(t).attr('d', this.line); |
... | ... | @@ -1095,7 +1095,7 @@ |
1095 | 1095 | return this.hideOrbiter(slug); |
1096 | 1096 | } |
1097 | 1097 | |
1098 | - showOrbiter(slug) { | |
1098 | + showOrbiter(slug, doResize=true) { | |
1099 | 1099 | if (!this.data[slug].length) { |
1100 | 1100 | return; |
1101 | 1101 | } |
... | ... | @@ -1106,7 +1106,9 @@ |
1106 | 1106 | this.orbitersElements[slug].orbiter.style("display", null); |
1107 | 1107 | this.orbitersElements[slug].orbit_ellipse.style("display", null); |
1108 | 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 | 1114 | hideOrbiter(slug) { |
... | ... | @@ -1136,7 +1138,7 @@ |
1136 | 1138 | extremum == null && (extremum = null); |
1137 | 1139 | const width = Math.ceil($(this.container).width() - this.margin.left - this.margin.right); |
1138 | 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 | 1142 | if (extremum === null) { |
1141 | 1143 | extremum = 1.1 * d3.max((function () { |
1142 | 1144 | let ref$; |
... | ... | @@ -1272,25 +1274,24 @@ |
1272 | 1274 | } |
1273 | 1275 | |
1274 | 1276 | resizeDomain(started_at, stopped_at) { |
1275 | - let slug; | |
1276 | - let ref$; | |
1277 | 1277 | let config; |
1278 | 1278 | let el; |
1279 | 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 | 1282 | el = this.orbitersElements[slug]; |
1284 | 1283 | data = this.data[slug].filter(onlyDataInRange); |
1285 | - if (!data.length) { | |
1284 | + if ( ! data.length) { | |
1286 | 1285 | this.hideOrbiter(slug); |
1287 | 1286 | continue; |
1288 | 1287 | } |
1289 | 1288 | el['orbit_section'].datum(data); |
1290 | 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 | 1296 | function onlyDataInRange(d) { |
1296 | 1297 | return started_at <= d.t && d.t <= stopped_at; | ... | ... |