Commit 8644387c4775291d14c8a1f2f8f5467e21614ea5
1 parent
c15a50cb
Exists in
master
and in
3 other branches
Use real data.
Showing
4 changed files
with
208 additions
and
90 deletions
Show diff stats
CHANGELOG.md
1 | +- Start/Stop datetime fields | |
2 | +- Play button to start time dimension | |
3 | +- Download raw data for time interval | |
4 | +- Same via SAMP | |
5 | + | |
6 | +- Planets | |
7 | +- Probes | |
8 | + - Rosetta | |
9 | + - Juno | |
10 | +- Comets (the one visited by rosetta) | |
11 | + | |
1 | 12 | ## 0.0.0 |
2 | 13 | |
3 | 14 | - Initial website skeleton |
4 | -- Initial data bridge between netCDF and CSV | |
5 | 15 | \ No newline at end of file |
16 | +- Initial data bridge between netCDF and CSV | |
17 | +- New parameters | |
18 | + - Temperature `T` (K) | |
19 | + - Density `N` (cm^-3) | |
20 | + - Angle Planet-Sun-Earth `Delta_angle` (degrees) | |
21 | + - Magnetism => B Tangential | |
22 | +- Orbits axes titles | |
23 | +- Logo Europlanet | ... | ... |
config.yml
... | ... | @@ -35,6 +35,27 @@ authors: |
35 | 35 | role: Project Coordinator |
36 | 36 | mail: vincent.genot@irap.omp.eu |
37 | 37 | |
38 | + | |
39 | +amda: "http://cdpp.irap.omp.eu/BASE/DDService/getDataUrl.php?dataSet={dataSet}&StartTime={startTime}&StopTime={stopTime}" | |
40 | + | |
41 | +#Targets | |
42 | +#Earth earth_orb_all | |
43 | +#Jupiter jupiter_orb_all | |
44 | +#Mars mars_orb_all | |
45 | +#Mercury mercury_orb_all | |
46 | +#Neptune neptune_orb_all | |
47 | +#Venus venus_orb_all | |
48 | +#Uranus uranus_orb_all | |
49 | +# | |
50 | +#Comets | |
51 | +#67P p67_orb_all | |
52 | +# | |
53 | +#Probes | |
54 | +#Maven maven_orb_cruise | |
55 | +#Juno juno_cruise_all | |
56 | +#Exomars exomars_cruise_all | |
57 | +#Rosetta ros_orb_cruise | |
58 | + | |
38 | 59 | # `slug` used internally, and should match [a-z0-9]+ |
39 | 60 | # `name` is displayed |
40 | 61 | # `title` appears on mouse hover |
... | ... | @@ -45,54 +66,94 @@ sources: |
45 | 66 | slug: 'mercury' |
46 | 67 | name: 'Mercury' |
47 | 68 | title: 'Mercury (coming soon)' |
69 | + orbit: 'mercury_orb_all' | |
70 | + models: | |
71 | + - slug: 'tao_mercury_sw' | |
72 | + started_at: "1990-01-01T01:30:00" | |
73 | + stopped_at: "2017-02-19T00:00:00" | |
48 | 74 | locked: true |
49 | 75 | default: true |
50 | 76 | - type: 'planet' |
51 | 77 | slug: 'venus' |
52 | 78 | name: 'Venus' |
53 | 79 | title: 'Venus (coming soon)' |
80 | + orbit: 'venus_orb_all' | |
81 | + models: | |
82 | + - slug: 'tao_venus_sw' | |
83 | + started_at: "1990-01-01T01:30:00" | |
84 | + stopped_at: "2017-02-19T00:00:00" | |
54 | 85 | locked: true |
55 | 86 | default: true |
56 | 87 | - type: 'planet' |
57 | 88 | slug: 'earth' |
58 | 89 | name: 'Earth' |
59 | 90 | title: 'Earth (coming soon)' |
91 | + orbit: 'earth_orb_all' | |
92 | + #model: 'tao_earth_sw' | |
60 | 93 | locked: true |
61 | 94 | default: true |
62 | 95 | - type: 'planet' |
63 | 96 | slug: 'mars' |
64 | 97 | name: 'Mars' |
65 | 98 | title: 'Mars (coming soon)' |
99 | + orbit: 'mars_orb_all' | |
100 | + models: | |
101 | + - slug: 'tao_mars_sw' | |
102 | + started_at: "1990-01-01T01:30:00" | |
103 | + stopped_at: "2017-02-19T00:00:00" | |
66 | 104 | locked: true |
67 | 105 | default: true |
68 | 106 | - type: 'planet' |
69 | 107 | slug: 'jupiter' |
70 | 108 | name: 'Jupiter' |
71 | 109 | title: 'Jupiter' |
110 | + orbit: 'jupiter_orb_all' | |
111 | + models: | |
112 | + - slug: 'tao_jup_sw' | |
113 | + started_at: "1990-01-01T01:30:00" | |
114 | + stopped_at: "2017-02-19T00:00:00" | |
115 | + started_at: "1990-01-01T01:30:00" | |
116 | + stopped_at: "2017-02-19T00:00:00" | |
72 | 117 | locked: false |
73 | 118 | default: true |
74 | 119 | - type: 'planet' |
75 | 120 | slug: 'saturn' |
76 | 121 | name: 'Saturn' |
77 | 122 | title: 'Saturn (coming soon)' |
123 | + orbit: 'saturn_orb_all' | |
124 | + models: | |
125 | + - slug: 'tao_sat_sw' | |
126 | + started_at: "1990-01-01T01:30:00" | |
127 | + stopped_at: "2017-02-19T00:00:00" | |
78 | 128 | locked: true |
79 | 129 | default: true |
80 | 130 | - type: 'probe' |
81 | 131 | slug: 'rosetta' |
82 | 132 | name: 'Rosetta' |
83 | 133 | title: 'Rosetta (coming soon)' |
134 | + orbit: 'ros_orb_cruise' | |
135 | + models: | |
136 | + - slug: 'tao_ros_sw' | |
137 | + started_at: "1990-01-01T01:30:00" | |
138 | + stopped_at: "2017-02-19T00:00:00" | |
84 | 139 | locked: true |
85 | 140 | default: false |
86 | 141 | - type: 'probe' |
87 | 142 | slug: 'juno' |
88 | 143 | name: 'Juno' |
89 | 144 | title: 'Juno (coming soon)' |
145 | + orbit: 'juno_cruise_all' | |
146 | + models: | |
147 | + - slug: 'tao_juno_sw' | |
148 | + started_at: "1990-01-01T01:30:00" | |
149 | + stopped_at: "2017-02-19T00:00:00" | |
90 | 150 | locked: true |
91 | 151 | default: false |
92 | 152 | - type: 'comet' |
93 | 153 | slug: 'tchouri' |
94 | 154 | name: 'Tchouri' |
95 | 155 | title: 'Tchouri (coming soon)' |
156 | + orbit: 'p67_orb_all' | |
96 | 157 | locked: true |
97 | 158 | default: false |
98 | 159 | ... | ... |
web/run.py
... | ... | @@ -7,6 +7,9 @@ from os import listdir, environ |
7 | 7 | from os.path import isfile, join, abspath, dirname |
8 | 8 | |
9 | 9 | import csv |
10 | +import json | |
11 | +import gzip | |
12 | +import urllib | |
10 | 13 | from pprint import pprint |
11 | 14 | from csv import writer as csv_writer |
12 | 15 | from yaml import load as yaml_load |
... | ... | @@ -143,6 +146,60 @@ def datetime_from_list(time_list): |
143 | 146 | ) |
144 | 147 | |
145 | 148 | |
149 | +def get_source_config(slug): | |
150 | + for s in config['sources']: | |
151 | + if s['slug'] == slug: | |
152 | + return s | |
153 | + raise Exception("No source found for slug '%s'." % slug) | |
154 | + | |
155 | + | |
156 | +def retrieve_data(orbiter, what, started_at, stopped_at): | |
157 | + """ | |
158 | + Handles remote querying Myriam's API, downloading, extracting and caching | |
159 | + the netCDF files. | |
160 | + :param orbiter: key of the source in the YAML config | |
161 | + :param what: either 'model' or 'orbit', a key in the config of the source | |
162 | + :param started_at: | |
163 | + :param stopped_at: | |
164 | + :return: a list of local file paths to netCDF (.nc) files | |
165 | + """ | |
166 | + | |
167 | + url = config['amda'].format( | |
168 | + dataSet=what, | |
169 | + startTime=started_at.isoformat(), | |
170 | + stopTime=stopped_at.isoformat() | |
171 | + ) | |
172 | + response = urllib.urlopen(url) | |
173 | + remote_gzip_files = json.loads(response.read()) | |
174 | + if not remote_gzip_files or remote_gzip_files == 'NODATASET': | |
175 | + abort(400, "Failed to fetch data at '%s'." % url) | |
176 | + | |
177 | + # retriever = urllib.URLopener() # would we need to do this every time ? | |
178 | + local_gzip_files = [] | |
179 | + for remote_gzip_file in remote_gzip_files: | |
180 | + # removeme @Myriam | |
181 | + if remote_gzip_file.endswith('/.gz'): | |
182 | + continue | |
183 | + remote_gzip_file = remote_gzip_file.replace('cdpp1', 'cdpp', 1) | |
184 | + ######################### | |
185 | + filename = "%s_%s" % (orbiter, str(remote_gzip_file).split('/')[-1]) | |
186 | + local_gzip_file = get_path("../cache/%s" % filename) | |
187 | + local_gzip_files.append(local_gzip_file) | |
188 | + if not isfile(local_gzip_file): | |
189 | + urllib.urlretrieve(remote_gzip_file, local_gzip_file) | |
190 | + | |
191 | + local_netc_files = [] | |
192 | + for local_gzip_file in local_gzip_files: | |
193 | + local_netc_file = local_gzip_file[0:-3] | |
194 | + local_netc_files.append(local_netc_file) | |
195 | + with gzip.open(local_gzip_file, 'rb') as f: | |
196 | + file_content = f.read() | |
197 | + with open(local_netc_file, 'w+b') as g: | |
198 | + g.write(file_content) | |
199 | + | |
200 | + return local_netc_files | |
201 | + | |
202 | + | |
146 | 203 | # ROUTING ##################################################################### |
147 | 204 | |
148 | 205 | @app.route('/favicon.ico') |
... | ... | @@ -188,40 +245,6 @@ def analyze_cdf(): |
188 | 245 | return si.getvalue() |
189 | 246 | |
190 | 247 | |
191 | -@app.route("/test.csv") | |
192 | -def get_csv(): | |
193 | - si = StringIO.StringIO() | |
194 | - cw = csv_writer(si) | |
195 | - | |
196 | - # Time, StartTime, StopTime, V, B, N, T, Delta_angle, P_dyn, QualityFlag | |
197 | - cdf_handle = Dataset(get_path("../res/dummy.nc"), "r", format="NETCDF4") | |
198 | - # YYYY DOY HH MM SS .ms | |
199 | - times = cdf_handle.variables['Time'] | |
200 | - data_v = cdf_handle.variables['V'] | |
201 | - data_b = cdf_handle.variables['B'] | |
202 | - data_t = cdf_handle.variables['T'] | |
203 | - data_n = cdf_handle.variables['N'] | |
204 | - data_p = cdf_handle.variables['P_dyn'] | |
205 | - data_a = cdf_handle.variables['Delta_angle'] | |
206 | - cw.writerow(( | |
207 | - 'time', | |
208 | - 'vrad', 'vtan', 'vlen', | |
209 | - 'magn', 'temp', 'pdyn', 'dens', 'angl' | |
210 | - )) | |
211 | - for time, datum_v, datum_b, datum_t, datum_p, datum_n, datum_a in \ | |
212 | - zip(times, data_v, data_b, data_t, data_n, data_p, data_a): | |
213 | - vrad = datum_v[0] | |
214 | - vtan = datum_v[1] | |
215 | - cw.writerow(( | |
216 | - datetime_from_list(time).strftime("%Y-%m-%dT%H:%M:%S+00:00"), | |
217 | - vrad, vtan, sqrt(vrad * vrad + vtan * vtan), | |
218 | - datum_b, datum_t, datum_n, datum_p, datum_a | |
219 | - )) | |
220 | - cdf_handle.close() | |
221 | - | |
222 | - return si.getvalue() | |
223 | - | |
224 | - | |
225 | 248 | @app.route("/<orbiter>_data.csv") |
226 | 249 | def get_orbiter_csv(orbiter): |
227 | 250 | # http://cdpp1.cesr.fr/BASE/DDService/getDataUrl.php?dataSet=tao_ros_sw&StartTime=2014-02-23T10:00&StopTime=2016-02-24T23:59 |
... | ... | @@ -242,55 +265,74 @@ def get_orbiter_csv(orbiter): |
242 | 265 | |
243 | 266 | # Grab the list of netCDF files from Myriam's API todo |
244 | 267 | # |
268 | + # http://cdpp.irap.omp.eu/BASE/DDService/getDataUrl.php?dataSet=jupiter_orb_all&StartTime=2014-02-23T10:00:10&StopTime=2017-02-24T23:59:00 | |
269 | + # http://cdpp.irap.omp.eu/BASE/DATA/TAO/JUPITER/SW/sw_2014.nc.gz | |
270 | + | |
271 | + source_config = get_source_config(orbiter) | |
272 | + try: | |
273 | + model_slug = source_config['models'][0]['slug'] | |
274 | + except: | |
275 | + abort(500, "Invalid model configuration for '%s'." % orbiter) | |
276 | + model_files = retrieve_data(orbiter, model_slug, started_at, stopped_at) | |
277 | + orbits_files = retrieve_data(orbiter, source_config['orbit'], started_at, stopped_at) | |
245 | 278 | |
246 | 279 | si = StringIO.StringIO() |
247 | 280 | cw = csv_writer(si) |
248 | - | |
249 | - # Time, StartTime, StopTime, V, B, N, T, Delta_angle, P_dyn, QualityFlag | |
250 | - cdf_handle = Dataset(get_path("../res/dummy.nc"), "r", format="NETCDF4") | |
251 | - | |
252 | - # YYYY DOY HH MM SS .ms | |
253 | - times = cdf_handle.variables['Time'] | |
254 | - data_v = cdf_handle.variables['V'] | |
255 | - data_b = cdf_handle.variables['B'] | |
256 | - data_p = cdf_handle.variables['P_dyn'] | |
257 | - cw.writerow(( | |
281 | + cw.writerow(( # the order matters ! | |
258 | 282 | 'time', |
259 | 283 | 'vrad', 'vtan', 'vlen', |
260 | - 'magn', 'pdyn' | |
284 | + 'magn', 'temp', 'pdyn', 'dens', 'angl', | |
285 | + 'xhci', 'yhci' | |
261 | 286 | )) |
262 | - for time, datum_v, datum_b, datum_p in zip(times, data_v, data_b, data_p): | |
263 | - vrad = datum_v[0] | |
264 | - vtan = datum_v[1] | |
265 | - cw.writerow(( | |
266 | - datetime_from_list(time).strftime("%Y-%m-%dT%H:%M:%S+00:00"), | |
267 | - vrad, vtan, sqrt(vrad * vrad + vtan * vtan), | |
268 | - datum_b, datum_p | |
269 | - )) | |
270 | - cdf_handle.close() | |
271 | 287 | |
272 | - return si.getvalue() | |
273 | - | |
274 | - | |
275 | -@app.route("/astral_coordinates.csv") | |
276 | -def get_astral_coordinates_csv(): | |
277 | - si = StringIO.StringIO() | |
278 | - cw = csv_writer(si) | |
279 | - | |
280 | - # Time, StartTime, StopTime, XYZ_HCI, XYZ_IAU_SUN, XYZ_HEE | |
281 | - cdf_handle = Dataset(get_path("../res/dummy_jupiter_coordinates.nc"), "r", format="NETCDF4") | |
282 | - times = cdf_handle.variables['Time'] | |
283 | - data_xyz_hci = cdf_handle.variables['XYZ_HCI'] | |
284 | - cw.writerow(('time', 'x_hci', 'y_hci')) | |
285 | - for time, datum_xyz_hci in zip(times, data_xyz_hci): | |
286 | - cw.writerow(( | |
287 | - datetime_from_list(time).strftime("%Y-%m-%dT%H:%M:%S+00:00"), | |
288 | - datum_xyz_hci[0], datum_xyz_hci[1] | |
289 | - )) | |
290 | - cdf_handle.close() | |
288 | + precision = "%Y-%m-%dT%H" # model and orbits times are equal-ish | |
289 | + orbits_data = {} # keys are datetime as str, values arrays of XY | |
290 | + for orbits_file in orbits_files: | |
291 | + cdf_handle = Dataset(orbits_file, "r", format="NETCDF4") | |
292 | + times = cdf_handle.variables['Time'] # YYYY DOY HH MM SS .ms | |
293 | + data_hci = cdf_handle.variables['HCI'] | |
294 | + for time, datum_hci in zip(times, data_hci): | |
295 | + dtime = datetime_from_list(time) | |
296 | + if started_at <= dtime <= stopped_at: | |
297 | + dkey = dtime.strftime(precision) | |
298 | + orbits_data[dkey] = datum_hci | |
299 | + all_data = {} # keys are datetime as str, values tuples of data | |
300 | + for model_file in model_files: | |
301 | + # Time, StartTime, StopTime, V, B, N, T, Delta_angle, P_dyn | |
302 | + cdf_handle = Dataset(model_file, "r", format="NETCDF4") | |
303 | + times = cdf_handle.variables['Time'] # YYYY DOY HH MM SS .ms | |
304 | + data_v = cdf_handle.variables['V'] | |
305 | + data_b = cdf_handle.variables['B'] | |
306 | + data_t = cdf_handle.variables['T'] | |
307 | + data_n = cdf_handle.variables['N'] | |
308 | + data_p = cdf_handle.variables['P_dyn'] | |
309 | + data_d = cdf_handle.variables['Delta_angle'] | |
310 | + for time, datum_v, datum_b, datum_t, datum_p, datum_n, datum_d \ | |
311 | + in zip(times, data_v, data_b, data_t, data_n, data_p, data_d): | |
312 | + vrad = datum_v[0] | |
313 | + vtan = datum_v[1] | |
314 | + dtime = datetime_from_list(time) | |
315 | + if started_at <= dtime <= stopped_at: | |
316 | + dkey = dtime.strftime(precision) | |
317 | + x_hci = None | |
318 | + y_hci = None | |
319 | + if dkey in orbits_data: | |
320 | + x_hci = orbits_data[dkey][0] | |
321 | + y_hci = orbits_data[dkey][1] | |
322 | + all_data[dkey] = ( | |
323 | + dtime.strftime("%Y-%m-%dT%H:%M:%S+00:00"), | |
324 | + vrad, vtan, sqrt(vrad * vrad + vtan * vtan), | |
325 | + datum_b, datum_t, datum_n, datum_p, datum_d, | |
326 | + x_hci, y_hci | |
327 | + ) | |
328 | + cdf_handle.close() | |
329 | + | |
330 | + for dkey in sorted(all_data): | |
331 | + cw.writerow(all_data[dkey]) | |
291 | 332 | |
292 | 333 | return si.getvalue() |
293 | 334 | |
335 | + | |
294 | 336 | # MAIN ######################################################################## |
295 | 337 | |
296 | 338 | if __name__ == "__main__": | ... | ... |
web/view/home.html.jinja2
... | ... | @@ -176,16 +176,20 @@ jQuery().ready(function($){ |
176 | 176 | |
177 | 177 | var sw = new SpaceWeather(configuration); |
178 | 178 | |
179 | - d3.csv('{{ url_for('get_csv') }}', function(csv){ | |
179 | + d3.csv('{{ url_for('get_orbiter_csv', orbiter='jupiter', started_at='2016-03-19T00:00:00', stopped_at='2022-01-01T00:00:00') }}', function(csv){ | |
180 | 180 | var timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z'); |
181 | - var data = {'pdyn': [], 'magn': [], 'vlen': [], 'temp': [], 'dens': [], 'angl': []}; | |
181 | + var data = {'pdyn': [], 'magn': [], 'vlen': [], 'temp': [], 'dens': [], 'angl': [], 'hci': []}; | |
182 | 182 | csv.forEach(function (d) { |
183 | - data['pdyn'].push({x: timeFormat(d['time']), y: parseFloat(d['pdyn'])}); | |
184 | - data['magn'].push({x: timeFormat(d['time']), y: parseFloat(d['magn'])}); | |
185 | - data['vlen'].push({x: timeFormat(d['time']), y: parseFloat(d['vlen'])}); | |
186 | - data['temp'].push({x: timeFormat(d['time']), y: parseFloat(d['temp'])}); | |
187 | - data['dens'].push({x: timeFormat(d['time']), y: parseFloat(d['dens'])}); | |
188 | - data['angl'].push({x: timeFormat(d['time']), y: parseFloat(d['angl'])}); | |
183 | + var dtime = timeFormat(d['time']); | |
184 | + data['pdyn'].push({x: dtime, y: parseFloat(d['pdyn'])}); | |
185 | + data['magn'].push({x: dtime, y: parseFloat(d['magn'])}); | |
186 | + data['vlen'].push({x: dtime, y: parseFloat(d['vlen'])}); | |
187 | + data['temp'].push({x: dtime, y: parseFloat(d['temp'])}); | |
188 | + data['dens'].push({x: dtime, y: parseFloat(d['dens'])}); | |
189 | + data['angl'].push({x: dtime, y: parseFloat(d['angl'])}); | |
190 | + if (d['xhci'] && d['yhci']) { | |
191 | + data['hci'].push({t: dtime, x: parseFloat(d['xhci']), y: parseFloat(d['yhci'])}); | |
192 | + } | |
189 | 193 | }); |
190 | 194 | |
191 | 195 | var container = '#time_series'; |
... | ... | @@ -221,16 +225,9 @@ jQuery().ready(function($){ |
221 | 225 | }; |
222 | 226 | }); |
223 | 227 | |
224 | - }); | |
225 | 228 | |
226 | - d3.csv('{{ url_for('get_astral_coordinates_csv') }}', function(csv){ | |
227 | - var timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z'); | |
228 | - var data = []; | |
229 | - csv.forEach(function (d) { | |
230 | - data.push({t: timeFormat(d['time']), x: parseFloat(d['x_hci']), y: parseFloat(d['y_hci'])}); | |
231 | - }); | |
229 | + orbits = new Orbits(configuration.sources, data['hci'], configuration.orbits_container); | |
232 | 230 | |
233 | - orbits = new Orbits(configuration.sources, data, '#orbits'); | |
234 | 231 | }); |
235 | 232 | |
236 | 233 | var toggleTimeSeries = function(slug) { | ... | ... |