@@ -1,713 +1,710 | |||
|
1 | 1 | |
|
2 | 2 | var icon = { |
|
3 | 3 | 'width': 20, |
|
4 | 4 | 'path': 'M18.303,4.742l-1.454-1.455c-0.171-0.171-0.475-0.171-0.646,0l-3.061,3.064H2.019c-0.251,0-0.457,0.205-0.457,0.456v9.578c0,0.251,0.206,0.456,0.457,0.456h13.683c0.252,0,0.457-0.205,0.457-0.456V7.533l2.144-2.146C18.481,5.208,18.483,4.917,18.303,4.742 M15.258,15.929H2.476V7.263h9.754L9.695,9.792c-0.057,0.057-0.101,0.13-0.119,0.212L9.18,11.36h-3.98c-0.251,0-0.457,0.205-0.457,0.456c0,0.253,0.205,0.456,0.457,0.456h4.336c0.023,0,0.899,0.02,1.498-0.127c0.312-0.077,0.55-0.137,0.55-0.137c0.08-0.018,0.155-0.059,0.212-0.118l3.463-3.443V15.929z M11.241,11.156l-1.078,0.267l0.267-1.076l6.097-6.091l0.808,0.808L11.241,11.156z', |
|
5 | 5 | 'ascent': 20, |
|
6 | 6 | 'descent': 2, |
|
7 | 7 | }; |
|
8 | 8 | |
|
9 | 9 | function list2dict(values) { |
|
10 | 10 | |
|
11 | 11 | var o = {}; |
|
12 | 12 | $.each(values, function () { |
|
13 | 13 | o[this.name] = this.value; |
|
14 | 14 | }); |
|
15 | 15 | return o; |
|
16 | 16 | }; |
|
17 | 17 | /* In this class is defined all the function to RTI plot */ |
|
18 | 18 | class PcolorBuffer { |
|
19 | 19 | constructor({ div, data }) { |
|
20 | 20 | this.div = document.getElementById(div); |
|
21 | 21 | this.n = 0; |
|
22 | 22 | this.divs = []; |
|
23 | 23 | this.wait = false; |
|
24 | 24 | this.lastRan = Date.now(); |
|
25 | 25 | this.lastFunc = null; |
|
26 | 26 | this.zbuffer = []; |
|
27 | 27 | this.xbuffer = []; |
|
28 | 28 | this.empty = Array(data.metadata.yrange.length).fill(null); |
|
29 | 29 | this.timespan = 12; |
|
30 | 30 | this.metadata = data.metadata; |
|
31 | 31 | this.setup(data); |
|
32 | 32 | } |
|
33 | 33 | /* This function is used to plot all the data that have the DB and just is used when is loaded or reloaded*/ |
|
34 | 34 | setup(data) { |
|
35 | 35 | this.last = data.time.slice(-1); |
|
36 | 36 | var diffArr = []; |
|
37 | 37 | for(var i=0; i<data.time.length-1; i++){ |
|
38 | 38 | diffArr.push(data.time[i+1]-data.time[i]); |
|
39 | 39 | } |
|
40 | 40 | this.interval = Math.round(Math.min.apply(null, diffArr)*100 / 100); |
|
41 | 41 | if (data.time.length == 1) { |
|
42 | 42 | var values = { 'time': data.time, 'data': data['data'].map(function (x) { return [x] }) }; |
|
43 | 43 | } else { |
|
44 | 44 | var values = this.fill_gaps(data.time, data['data'], this.interval, data['data'].length); |
|
45 | 45 | } |
|
46 | 46 | var t = values.time.map(function (x) { |
|
47 | 47 | var a = new Date(x * 1000); |
|
48 | // This condition is used to change from UTC to LT | |
|
49 | //if (data.metadata.localtime == true){ | |
|
50 | a.setTime( a.getTime() + a.getTimezoneOffset()*60*1000 ); | |
|
51 | //} | |
|
48 | if (data.metadata.localtime == 0){ | |
|
49 | a.setTime( a.getTime() + a.getTimezoneOffset()*60*1000 ); | |
|
50 | } | |
|
52 | 51 |
|
|
53 | 52 | }); |
|
54 | 53 | |
|
55 | 54 | var label; |
|
56 |
|
|
|
57 | label = "[LT]"; | |
|
58 | ||
|
59 | //} | |
|
60 |
|
|
|
61 | // label = "[UTC]"; | |
|
62 | //} | |
|
55 | if (data.metadata.localtime == 1){ | |
|
56 | label = "[LT]"; | |
|
57 | }else{ | |
|
58 | label = "[UTC]"; | |
|
59 | } | |
|
63 | 60 |
|
|
64 | 61 | for (var i = 0; i < data['data'].length; i++) { |
|
65 | 62 | var layout = { |
|
66 | 63 | height: 350, |
|
67 | 64 | xaxis: { |
|
68 | 65 | title: 'Time ' + label, |
|
69 | 66 | showgrid: false, |
|
70 | 67 | linewidth: 2, |
|
71 | 68 | size: 12, |
|
72 | 69 | mirror: true, |
|
73 | 70 | }, |
|
74 | 71 | yaxis: { |
|
75 | 72 | title: data.metadata.ylabel || 'km', |
|
76 | 73 | showgrid: false, |
|
77 | 74 | linewidth: 2, |
|
78 | 75 | size: 12, |
|
79 | 76 | mirror: true, |
|
80 | 77 | }, |
|
81 | 78 | titlefont: { |
|
82 | 79 | size: 16, |
|
83 | 80 | }, |
|
84 | 81 | margin: { |
|
85 | 82 | t: 30, |
|
86 | 83 | } |
|
87 | 84 | }; |
|
88 | 85 | var iDiv = document.createElement('div'); |
|
89 | 86 | iDiv.id = 'plot-' + i; |
|
90 | 87 | this.zbuffer.push([]); |
|
91 | 88 | this.n = this.n + 1; |
|
92 | 89 | this.div.appendChild(iDiv); |
|
93 | 90 | this.divs.push(iDiv.id); |
|
94 | 91 | var trace = { |
|
95 | 92 | z: values.data[i], |
|
96 | 93 | x: t, |
|
97 | 94 | y: data.metadata.yrange, |
|
98 | 95 | colorscale: this.metadata.colormap || 'Jet', |
|
99 | 96 | transpose: true, |
|
100 | 97 | type: 'heatmap' |
|
101 | 98 | }; |
|
102 | 99 | |
|
103 | 100 | if (this.metadata.zmin) { trace.zmin = this.metadata.zmin } |
|
104 | 101 | if (this.metadata.zmax) { trace.zmax = this.metadata.zmax } |
|
105 | 102 | |
|
106 | 103 | var tm = new Date(this.last * 1000); |
|
107 | tm.setTime( tm.getTime() + tm.getTimezoneOffset()*60*1000 ); | |
|
108 | ||
|
104 | if (data.metadata.localtime == 0){ | |
|
105 | tm.setTime( tm.getTime() + tm.getTimezoneOffset()*60*1000 ); | |
|
106 | } | |
|
109 | 107 | if ('titles' in this.metadata){ |
|
110 | 108 | layout.title = this.metadata.titles[i] + ' - ' + tm.toLocaleString(); |
|
111 | 109 | }else{ |
|
112 | 110 | layout.title = 'Ch ' + i + ' - ' + tm.toLocaleString(); |
|
113 | 111 | } |
|
114 | 112 | |
|
115 | 113 | var conf = { |
|
116 | 114 | modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'], |
|
117 | 115 | modeBarButtonsToAdd: [{ |
|
118 | 116 | name: 'Edit plot', |
|
119 | 117 | icon: icon, |
|
120 | 118 | click: function (gd) { |
|
121 | 119 | var div = gd.id; |
|
122 | 120 | $('input[id=id_plotdiv]').val(div); |
|
123 | 121 | $('#setup').modal('show'); |
|
124 | 122 | } |
|
125 | 123 | }], |
|
126 | 124 | displaylogo: false, |
|
127 | 125 | showTips: true |
|
128 | 126 | }; |
|
129 | 127 | Plotly.newPlot('plot-' + i, [trace], layout, conf); |
|
130 | 128 | } |
|
131 | 129 | $('#id_ymin').val(Math.min(...this.metadata.yrange)); |
|
132 | 130 | $('#id_ymax').val(Math.max(...this.metadata.yrange)); |
|
133 | 131 | if (this.metadata.zmin) { |
|
134 | 132 | $('#id_zmin').val(this.metadata.zmin); |
|
135 | 133 | } else { |
|
136 | 134 | $('#id_zmin').val(Math.min(...values.data[0][0])); |
|
137 | 135 | } |
|
138 | 136 | if (this.metadata.zmax) { |
|
139 | 137 | $('#id_zmax').val(this.metadata.zmax); |
|
140 | 138 | } else { |
|
141 | 139 | $('#id_zmax').val(Math.max(...values.data[0][0])); |
|
142 | 140 | } |
|
143 | 141 | } |
|
144 | 142 | |
|
145 | 143 | getSize() { |
|
146 | 144 | var div = document.getElementById(this.divs[0]); |
|
147 | 145 | var t = this.xbuffer.slice(-1)[0]; |
|
148 | 146 | var n = 0; |
|
149 | 147 | var timespan = this.timespan * 1000 * 60 * 60; |
|
150 | 148 | |
|
151 | 149 | while ((t - div.data[0].x[n]) > timespan) { |
|
152 | 150 | n += 1; |
|
153 | 151 | } |
|
154 | 152 | if(n>720){ |
|
155 | 153 | return 720; |
|
156 | 154 | }else{ |
|
157 | 155 | return n; |
|
158 | 156 | } |
|
159 | 157 | } |
|
160 | 158 | |
|
161 | 159 | fill_gaps(xBuffer, zBuffer, interval, N) { |
|
162 | 160 | |
|
163 | 161 | var x = [xBuffer[0]]; |
|
164 | 162 | var z = []; |
|
165 | 163 | var last; |
|
166 | 164 | |
|
167 | 165 | for (var j = 0; j < N; j++) { |
|
168 | 166 | z.push([zBuffer[j][0]]); |
|
169 | 167 | } |
|
170 | 168 | |
|
171 | 169 | for (var i = 1; i < xBuffer.length; i++) { |
|
172 | 170 | var cnt = 0; |
|
173 | 171 | last = x[x.length-1]; |
|
174 | 172 | while (Math.abs(parseFloat(xBuffer[i]) - last ) > 1.5 * parseFloat(interval)) { |
|
175 | 173 | cnt += 1; |
|
176 | 174 | last = last + interval; |
|
177 | 175 | x.push(last); |
|
178 | 176 | for (var j = 0; j < N; j++) { |
|
179 | 177 | z[j].push(this.empty); |
|
180 | 178 | } |
|
181 | 179 | // Avoid infinite loop |
|
182 | 180 | if (cnt == 100) { break; } |
|
183 | 181 | } |
|
184 | 182 | x.push(xBuffer[i]); |
|
185 | 183 | for (var j = 0; j < N; j++) { |
|
186 | 184 | z[j].push(zBuffer[j][i]); |
|
187 | 185 | } |
|
188 | 186 | } |
|
189 | 187 | return { 'time': x, 'data': z }; |
|
190 | 188 | } |
|
191 | 189 | |
|
192 | 190 | plot() { |
|
193 | 191 | // add new data to plots and empty buffers |
|
194 | 192 | var N = this.getSize(); |
|
195 | 193 | // // // // console.log('Plotting...'); |
|
196 | 194 | for (var i = 0; i < this.n; i++) { |
|
197 | 195 | var div = document.getElementById(this.divs[i]); |
|
198 | 196 | if (N > 0) { |
|
199 | 197 | div.data[0].z = div.data[0].z.slice(N, ) |
|
200 | 198 | div.data[0].x = div.data[0].x.slice(N, ) |
|
201 | 199 | } |
|
202 | 200 | Plotly.extendTraces(div, { |
|
203 | 201 | z: [this.zbuffer[i]], |
|
204 | 202 | x: [this.xbuffer] |
|
205 | 203 | }, [0]); |
|
206 | 204 | this.zbuffer[i] = []; |
|
207 | 205 | } |
|
208 | 206 | this.xbuffer = []; |
|
209 | 207 | } |
|
210 | 208 | //This function just add the last data and is used if previously was used setup() |
|
211 | 209 | update(obj) { |
|
212 | 210 | |
|
213 | 211 | // fill data gaps |
|
214 | 212 | var cnt = 0; |
|
215 | 213 | |
|
216 | 214 | while (Math.abs(parseFloat(obj.time[0]) - this.last) > 1.5 * parseFloat(this.interval)) { |
|
217 | 215 | cnt += 1; |
|
218 | 216 | this.last += this.interval; |
|
219 | 217 | var newt = new Date((this.last) * 1000); |
|
220 | // This condition is used to change from UTC to LT | |
|
221 | // if (obj.metadata.localtime == true){ | |
|
222 | newt.setTime( newt.getTime() + newt.getTimezoneOffset()*60*1000 ); | |
|
223 | //} | |
|
218 | if (obj.metadata.localtime == 0){ | |
|
219 | newt.setTime( newt.getTime() + newt.getTimezoneOffset()*60*1000 ); | |
|
220 | } | |
|
224 | 221 |
|
|
225 | 222 | for (var i = 0; i < obj['data'].length; i++) { |
|
226 | 223 | this.zbuffer[i].push(this.empty); |
|
227 | 224 | } |
|
228 | 225 | // Avoid infinite loop |
|
229 | 226 | if (cnt == 100) { break; } |
|
230 | 227 | } |
|
231 | 228 | |
|
232 | 229 | // update buffers |
|
233 | 230 | this.last = parseFloat(obj.time[0]); |
|
234 | 231 | var t = new Date(obj.time[0] * 1000); |
|
235 | // This condition is used to change from UTC to LT | |
|
236 | //if (obj.metadata.localtime == true){ | |
|
237 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
238 | //} | |
|
232 | if (obj.metadata.localtime == 0){ | |
|
233 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
234 | } | |
|
239 | 235 |
|
|
240 | 236 | for (var i = 0; i < obj['data'].length; i++) { |
|
241 | 237 | this.zbuffer[i].push(obj['data'][i]); |
|
242 | 238 | var div = document.getElementById(this.divs[i]); |
|
243 | 239 | |
|
244 | 240 | if ('titles' in obj.metadata){ |
|
245 | 241 | var title = obj.metadata.titles[i] + ' - ' + t.toLocaleString(); |
|
246 | 242 | }else{ |
|
247 | 243 | var title = 'Ch ' + i + ' - ' + t.toLocaleString(); |
|
248 | 244 | } |
|
249 | 245 | |
|
250 | 246 | Plotly.relayout(div, { |
|
251 | 247 | title: title |
|
252 | 248 | }); |
|
253 | 249 | } |
|
254 | 250 | |
|
255 | 251 | if (!this.wait) { |
|
256 | 252 | this.plot(); |
|
257 | 253 | this.wait = true; |
|
258 | 254 | } else { |
|
259 | 255 | clearTimeout(this.lastFunc) |
|
260 | 256 | this.lastFunc = setTimeout(function (scope) { |
|
261 | 257 | if ((Date.now() - scope.lastRan) >= 30000) { |
|
262 | 258 | scope.plot() |
|
263 | 259 | scope.lastRan = Date.now() |
|
264 | 260 | } |
|
265 | 261 | }, 30000 - (Date.now() - this.lastRan), this) |
|
266 | 262 | } |
|
267 | 263 | } |
|
268 | 264 | // With this function You can change parameters in your plot |
|
269 | 265 | restyle(values) { |
|
270 | 266 | |
|
271 | 267 | var values = list2dict(values); |
|
272 | 268 | var div = document.getElementById(values.plotdiv); |
|
273 | 269 | |
|
274 | 270 | Plotly.relayout(div, { |
|
275 | 271 | yaxis: { |
|
276 | 272 | range: [values.ymin, values.ymax], |
|
277 | 273 | title: this.metadata.ylabel || 'km', |
|
278 | 274 | linewidth: 2, |
|
279 | 275 | size: 12, |
|
280 | 276 | mirror: true, |
|
281 | 277 | } |
|
282 | 278 | |
|
283 | 279 | }); |
|
284 | 280 | |
|
285 | 281 | Plotly.restyle(div, { |
|
286 | 282 | zmin: values.zmin, |
|
287 | 283 | zmax: values.zmax, |
|
288 | 284 | colorscale: values.colormap |
|
289 | 285 | }); |
|
290 | 286 | } |
|
291 | 287 | } |
|
292 | 288 | /* In this class is defined all the function to SPC plot */ |
|
293 | 289 | class Pcolor { |
|
294 | 290 | constructor({ div, data }) { |
|
295 | 291 | this.div = document.getElementById(div); |
|
296 | 292 | this.n = 0; |
|
297 | 293 | this.divs = []; |
|
298 | 294 | this.metadata = data.metadata; |
|
299 | 295 | this.setup(data); |
|
300 | 296 | } |
|
301 | 297 | /* This function is used to plot all the data that have the DB and just is used when is loaded or reloaded*/ |
|
302 | 298 | setup(data) { |
|
303 | 299 | for (var i = 0; i < data['data'].length; i++) { |
|
304 | 300 | var layout = { |
|
305 | 301 | margin: { |
|
306 | 302 | t:30, |
|
307 | 303 | }, |
|
308 | 304 | height: 320, |
|
309 | 305 | xaxis: { |
|
310 | 306 | title: data.metadata.xlabel || 'Velocity', |
|
311 | 307 | showgrid: false, |
|
312 | 308 | zeroline: false, |
|
313 | 309 | linewidth: 2, |
|
314 | 310 | mirror: true, |
|
315 | 311 | size: 12, |
|
316 | 312 | }, |
|
317 | 313 | yaxis: { |
|
318 | 314 | title: data.metadata.ylabel || 'km', |
|
319 | 315 | showgrid: false, |
|
320 | 316 | linewidth: 2, |
|
321 | 317 | mirror: 'all', |
|
322 | 318 | size: 12, |
|
323 | 319 | }, |
|
324 | 320 | titlefont: { |
|
325 | 321 | size: 14 |
|
326 | 322 | }, |
|
327 | 323 | }; |
|
328 | 324 | var iDiv = document.createElement('div'); |
|
329 | 325 | iDiv.id = 'plot-' + i; |
|
330 | 326 | iDiv.className += iDiv.className ? ' col-md-6' : 'col-md-6'; |
|
331 | 327 | this.n = this.n + 1; |
|
332 | 328 | this.div.appendChild(iDiv); |
|
333 | 329 | this.divs.push(iDiv.id); |
|
334 | 330 | var trace1 = { |
|
335 | 331 | z: data['data'][i], |
|
336 | 332 | y: data.metadata.yrange, |
|
337 | 333 | x: data.metadata.xrange, |
|
338 | 334 | colorscale: this.metadata.colormap || 'Jet', |
|
339 | 335 | transpose: true, |
|
340 | 336 | type: 'heatmap' |
|
341 | 337 | }; |
|
342 | 338 | |
|
343 | 339 | if (this.metadata.zmin) { |
|
344 | 340 | trace1.zmin = this.metadata.zmin |
|
345 | 341 | } |
|
346 | 342 | if (this.metadata.zmax) { |
|
347 | 343 | trace1.zmax = this.metadata.zmax; |
|
348 | 344 | } |
|
349 | 345 | |
|
350 | 346 | var t = new Date(data.time * 1000); |
|
351 |
|
|
|
352 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
353 |
|
|
|
347 | if (data.metadata.localtime == 0){ | |
|
348 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
349 | } | |
|
354 | 350 |
|
|
355 | 351 | layout.title = data.metadata.titles[i] + ' ' + t.toLocaleString(); |
|
356 | 352 | }else{ |
|
357 | 353 | layout.title = 'Ch ' + i + ': ' + t.toLocaleString(); |
|
358 | 354 | } |
|
359 | 355 | var conf = { |
|
360 | 356 | modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'], |
|
361 | 357 | modeBarButtonsToAdd: [{ |
|
362 | 358 | name: 'Edit plot', |
|
363 | 359 | icon: icon, |
|
364 | 360 | click: function (gd) { |
|
365 | 361 | var div = gd.id; |
|
366 | 362 | $('input[id=id_plotdiv]').val(div); |
|
367 | 363 | $('#setup').modal('show'); |
|
368 | 364 | } |
|
369 | 365 | }], |
|
370 | 366 | displaylogo: false, |
|
371 | 367 | showTips: true |
|
372 | 368 | }; |
|
373 | 369 | |
|
374 | 370 | var traces = [trace1] |
|
375 | 371 | |
|
376 | 372 | Plotly.newPlot('plot-' + i, traces, layout, conf); |
|
377 | 373 | } |
|
378 | 374 | $('#id_ymin').val(Math.min(...this.metadata.yrange)); |
|
379 | 375 | $('#id_ymax').val(Math.max(...this.metadata.yrange)); |
|
380 | 376 | $('#id_xmin').val(Math.min(...this.metadata.xrange)); |
|
381 | 377 | $('#id_xmax').val(Math.max(...this.metadata.xrange)); |
|
382 | 378 | |
|
383 | 379 | if (this.metadata.zmin) { |
|
384 | 380 | $('#id_zmin').val(this.metadata.zmin); |
|
385 | 381 | } else { |
|
386 | 382 | $('#id_zmin').val(Math.min(...data.data[0][0])); |
|
387 | 383 | } |
|
388 | 384 | if (this.metadata.zmax) { |
|
389 | 385 | $('#id_zmax').val(this.metadata.zmax); |
|
390 | 386 | } else { |
|
391 | 387 | $('#id_zmax').val(Math.max(...data.data[0][0])); |
|
392 | 388 | } |
|
393 | 389 | } |
|
394 | 390 | |
|
395 | 391 | plot(obj) { |
|
396 | 392 | this.data = obj; |
|
397 | 393 | // add new data to plots and empty buffers |
|
398 | 394 | // // // console.log('Plotting...'); |
|
399 | 395 | var t = new Date(obj.time[0] * 1000); |
|
400 | // This condition is used to change from UTC to LT | |
|
401 | //if (obj.metadata.localtime == true){ | |
|
402 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
403 | //} | |
|
396 | if (obj.metadata.localtime == 0){ | |
|
397 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
398 | } | |
|
404 | 399 |
|
|
405 | 400 | var div = document.getElementById(this.divs[i]); |
|
406 | 401 | |
|
407 | 402 | if ('titles' in obj.metadata){ |
|
408 | 403 | var title = obj.metadata.titles[i] + ' ' + t.toLocaleString(); |
|
409 | 404 | }else{ |
|
410 | 405 | var title = 'Ch ' + i + ': ' + t.toLocaleString(); |
|
411 | 406 | } |
|
412 | 407 | |
|
413 | 408 | Plotly.relayout(div, { |
|
414 | 409 | title: title, |
|
415 | 410 | }); |
|
416 | 411 | |
|
417 | 412 | Plotly.restyle(div, { |
|
418 | 413 | z: [obj['data'][i]], |
|
419 | 414 | x: [obj.xrange] |
|
420 | 415 | }, [0]); |
|
421 | 416 | } |
|
422 | 417 | } |
|
423 | 418 | |
|
424 | 419 | update(data) { |
|
425 | 420 | this.plot(data); |
|
426 | 421 | } |
|
427 | 422 | |
|
428 | 423 | restyle(values) { |
|
429 | 424 | |
|
430 | 425 | var values = list2dict(values); |
|
431 | 426 | var div = document.getElementById(values.plotdiv); |
|
432 | 427 | |
|
433 | 428 | Plotly.relayout(div, { |
|
434 | 429 | yaxis: { |
|
435 | 430 | title: this.metadata.ylabel || 'km', |
|
436 | 431 | linewidth: 2, |
|
437 | 432 | range: [values.ymin, values.ymax] |
|
438 | 433 | }, |
|
439 | 434 | xaxis: { |
|
440 | 435 | title: this.metadata.xlabel || 'Velocity', |
|
441 | 436 | linewidth: 2, |
|
442 | 437 | mirror: true, |
|
443 | 438 | range: [values.xmin, values.xmax] |
|
444 | 439 | } |
|
445 | 440 | }); |
|
446 | 441 | |
|
447 | 442 | Plotly.restyle(div, { |
|
448 | 443 | zmin: values.zmin, |
|
449 | 444 | zmax: values.zmax, |
|
450 | 445 | colorscale: values.colormap |
|
451 | 446 | }); |
|
452 | 447 | } |
|
453 | 448 | } |
|
454 | 449 | |
|
455 | 450 | class ScatterBuffer { |
|
456 | 451 | constructor({ div, data }) { |
|
457 | 452 | this.div = document.getElementById(div); |
|
458 | 453 | this.n = 0; |
|
459 | 454 | this.wait = false; |
|
460 | 455 | this.lastRan = Date.now(); |
|
461 | 456 | this.lastFunc = null; |
|
462 | 457 | this.ybuffer = []; |
|
463 | 458 | this.xbuffer = []; |
|
464 | 459 | this.timespan = 12; |
|
465 | 460 | this.metadata = data.metadata; |
|
466 | 461 | this.setup(data); |
|
467 | 462 | } |
|
468 | 463 | /* This function is used to plot all the data that have the DB and just is used when is loaded or reloaded*/ |
|
469 | 464 | setup(data) { |
|
470 | 465 | |
|
471 | 466 | var traces = []; |
|
472 | 467 | this.last = data.time.slice(-1); |
|
473 | 468 | var diffArr = []; |
|
474 | 469 | for(var i=0; i<data.time.length-1; i++){ |
|
475 | 470 | diffArr.push(data.time[i+1]-data.time[i]); |
|
476 | 471 | } |
|
477 | 472 | this.interval = Math.round(Math.min.apply(null, diffArr)*100 / 100); |
|
478 | 473 | |
|
479 | 474 | if (data.time.length == 1) { |
|
480 | 475 | var values = { 'time': data.time, 'data': data['data'] }; |
|
481 | 476 | } else { |
|
482 | 477 | var values = this.fill_gaps(data.time, data['data'], this.interval, data['data'].length); |
|
483 | 478 | } |
|
484 | 479 | |
|
485 | 480 | var t = values.time.map(function (x) { |
|
486 | 481 | var a = new Date(x * 1000); |
|
487 | 482 | // This condition is used to change from UTC to LT |
|
488 |
|
|
|
489 | a.setTime( a.getTime() + a.getTimezoneOffset()*60*1000 ); | |
|
490 |
|
|
|
483 | if (data.metadata.localtime == 0){ | |
|
484 | a.setTime( a.getTime() + a.getTimezoneOffset()*60*1000 ); | |
|
485 | } | |
|
491 | 486 |
|
|
492 | 487 | }); |
|
493 | 488 | |
|
494 | 489 | for (var i = 0; i < data['data'].length; i++) { |
|
495 | 490 | |
|
496 | 491 | this.n = this.n + 1; |
|
497 | 492 | this.ybuffer.push([]); |
|
498 | 493 | var trace = { |
|
499 | 494 | x: t, |
|
500 | 495 | y: values.data[i], |
|
501 | 496 | mode: 'lines', |
|
502 | 497 | type: 'scatter', |
|
503 | 498 | name: 'Channel ' + i, |
|
504 | 499 | connectgaps: false, |
|
505 | 500 | }; |
|
506 | 501 | |
|
507 | 502 | traces.push(trace); |
|
508 | 503 | } |
|
509 | 504 | |
|
510 | 505 | var label; |
|
511 | label = "[LT]"; | |
|
506 | if (data.metadata.localtime == 1){ | |
|
507 | label = "[LT]"; | |
|
508 | }else{ | |
|
509 | label = "[UTC]"; | |
|
510 | } | |
|
512 | 511 | |
|
513 | 512 | var layout = { |
|
514 | 513 | height: 300, |
|
515 | 514 | title: t.slice(-1).toLocaleString(), |
|
516 | 515 | font: { |
|
517 | 516 | size: 12, |
|
518 | 517 | }, |
|
519 | 518 | xaxis: { |
|
520 | 519 | title: 'Time ' + label, |
|
521 | 520 | size: 12, |
|
522 | 521 | linewidth: 2, |
|
523 | 522 | mirror: true, |
|
524 | 523 | }, |
|
525 | 524 | yaxis: { |
|
526 | 525 | title: data.metadata.ylabel || 'dB', |
|
527 | 526 | linewidth: 2, |
|
528 | 527 | mirror: true, |
|
529 | 528 | }, |
|
530 | 529 | titlefont: { |
|
531 | 530 | size: 16, |
|
532 | 531 | }, |
|
533 | 532 | margin: { |
|
534 | 533 | t: 30, |
|
535 | 534 | } |
|
536 | 535 | }; |
|
537 | 536 | |
|
538 | 537 | if (data.metadata.ymin) { layout.yaxis.range = [data.metadata.ymin, data.metadata.ymax] } |
|
539 | 538 | |
|
540 | 539 | var conf = { |
|
541 | 540 | modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'], |
|
542 | 541 | modeBarButtonsToAdd: [{ |
|
543 | 542 | name: 'Edit plot', |
|
544 | 543 | icon: icon, |
|
545 | 544 | click: function (gd) { |
|
546 | 545 | $('#setup').modal('show'); |
|
547 | 546 | } |
|
548 | 547 | }], |
|
549 | 548 | displaylogo: false, |
|
550 | 549 | showTips: true |
|
551 | 550 | }; |
|
552 | 551 | Plotly.newPlot('plot', traces, layout, conf); |
|
553 | 552 | |
|
554 | 553 | if (this.metadata.ymin) { |
|
555 | 554 | $('#id_ymin').val(this.metadata.ymin); |
|
556 | 555 | } else { |
|
557 | 556 | $('#id_ymin').val(layout.yaxis.range[0]); |
|
558 | 557 | } |
|
559 | 558 | if (this.metadata.ymax) { |
|
560 | 559 | $('#id_ymax').val(this.metadata.ymax); |
|
561 | 560 | } else { |
|
562 | 561 | $('#id_ymax').val(layout.yaxis.range[1]); |
|
563 | 562 | } |
|
564 | 563 | } |
|
565 | 564 | |
|
566 | 565 | getSize() { |
|
567 | 566 | var t = this.xbuffer.slice(-1)[0]; |
|
568 | 567 | var n = 0; |
|
569 | 568 | var timespan = this.timespan * 1000 * 60 * 60; |
|
570 | 569 | |
|
571 | 570 | while ((t - this.div.data[0].x[n]) > timespan) { |
|
572 | 571 | n += 1; |
|
573 | 572 | } |
|
574 | 573 | if(n>720){ |
|
575 | 574 | return 720; |
|
576 | 575 | }else{ |
|
577 | 576 | return n; |
|
578 | 577 | } |
|
579 | 578 | } |
|
580 | 579 | |
|
581 | 580 | fill_gaps(xBuffer, yBuffer, interval, N) { |
|
582 | 581 | |
|
583 | 582 | var x = [xBuffer[0]]; |
|
584 | 583 | var y = []; |
|
585 | 584 | |
|
586 | 585 | for (var j = 0; j < N; j++) { |
|
587 | 586 | y.push([yBuffer[j][0]]); |
|
588 | 587 | } |
|
589 | 588 | |
|
590 | 589 | var last; |
|
591 | 590 | |
|
592 | 591 | for (var i = 1; i < xBuffer.length; i++) { |
|
593 | 592 | var cnt = 0; |
|
594 | 593 | last = x.slice(-1)[0]; |
|
595 | 594 | while (Math.abs(parseFloat(xBuffer[i]) - last) > 1.5 * parseFloat(interval)) { |
|
596 | 595 | cnt += 1; |
|
597 | 596 | last = last + interval; |
|
598 | 597 | x.push(last); |
|
599 | 598 | for (var j = 0; j < N; j++) { |
|
600 | 599 | y[j].push(null); |
|
601 | 600 | } |
|
602 | 601 | // Avoid infinite loop |
|
603 | 602 | if (cnt == 50) { break; } |
|
604 | 603 | } |
|
605 | 604 | x.push(xBuffer[i]); |
|
606 | 605 | |
|
607 | 606 | for (var j = 0; j < N; j++) { |
|
608 | 607 | y[j].push(yBuffer[j][i]); |
|
609 | 608 | } |
|
610 | 609 | } |
|
611 | 610 | return { 'time': x, 'data': y }; |
|
612 | 611 | } |
|
613 | 612 | |
|
614 | 613 | plot() { |
|
615 | 614 | // add new data to plots and empty buffers |
|
616 | 615 | var xvalues = []; |
|
617 | 616 | var yvalues = []; |
|
618 | 617 | var traces = []; |
|
619 | 618 | var N = this.getSize(); |
|
620 | 619 | // // console.log('Plotting...'); |
|
621 | 620 | for (var i = 0; i < this.n; i++) { |
|
622 | 621 | if (N > 0) { |
|
623 | 622 | this.div.data[i].y = this.div.data[i].y.slice(N, ) |
|
624 | 623 | this.div.data[i].x = this.div.data[i].x.slice(N, ) |
|
625 | 624 | } |
|
626 | 625 | yvalues.push(this.ybuffer[i]); |
|
627 | 626 | xvalues.push(this.xbuffer); |
|
628 | 627 | traces.push(i); |
|
629 | 628 | this.ybuffer[i] = []; |
|
630 | 629 | } |
|
631 | 630 | Plotly.extendTraces(this.div, { |
|
632 | 631 | y: yvalues, |
|
633 | 632 | x: xvalues |
|
634 | 633 | }, traces); |
|
635 | 634 | this.xbuffer = []; |
|
636 | 635 | } |
|
637 | 636 | //This function just add the last data and is used if previously was used setup() |
|
638 | 637 | update(obj) { |
|
639 | 638 | // fill data gaps |
|
640 | 639 | var cnt = 0; |
|
641 | 640 | while (Math.abs(parseFloat(obj.time[0]) - this.last ) > 1.5 * parseFloat(this.interval)) { |
|
642 | 641 | cnt += 1; |
|
643 | 642 | this.last += this.interval; |
|
644 | 643 | var newt = new Date((this.last) * 1000); |
|
645 | // This condition is used to change from UTC to LT | |
|
646 | //if (obj.metadata.localtime == true){ | |
|
647 | newt.setTime( newt.getTime() + newt.getTimezoneOffset()*60*1000 ); | |
|
648 | //} | |
|
644 | if (obj.metadata.localtime == 0){ | |
|
645 | newt.setTime( newt.getTime() + newt.getTimezoneOffset()*60*1000 ); | |
|
646 | } | |
|
649 | 647 |
|
|
650 | 648 | for (var i = 0; i < this.n; i++) { |
|
651 | 649 | this.ybuffer[i].push(null); |
|
652 | 650 | } |
|
653 | 651 | // Avoid infinite loop |
|
654 | 652 | if (cnt == 100) { break; } |
|
655 | 653 | } |
|
656 | 654 | |
|
657 | 655 | // update buffers |
|
658 | 656 | this.last = parseFloat(obj.time[0]); |
|
659 | 657 | var t = new Date(obj.time[0] * 1000); |
|
660 | // This condition is used to change from UTC to LT | |
|
661 | //if (obj.metadata.localtime == true){ | |
|
662 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
663 | //} | |
|
658 | if (obj.metadata.localtime == 0){ | |
|
659 | t.setTime( t.getTime() + t.getTimezoneOffset()*60*1000 ); | |
|
660 | } | |
|
664 | 661 |
|
|
665 | 662 | for (var i = 0; i < this.n; i++) { |
|
666 | 663 | this.ybuffer[i].push(obj['data'][i][0]); |
|
667 | 664 | } |
|
668 | 665 | |
|
669 | 666 | Plotly.relayout(this.div, { |
|
670 | 667 | title: t.toLocaleString(), |
|
671 | 668 | }); |
|
672 | 669 | |
|
673 | 670 | if (!this.wait) { |
|
674 | 671 | this.plot(); |
|
675 | 672 | this.wait = true; |
|
676 | 673 | } else { |
|
677 | 674 | clearTimeout(this.lastFunc) |
|
678 | 675 | this.lastFunc = setTimeout(function (scope) { |
|
679 | 676 | if ((Date.now() - scope.lastRan) >= 30000) { |
|
680 | 677 | scope.plot() |
|
681 | 678 | scope.lastRan = Date.now() |
|
682 | 679 | } |
|
683 | 680 | }, 30000 - (Date.now() - this.lastRan), this) |
|
684 | 681 | } |
|
685 | 682 | } |
|
686 | 683 | |
|
687 | 684 | restyle(values) { |
|
688 | 685 | |
|
689 | 686 | var values = list2dict(values); |
|
690 | 687 | Plotly.relayout(this.div, { |
|
691 | 688 | yaxis: { |
|
692 | 689 | range: [values.ymin, values.ymax], |
|
693 | 690 | title: this.metadata.ylabel || 'dB' |
|
694 | 691 | } |
|
695 | 692 | }); |
|
696 | 693 | } |
|
697 | 694 | } |
|
698 | 695 | |
|
699 | 696 | class StaticPlot { |
|
700 | 697 | constructor({ div, data }) { |
|
701 | 698 | this.div = document.getElementById(div); |
|
702 | 699 | this.setup(data); |
|
703 | 700 | } |
|
704 | 701 | |
|
705 | 702 | setup(data) { |
|
706 | 703 | document.querySelectorAll('[id="image"]')[0].src = 'data:image/png;base64, '+data["data"]; |
|
707 | 704 | } |
|
708 | 705 | |
|
709 | 706 | update(obj) { |
|
710 | 707 | document.querySelectorAll('[id="image"]')[0].src = 'data:image/png;base64, '+obj["data"]; |
|
711 | 708 | // console.log('Plotting...'); |
|
712 | 709 | } |
|
713 | 710 | } No newline at end of file |
@@ -1,143 +1,170 | |||
|
1 | 1 | {% extends 'base.html' %} |
|
2 | 2 | {% load static%} |
|
3 | 3 | {% block content %} |
|
4 | 4 | <p>Useful tools and data from other partners/observatories.</p> |
|
5 | 5 | <div class="card-columns p-2"> |
|
6 | ||
|
7 | <div class="card text-justify"> | |
|
8 | <div class="card-body"> | |
|
9 | <h5 class="card-title">DOY Calendar</h5> | |
|
10 | <p class="card-text">The day of year (DOY) is the sequential day number starting with day 1 on January 1st</p> | |
|
11 | <input type="date" class="form-control tools-date" id="doy-date" placeholder="yyyy-mm-dd" | |
|
12 | aria-describedby="validationTooltipSkynoiseDate" value="{% now 'Y-m-d' %}" required> | |
|
13 | <div class="invalid-tooltip"> | |
|
14 | Please enter a valid date. | |
|
15 | </div> | |
|
16 | <p id="pdoy" class="card-text text-center" style="padding-top: 0.5em; font-weight:500; font-size:1.5em; color:var(--secondary);">DOY: {{doy}}</p> | |
|
17 | </div> | |
|
18 | </div> | |
|
19 | ||
|
20 | ||
|
6 | 21 | <div class="card text-justify"> |
|
7 | 22 | <img src="{% static 'images/skynoise.png' %}" class="card-img-top" alt="..."> |
|
8 | 23 | <div class="card-body"> |
|
9 | 24 | <h5 class="card-title">Sky noise</h5> |
|
10 | 25 | <p class="card-text">Sky brightness at 50 MHz, useful for antenna calibrations and measure radar's sensitivity. |
|
11 | 26 | </p> |
|
12 | 27 | <input type="date" class="form-control tools-date" id="skynoise-date" placeholder="dd/mm/yy" |
|
13 | 28 | aria-describedby="validationTooltipSkynoiseDate" value="{% now 'Y-m-d' %}" required> |
|
14 | 29 | <div class="invalid-tooltip"> |
|
15 | 30 | Please enter a valid date. |
|
16 | 31 | </div> |
|
17 | 32 | <a class="btn btn-primary m-1" data-toggle="modal" href="#toolModal" data-title="Sky Noise" |
|
18 | 33 | data-image="{% url 'url_skynoise' %}">Go</a> |
|
19 | 34 | </div> |
|
20 | 35 | </div> |
|
21 | 36 | |
|
22 | 37 | <div class="card text-justify"> |
|
23 | 38 | <div class="card-body"> |
|
24 | 39 | <h5 class="card-title">Over JRO</h5> |
|
25 | 40 | <p class="card-text">Main antenna radiation pattern for several experiments. |
|
26 | 41 | |
|
27 | 42 | <input type="date" class="form-control form-control-sm tools-date" id="overjro-date" placeholder="dd/mm/yy" |
|
28 | 43 | aria-describedby="validationTooltipOverJRODate" value="{% now 'Y-m-d' %}" required> |
|
29 | 44 | <div class="invalid-tooltip"> |
|
30 | 45 | Please enter a valid date. |
|
31 | 46 | </div> |
|
32 | 47 | <select name="experiment" class="form-control form-control-sm"> |
|
33 | 48 | <option value="-1">Experiment:</option> |
|
34 | 49 | <option value="-1">------------------</option> |
|
35 | 50 | <option value="20">Vertical Drifts</option> |
|
36 | 51 | <option value="[21,22]">East West 1996</option> |
|
37 | 52 | <option value="[25,26]">East West 2003</option> |
|
38 | 53 | <option value="23">Differential Phase 2000</option> |
|
39 | 54 | <option value="24">Differential Phase 2004 High Alt</option> |
|
40 | 55 | <option value="27">Differential Phase 2005 - 2006</option> |
|
41 | 56 | <option value="[28,29]">DEWD 2005</option> |
|
42 | 57 | <option value="2710">DVD 2006 - 2008</option> |
|
43 | 58 | <option value="-1">------------------</option> |
|
44 | 59 | <option value="10">Oblique ISR On-Axis</option> |
|
45 | 60 | <option value="11">Oblique ISR 4.5</option> |
|
46 | 61 | <option value="12">Oblique ISR 6.0S</option> |
|
47 | 62 | <option value="13">Oblique ISR 3.0N</option> |
|
48 | 63 | <option value="-1">------------------</option> |
|
49 | 64 | <option value="[30,31]">JULIA CP2</option> |
|
50 | 65 | <option value="32">JULIA CP3</option> |
|
51 | 66 | <option value="35">JULIA V (2005-2006)</option> |
|
52 | 67 | <option value="[33,34]">JULIA EW 2003</option> |
|
53 | 68 | <option value="[35,36]">JULIA EW (2006-2007)</option> |
|
54 | 69 | <option value="-1">------------------</option> |
|
55 | 70 | <option value="0">Modulo Rx</option> |
|
56 | 71 | <option value="1">1/16 Rx</option> |
|
57 | 72 | <option value="2">1/4 Rx</option> |
|
58 | 73 | <option value="3">All Rx</option> |
|
59 | 74 | <option value="-1">------------------</option> |
|
60 | 75 | <option value="40">EW Imaging 1996</option> |
|
61 | 76 | <option value="41">EW Imaging 2003</option> |
|
62 | 77 | <option value="43">EW Imaging 2006-2008</option> |
|
63 | 78 | <option value="-1">------------------</option> |
|
64 | 79 | <option value="50">MST North (Fritts)</option> |
|
65 | 80 | <option value="51">MST West (Fritts)</option> |
|
66 | 81 | <option value="52">MST South (Fritts)</option> |
|
67 | 82 | <option value="53">MST East (Fritts)</option> |
|
68 | 83 | <option value="-1">------------------</option> |
|
69 | 84 | <option value="54">Vertical (Yellow Cables)</option> |
|
70 | 85 | </select> |
|
71 | 86 | <br> |
|
72 | 87 | <p class="card-text">Choose object: |
|
73 | 88 | <div class="form-check card-text"> |
|
74 | 89 | <input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1"> |
|
75 | 90 | <label class="form-check-label" for="inlineCheckbox1">B Field</label><br> |
|
76 | 91 | <input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1"> |
|
77 | 92 | <label class="form-check-label" for="inlineCheckbox1">Sun</label><br> |
|
78 | 93 | <input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1"> |
|
79 | 94 | <label class="form-check-label" for="inlineCheckbox1">Moon</label><br> |
|
80 | 95 | <input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1"> |
|
81 | 96 | <label class="form-check-label" for="inlineCheckbox1">Hydra</label><br> |
|
82 | 97 | <input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1"> |
|
83 | 98 | <label class="form-check-label" for="inlineCheckbox1">Galaxy Center</label> |
|
84 | 99 | </div> |
|
85 | 100 | </p> |
|
86 | 101 | </div> |
|
87 | 102 | <a class="btn btn-primary m-1" data-toggle="modal" href="#toolModal" data-title="Over JRO" |
|
88 | 103 | data-image="{% url 'url_overjro' %}">Go</a> |
|
89 | 104 | </div> |
|
90 | 105 | |
|
91 | 106 | <div class="card text-justify"> |
|
92 | 107 | <img src="{% static 'images/kp.png' %}" class="card-img-top" alt="..."> |
|
93 | 108 | <div class="card-body"> |
|
94 | 109 | <h5 class="card-title">Kp Index</h5> |
|
95 | 110 | <p class="card-text">The K-index, are used to characterize the magnitude of geomagnetic storms. Kp is an excellent |
|
96 | 111 | indicator of disturbances in the Earth's magnetic field (<a |
|
97 | 112 | href="https://www.swpc.noaa.gov/products/planetary-k-index" target="_blank">NOAA/SWPC</a>).</p> |
|
98 | 113 | <a class="btn btn-primary" data-toggle="modal" href="#toolModal" data-title="Kp Index" |
|
99 | 114 | data-image="https://services.swpc.noaa.gov/images/planetary-k-index.gif">Go</a> |
|
100 | 115 | </div> |
|
101 | 116 | </div> |
|
102 | 117 | </div> |
|
103 | 118 | |
|
104 | </div> | |
|
105 | ||
|
106 | 119 | <!-- Modal --> |
|
107 | 120 | <div class="modal fade" id="toolModal" tabindex="-1" role="dialog" aria-labelledby="toolModalTitle" aria-hidden="true"> |
|
108 | 121 | <div class="modal-dialog modal-lg" role="document"> |
|
109 | 122 | <div class="modal-content"> |
|
110 | 123 | <div class="modal-header"> |
|
111 | 124 | <h5 class="modal-title" id="toolModalTitle">Modal title</h5> |
|
112 | 125 | <button type="button" class="close" data-dismiss="modal" aria-label="Close"> |
|
113 | 126 | <span aria-hidden="true">×</span> |
|
114 | 127 | </button> |
|
115 | 128 | </div> |
|
116 | 129 | <div class="modal-body text-center"> |
|
117 | 130 | <img class="img-fluid" src=""> |
|
118 | 131 | </div> |
|
119 | 132 | </div> |
|
120 | 133 | </div> |
|
121 | 134 | </div> |
|
122 | 135 | |
|
123 | 136 | {% endblock content %} |
|
124 | 137 | |
|
125 | 138 | {% block script %} |
|
126 | 139 | <script> |
|
140 | ||
|
127 | 141 | $('#toolModal').on('show.bs.modal', function (e) { |
|
128 | 142 | |
|
129 | 143 | //get data attribute of the clicked element |
|
130 | 144 | var title = $(e.relatedTarget).data('title'); |
|
131 | 145 | var image = $(e.relatedTarget).data('image'); |
|
132 | 146 | |
|
133 | 147 | if (image.indexOf('skynoise') > 0) { |
|
134 | 148 | var dt = $('#skynoise-date').val(); |
|
135 | 149 | image += '?date=' + dt; |
|
136 | 150 | } |
|
137 | 151 | |
|
138 | 152 | //populate values |
|
139 | 153 | $(e.currentTarget).find('h5').text(title); |
|
140 | 154 | $(e.currentTarget).find('img').attr('src', image); |
|
141 | 155 | }); |
|
156 | ||
|
157 | $('#doy-date').change(function() { | |
|
158 | var old = new Date($(this).val()); | |
|
159 | var now = new Date(old.getTime()+old.getTimezoneOffset()*60*1000); | |
|
160 | var start = new Date(now.getFullYear(), 0, 0); | |
|
161 | var diff = (now - start) // + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000); | |
|
162 | var oneDay = 1000 * 60 * 60 * 24; | |
|
163 | var doy = Math.floor(diff / oneDay); | |
|
164 | $('#pdoy').text("DOY: " + doy); | |
|
165 | console.log(now); | |
|
166 | console.log(start); | |
|
167 | }); | |
|
168 | ||
|
142 | 169 | </script> |
|
143 | 170 | {% endblock script %} No newline at end of file |
@@ -1,242 +1,238 | |||
|
1 | 1 | #!/usr/bin/python |
|
2 | 2 | # -*- coding: UTF-8 -*- |
|
3 | 3 | |
|
4 | 4 | |
|
5 | 5 | import os |
|
6 | 6 | import time |
|
7 | 7 | from datetime import datetime |
|
8 | 8 | |
|
9 | 9 | from django import forms |
|
10 | 10 | from django.contrib import messages |
|
11 | 11 | from django.utils.safestring import mark_safe |
|
12 | 12 | from django.shortcuts import render |
|
13 | 13 | from django.http import HttpResponse |
|
14 | 14 | |
|
15 | 15 | import mongoengine |
|
16 | 16 | |
|
17 | 17 | from plotter.models import Experiment, ExpDetail, PlotMeta, PlotData |
|
18 | 18 | |
|
19 | 19 | from utils.plots import skynoise_plot |
|
20 | 20 | |
|
21 | 21 | host = os.environ.get('HOST_MONGO', 'localhost') |
|
22 | 22 | mongoengine.connect('dbplots', host=host, port=27017) |
|
23 | 23 | |
|
24 | 24 | |
|
25 | 25 | # Forms |
|
26 | 26 | class SearchForm(forms.Form): |
|
27 | 27 | |
|
28 | 28 | experiment = forms.ChoiceField() |
|
29 | 29 | plot = forms.ChoiceField() |
|
30 | 30 | |
|
31 | 31 | def __init__(self, *args, **kwargs): |
|
32 | 32 | |
|
33 | 33 | exp_choices = kwargs.pop('exp_choices', []) |
|
34 | 34 | plt_choices = kwargs.pop('plt_choices', []) |
|
35 | 35 | super(SearchForm, self).__init__(*args, **kwargs) |
|
36 | 36 | self.fields['experiment'].choices = [(0, 'Select Experiment')] + exp_choices |
|
37 | 37 | self.fields['plot'].choices = [(0, 'Select Plot')] + plt_choices |
|
38 | 38 | # we use this class to change the parameter in Scatter plot using the function plotly.restyle in jroplot.js |
|
39 | 39 | class ScatterSetupForm(forms.Form): |
|
40 | 40 | |
|
41 | 41 | plotdiv = forms.CharField(widget=forms.HiddenInput()) |
|
42 | 42 | ymax = forms.CharField(initial=30) |
|
43 | 43 | ymin = forms.CharField(initial=10) |
|
44 | 44 | |
|
45 | 45 | # we use this class to change the parameter in RTI plot using the function plotly.restyle in jroplot.js |
|
46 | 46 | class RTISetupForm(forms.Form): |
|
47 | 47 | |
|
48 | 48 | plotdiv = forms.CharField(widget=forms.HiddenInput()) |
|
49 | 49 | colormap = forms.ChoiceField(choices=[('Jet', 'Jet'), ('Viridis', 'Viridis'), ('RdBu', 'RdBu')]) |
|
50 | 50 | zmax = forms.CharField(initial=30) |
|
51 | 51 | zmin = forms.CharField(initial=10) |
|
52 | 52 | ymax = forms.CharField(initial=180) |
|
53 | 53 | ymin = forms.CharField(initial=80) |
|
54 | 54 | |
|
55 | 55 | # we use this class to change the parameter in SPC plot using the function plotly.restyle in jroplot.js |
|
56 | 56 | class SPCSetupForm(forms.Form): |
|
57 | 57 | |
|
58 | 58 | plotdiv = forms.CharField(widget=forms.HiddenInput()) |
|
59 | 59 | colormap = forms.ChoiceField(choices=[('Jet', 'Jet'), ('Viridis', 'Viridis'), ('RdBu', 'RdBu')]) |
|
60 | 60 | #como es un perfil xmin y xmax deben ser iguales a zmin y zmax |
|
61 | 61 | xmax = forms.CharField(initial=30) |
|
62 | 62 | xmin = forms.CharField(initial=10) |
|
63 | 63 | #x2max = forms.CharField(initial=30) |
|
64 | 64 | #x2min = forms.CharField(initial=10) |
|
65 | 65 | ymax = forms.CharField(initial=180) |
|
66 | 66 | ymin = forms.CharField(initial=80) |
|
67 | 67 | zmax = forms.CharField(initial=30) |
|
68 | 68 | zmin = forms.CharField(initial=10) |
|
69 | 69 | |
|
70 | 70 | # Create your views here. |
|
71 | 71 | def main(request, tag=None): |
|
72 | 72 | |
|
73 | 73 | kwargs = {} |
|
74 | date = request.GET.get('date', datetime.now().strftime('%d-%m-%Y')) | |
|
74 | date = request.GET.get('date', datetime.utcnow().strftime('%d-%m-%Y')) | |
|
75 | 75 | exps = ExpDetail.objects(date=datetime.strptime(date, '%d-%m-%Y')) |
|
76 | 76 | |
|
77 | 77 | tmp = {} |
|
78 | 78 | for exp in exps: |
|
79 | 79 | label = exp.tag.lower().strip() if exp.tag else 'other' |
|
80 | 80 | if label in tmp: |
|
81 | 81 | tmp[label] += 1 |
|
82 | 82 | else: |
|
83 | 83 | tmp[label] = 1 |
|
84 | 84 | tags = [] |
|
85 | 85 | |
|
86 | 86 | for key, value in tmp.items(): |
|
87 | 87 | if tag == key: |
|
88 | 88 | tags.append({'name': key, 'n': tmp[key], 'active': 'active'}) |
|
89 | 89 | else: |
|
90 | 90 | tags.append({'name': key, 'n': tmp[key]}) |
|
91 | 91 | |
|
92 | 92 | kwargs['tags'] = tags |
|
93 | 93 | |
|
94 | 94 | if tag: |
|
95 | 95 | experiments = [] |
|
96 | 96 | for exp in exps: |
|
97 | 97 | label = exp.tag.lower().strip() if exp.tag else 'other' |
|
98 | 98 | if label != tag: |
|
99 | 99 | continue |
|
100 | 100 | dum = {} |
|
101 | 101 | dum['code'] = exp.experiment.code |
|
102 | 102 | dum['plots'] = [] |
|
103 | 103 | dum['name'] = exp.experiment.name |
|
104 | dt = datetime.now() | |
|
105 | ||
|
106 | t = time.mktime(dt.timetuple()) | |
|
107 | t -= 5*60*60 | |
|
104 | ||
|
105 | t = time.time() | |
|
108 | 106 | |
|
109 | 107 | if (t-exp['last_time']) > 6*exp['interval']: |
|
110 | 108 | status = 'Offline' |
|
111 | 109 | clase = 'alertas-offline' |
|
112 | 110 | style = 'danger' |
|
113 | lastDataDate = exp['last_time'] | |
|
114 | 111 | elif (t-exp['last_time']) > 3*exp['interval']: |
|
115 | 112 | status = 'Delayed' |
|
116 | 113 | clase = 'alertas-delayed' |
|
117 | 114 | style = 'warning' |
|
118 | lastDataDate = exp['last_time'] | |
|
119 | 115 | else: |
|
120 | 116 | status = 'Online' |
|
121 | 117 | clase = 'alertas-online' |
|
122 | 118 | style = 'success' |
|
123 | lastDataDate = exp['last_time'] | |
|
124 | 119 | |
|
125 | 120 | dum['status'] = status |
|
126 | 121 | dum['class'] = clase |
|
127 | 122 | dum['style']= style |
|
128 |
dum['date']= datetime. |
|
|
123 | dum['date']= datetime.fromtimestamp(exp['last_time']) | |
|
129 | 124 | for plot in exp.plots(): |
|
130 | 125 | dum['plots'].append({'plot': plot.plot, 'name': plot.plot.replace('_', ' ').title(), 'id':plot.id}) |
|
131 | 126 | experiments.append(dum) |
|
132 | 127 | |
|
133 | 128 | kwargs['experiments'] = experiments |
|
134 | 129 | kwargs['tag'] = tag |
|
135 | 130 | |
|
136 | 131 | kwargs['date'] = date |
|
137 | 132 | kwargs['title'] = 'Home' |
|
138 | 133 | kwargs['sidebar'] = True |
|
139 | 134 | |
|
140 | 135 | return render(request, 'home.html', kwargs) |
|
141 | 136 | |
|
142 | 137 | def about(request): |
|
143 | 138 | ''' |
|
144 | 139 | ''' |
|
145 | 140 | kwargs = { |
|
146 | 141 | 'title': 'About' |
|
147 | 142 | } |
|
148 | 143 | return render(request, 'about.html', kwargs) |
|
149 | 144 | |
|
150 | 145 | |
|
151 | 146 | def tools(request): |
|
152 | 147 | ''' |
|
153 | 148 | ''' |
|
154 | 149 | kwargs = { |
|
155 | 'title': 'Tools' | |
|
150 | 'title': 'Tools', | |
|
151 | 'doy': (datetime.today().date()-datetime.today().date().replace(month=1, day=1)).days + 1 | |
|
156 | 152 | } |
|
157 | 153 | return render(request, 'tools.html', kwargs) |
|
158 | 154 | |
|
159 | 155 | def reports(request): |
|
160 | 156 | ''' |
|
161 | 157 | ''' |
|
162 | 158 | kwargs = { |
|
163 | 159 | 'title': 'Reports', |
|
164 | 160 | } |
|
165 | 161 | return render(request, 'reports.html', kwargs) |
|
166 | 162 | |
|
167 | 163 | def plot(request, code=None, plot=None): |
|
168 | 164 | ''' |
|
169 | 165 | ''' |
|
170 | 166 | |
|
171 | 167 | realtime = False |
|
172 | 168 | date = request.GET.get('date', None) |
|
173 | 169 | if date is None: |
|
174 | date = datetime.now().strftime('%d-%m-%Y') | |
|
170 | date = datetime.utcnow().strftime('%d-%m-%Y') | |
|
175 | 171 | realtime = True |
|
176 | 172 | exp = Experiment.objects.get(code=int(code)) |
|
177 | 173 | detail = ExpDetail.objects.get(experiment=exp, date=datetime.strptime(date, '%d-%m-%Y')) |
|
178 | 174 | meta = PlotMeta.objects.get(exp_detail=detail, plot=plot) |
|
179 | 175 | tag = detail.tag.lower().strip() if detail.tag else 'other' |
|
180 | 176 | |
|
181 | 177 | kwargs = { |
|
182 | 178 | 'code': code, |
|
183 | 179 | 'plot': plot, |
|
184 | 180 | 'meta':meta, |
|
185 | 181 | 'date': date, |
|
186 | 182 | 'id': meta.pk, |
|
187 | 183 | 'realtime': realtime, |
|
188 | 184 | 'title': 'Home', |
|
189 | 185 | 'name' : exp.name, |
|
190 | 186 | 'sidebar': True, |
|
191 | 187 | 'tag' : tag, |
|
192 | 188 | 'plots': [] |
|
193 | 189 | } |
|
194 | 190 | |
|
195 | 191 | for plt in detail.plots(): |
|
196 | 192 | kwargs['plots'].append({'plot': plt.plot, 'name': plt.plot.replace('_', ' ').title()}) |
|
197 | 193 | |
|
198 | 194 | # Logic to show my views |
|
199 | 195 | if meta.metadata['type'] == 'pcolorbuffer': |
|
200 | 196 | kwargs['setup_form'] = RTISetupForm() |
|
201 | 197 | kwargs['fn_plot'] = 'PcolorBuffer' |
|
202 | 198 | return render(request, 'plot.html', kwargs) |
|
203 | 199 | elif meta.metadata['type'] == 'pcolor': |
|
204 | 200 | kwargs['setup_form'] = SPCSetupForm() |
|
205 | 201 | kwargs['fn_plot'] = 'Pcolor' |
|
206 | 202 | return render(request, 'plot.html', kwargs) |
|
207 | 203 | elif meta.metadata['type'] == 'scatterbuffer': |
|
208 | 204 | kwargs['setup_form'] = ScatterSetupForm() |
|
209 | 205 | kwargs['fn_plot'] = 'ScatterBuffer' |
|
210 | 206 | return render(request, 'plot.html', kwargs) |
|
211 | 207 | elif meta.metadata['type'] == 'image': |
|
212 | 208 | kwargs['image'] = True |
|
213 | 209 | kwargs['fn_plot'] = 'StaticPlot' |
|
214 | 210 | return render(request, 'plot.html', kwargs) |
|
215 | 211 | else: |
|
216 | 212 | return render(request, 'home.html', {}) |
|
217 | 213 | |
|
218 | 214 | def plot_skynoise(request): |
|
219 | 215 | |
|
220 | 216 | date = request.GET.get('date', None) |
|
221 | 217 | if date is None: |
|
222 | 218 | date = datetime.now() |
|
223 | 219 | else: |
|
224 | 220 | date = datetime.strptime(date, '%Y-%m-%d') |
|
225 | 221 | |
|
226 | 222 | data = skynoise_plot(date.year, date.month, date.day) |
|
227 | 223 | response = HttpResponse(data.getvalue(), content_type='image/png') |
|
228 | 224 | |
|
229 | 225 | return response |
|
230 | 226 | |
|
231 | 227 | def plot_overjro(request): |
|
232 | 228 | |
|
233 | 229 | date = request.GET.get('date', None) |
|
234 | 230 | if date is None: |
|
235 | 231 | date = datetime.now() |
|
236 | 232 | else: |
|
237 | 233 | date = datetime.strptime(date, '%Y-%m-%d') |
|
238 | 234 | |
|
239 | 235 | data = skynoise_plot(date.year, date.month, date.day) |
|
240 | 236 | response = HttpResponse(data.getvalue(), content_type='image/png') |
|
241 | 237 | |
|
242 | 238 | return response No newline at end of file |
@@ -1,175 +1,169 | |||
|
1 | 1 | #!/usr/bin/python |
|
2 | 2 | # -*- coding: UTF-8 -*- |
|
3 | 3 | |
|
4 | 4 | import os |
|
5 | 5 | import sys |
|
6 | 6 | import json |
|
7 | 7 | import simplejson |
|
8 | 8 | from datetime import datetime |
|
9 | 9 | import time |
|
10 | 10 | import zmq |
|
11 | 11 | import mongoengine |
|
12 | 12 | import django |
|
13 | 13 | from threading import Thread |
|
14 | 14 | |
|
15 | 15 | sys.path.append(os.environ.get('APP_DIR', '../')) |
|
16 | 16 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "realtime.settings") |
|
17 | 17 | django.setup() |
|
18 | 18 | |
|
19 | 19 | from plotter.models import Experiment, ExpDetail, PlotMeta, PlotData |
|
20 | 20 | |
|
21 | 21 | host_mongo = os.environ.get('HOST_MONGO', 'localhost') |
|
22 | 22 | mongoengine.connect('dbplots', host=host_mongo, port=27017) |
|
23 | 23 | |
|
24 | 24 | import channels.layers |
|
25 | 25 | from asgiref.sync import async_to_sync |
|
26 | 26 | |
|
27 | 27 | channel = channels.layers.get_channel_layer() |
|
28 | 28 | |
|
29 | 29 | def loaddata(): |
|
30 | 30 | print('Loading Experiments...') |
|
31 | 31 | if os.environ.get('APP_DIR', None) is not None: |
|
32 | 32 | file_exp = os.path.join(os.environ.get('APP_DIR'), 'scripts', 'experiments.json') |
|
33 | 33 | else: |
|
34 | 34 | file_exp = './experiments.json' |
|
35 | 35 | for tup in json.load(open(file_exp)): |
|
36 | 36 | print(tup) |
|
37 | 37 | exp = Experiment.objects(code=tup['code']).modify( |
|
38 | 38 | upsert=True, # To add a new row |
|
39 | 39 | new=True, |
|
40 | 40 | set__code=tup['code'], |
|
41 | 41 | set__name=tup['name'], |
|
42 | 42 | ) |
|
43 | 43 | exp.save() |
|
44 | 44 | |
|
45 | 45 | #============== funcion para modificar datos en la tabla ============== |
|
46 | 46 | def update(buffer): |
|
47 | 47 | dt = datetime.utcfromtimestamp(buffer['time']) |
|
48 | 48 | interval = buffer['metadata'].pop('interval') |
|
49 | 49 | tag = buffer['metadata'].pop('tag') if 'tag' in buffer['metadata'] else '' |
|
50 | 50 | exp = Experiment.objects.get(code=buffer['code']) |
|
51 | 51 | |
|
52 | 52 | detail = ExpDetail.objects(experiment=exp, date=dt.date()).modify( |
|
53 | 53 | upsert=True, |
|
54 | 54 | new=True, |
|
55 | 55 | set__experiment=exp, |
|
56 | 56 | set__date=dt.date(), |
|
57 | 57 | set__last_time = buffer['time'], |
|
58 | 58 | set__interval = interval, |
|
59 | 59 | set__tag = tag, |
|
60 | 60 | ) |
|
61 | 61 | |
|
62 | 62 | label = buffer['plot'].replace(' ', '_').lower() |
|
63 | 63 | plot = PlotMeta.objects(exp_detail=detail, plot=label).modify( |
|
64 | 64 | upsert=True, |
|
65 | 65 | new=True, |
|
66 | 66 | set__metadata = buffer['metadata'] |
|
67 | 67 | ) |
|
68 | 68 | #plot.save() |
|
69 | 69 | |
|
70 | 70 | data = PlotData.objects(plot=plot, time=buffer['time']).modify( |
|
71 | 71 | upsert=True, # To add a new row |
|
72 | 72 | new=True, |
|
73 | 73 | set__time = buffer['time'], |
|
74 | 74 | set__data = buffer['data'] |
|
75 | 75 | ) |
|
76 | 76 | |
|
77 | 77 | #data.save() |
|
78 | 78 | |
|
79 | 79 | if datetime.now().date() == dt.date(): |
|
80 | 80 | return True |
|
81 | 81 | |
|
82 | 82 | return False |
|
83 | 83 | |
|
84 | 84 | # Function that is checking the state of my clients every 30s |
|
85 | 85 | def check_times(): |
|
86 | 86 | |
|
87 | 87 | while True: |
|
88 | 88 | dt = datetime.now() |
|
89 | 89 | exps = ExpDetail.objects(date=dt.date()) |
|
90 | 90 | |
|
91 | 91 | for detail in exps: |
|
92 | 92 | code = detail.experiment.code |
|
93 | 93 | plot = detail.plots()[0] |
|
94 |
|
|
|
95 | t = time.mktime(dt.timetuple()) | |
|
96 | t -= 5*60*60 | |
|
97 | data_time = detail['last_time'] + 5*60*60 | |
|
94 | t = time.time() | |
|
98 | 95 | |
|
99 | 96 | message = { |
|
100 | 97 | 'code': code, |
|
101 |
'time': d |
|
|
98 | 'time': detail['last_time'] | |
|
102 | 99 | } |
|
103 | 100 | |
|
104 | 101 | if (t-detail['last_time']) > 6*detail['interval']: |
|
105 | 102 | value = 'danger' |
|
106 | 103 | elif (t-detail['last_time']) > 3*detail['interval']: |
|
107 | 104 | value = 'warning' |
|
108 | 105 | else: |
|
109 | 106 | value = 'success' |
|
110 | 107 | |
|
111 | 108 | print(('{} {} {} {} {}'.format(code, t, detail['last_time'], (t-detail['last_time']), value))) |
|
112 | 109 | |
|
113 | 110 | message['value'] = value |
|
114 | 111 | |
|
115 | 112 | async_to_sync(channel.group_send)( |
|
116 | 113 | 'main', |
|
117 | 114 | { |
|
118 | 115 | 'type': 'zmq_message', |
|
119 | 116 | 'message': json.dumps(message) |
|
120 | 117 | } |
|
121 | 118 | ) |
|
122 | 119 | |
|
123 | 120 | time.sleep(60) |
|
124 | 121 | |
|
125 | 122 | def main(): |
|
126 | 123 | print('Starting ZMQ server...') |
|
127 | 124 | context = zmq.Context() |
|
128 | 125 | receiver = context.socket(zmq.REP) |
|
129 | 126 | receiver.bind("tcp://0.0.0.0:4444") |
|
130 | 127 | t = Thread(target=check_times) |
|
131 | 128 | t.start() |
|
132 | 129 | |
|
133 | 130 | while True: |
|
134 | 131 | |
|
135 | 132 | buffer = receiver.recv_json() |
|
136 | 133 | if not isinstance(buffer, dict): |
|
137 | 134 | print('Invalid data received: {}').format(str(buffer)) |
|
138 | 135 | continue |
|
139 | ||
|
140 | if buffer['metadata']['localtime'] == True: # Ask which type of time is coming: LT o UTC | |
|
141 | buffer['time'] -= 5*60*60 | |
|
142 | 136 | |
|
143 | 137 | if not update(buffer): |
|
144 | 138 | print('Updating {} for code {}'.format( |
|
145 | 139 | buffer['plot'], |
|
146 | 140 | buffer['code'] |
|
147 | 141 | )) |
|
148 | 142 | else: |
|
149 | 143 | buffer['time'] = [buffer['time']] |
|
150 | 144 | group = '{}_{}'.format( |
|
151 | 145 | buffer['code'], |
|
152 | 146 | buffer['plot'].replace(' ', '_').lower() |
|
153 | 147 | ) |
|
154 | 148 | async_to_sync(channel.group_send)( |
|
155 | 149 | group, |
|
156 | 150 | { |
|
157 | 151 | 'type': 'zmq_message', |
|
158 | 152 | 'message': simplejson.dumps(buffer, ignore_nan=True) |
|
159 | 153 | } |
|
160 | 154 | ) |
|
161 | 155 | |
|
162 | 156 | print('Sending to group {}_{} - {} bytes'.format( |
|
163 | 157 | buffer['code'], |
|
164 | 158 | buffer['plot'].replace(' ', '_').lower(), |
|
165 | 159 | len(str(buffer))) |
|
166 | 160 | ) |
|
167 | 161 | |
|
168 | 162 | receiver.send_string('ok') |
|
169 | 163 | |
|
170 | 164 | receiver.close() |
|
171 | 165 | context.term() |
|
172 | 166 | |
|
173 | 167 | if __name__=='__main__': |
|
174 | 168 | loaddata() |
|
175 | 169 | main() |
General Comments 0
You need to be logged in to leave comments.
Login now